hadoop 의 구성을 보면 Namenode 와 Datanode 가 있다. Namenode 를 일종의 마스터로 보면 Datanode 는 슬레이브로 볼 수 있으며 Namenode 와 Datanode 사이에는 주기적으로 통신을 한다.

Datanode 가 파일 시스템 정보나 기타 헬스체크를 주기적으로 Namenode 로 보내는데 이 때의 통신방법은 RPC 이다.
Namenode 가 기동 될 때 RPC Server 가 같이 기동되며 Namenode 는 DatanodeProtocol 인터페이스를 구현하였기 때문에 Datanode 가 이 메소드를 호출하는 RPC 통신을 하게 된다.

RPC 통신 구현 방법은 간단한데 Datanode 가 적합한 메소드(DatanodeProtocol 메소드 중의 하나)를 호출하면 ipc.Client 클래스를 이용하여 메소드 명,  파라미터 갯수, 루프를 돌면서 (파라미터 타입, 파라미터 값) 을 보내면 -RPC.Invocation클래스를 이용하면 관련 정보를 순서대로 보낸 - Namenode 는 ipc.Server 를 통해서 메소드명, 파라미터 갯수, 루프를 돌면서 (파라미터 타입, 파라미터 값) 을 받아 - RPC.Invation클래스를 이용하면 순서대로 받을 수 있다 - Namenode 의 적합한 메소드(DatanodeProtocol 메소드 중의 하나)를 invoke 한다.
invoke 후에는 리턴 값을 받아서 ipc.Server 를 통해 리턴 클래스명, 리턴 클래스의 값을 Datanode 에 보낸다.
Datanode 는 ipc.Client 를 통해서 리턴 클래스명, 리턴 클래스의 값을 받아 처음에 호출한  메소드의 결과값으로 리턴된다.

RPC의 핵심은 Proxy 클래스와 Reflection API 를 사용한다는 것. 
Posted by Kubernetes Korea co-leader seungkyua@gmail.com
TAG Hadoop, RPC
Datanode 는 Proxy.newProxyInstance(...) 로 DatanodeProtocol 인터페이스를 구현한 Proxy 객체를 구해서
다른 데이터노드와 통신한다.

이렇게 되면 DatanodeProtocol 의 메소드를 호출 할 때 마다 Proxy 객체 생성시에 저장된 InvokerHandler.invoke 메소가 호출된다. 결국 중요한 것은  InvokerHandler.invoke  메소드이다. (실제 작업하게 되는 메소드)

ObjectWritable value = (ObjectWritable) CLIENT.call(new Invocation(method, args), address);
return value.get();

Invocation 클래스는 대충 호출할 메소드와 파라미터를 저장한 것이라고 하면 CLIENT 클래스가 중요하다.

CLIENT 가 call 을 호출하면 내부적으로는 다음과 같은 진행을 한다.
1. 쓰레드 타입의 Connection 객체 생성하여 재사용을 위해 Hashtable 에 저장하고 쓰레드를 시작한다.
    Connection 객체에는 InetSocketAddr을 이용하여 DataInputStream 과 DataOutputStream 을 가지고 있다.
2. Call(param) 으로 call 객체를 파라미터만 저장하여 생성
3. call 객체를 Hashtable 에 저장하고 out.writeInt(call.id); call.param.write(out) 와 같이 파라미터를 보낸다.
4. Connection 쓰레드의 run 이 끝나서 결과를 받으르 때까지 타임아웃만큼 기다린다.  call.wait(timeout);
5. Connection 쓰레드의 run 메소드에서 id = in.readInt(); 후 Hashtable 의 call 객체를 remove 한다.
6. in.readBoolean(); 으로 에러여부를 읽고 value.readFields(in); value 값을 읽어 들인다.
7. call 객체에 value 를 세팅하고 call 객체의 notify() 를 호출한 후 Connection 쓰레드를 Hashtable에서
    제거한 후 쓰레드를 종료한다.
Posted by Kubernetes Korea co-leader seungkyua@gmail.com
NameNode 는 RPC 클래스를 통해서 Server 클래스를 동작시킨다.

Server 클래스는 아래의 3개의 내부 쓰레드를 가진다.

1. Listener 스레드 : ServerSocket 을 가지면 클라이언트가 접속할 때 마다 Connection 쓰레드를 생성
2. Connection 스레드 : 클라이언트의 요청 데이터를 받아서 Call 객체를 생성하여 callQueue 에 넣는다.
                                 데이터는 DataInput 으로 부터 읽어 들임
3. Handler 쓰레드 : callQueue로 부터 Call 객체를 받아와 RPC 호출을 실행 시킨다.
                           실제적으로 일을 하는 쓰레드로 conf 객체의 "dfs.namenode.handler.count"  값으로
                           갯수를 결정하며 default 는 10 이다.


클라이언트가 요청할 때 DataInput 으로 읽어들이는 값의 순서
1. id : in.readInt() 로 id 값을 읽음
2. methodName : UTF8.readString(in) 로 메소드 명을 읽음
3. 파라미터 갯수 : in.readInt() 로 파라미터 갯수를 int 값으로 읽음
4. 파라미터 객체를 읽음 : ObjectWritable.readObject(in, objectWritable, this.conf) 로 파라미터 객체 생성에 
                                    필요한 값을 읽음

4번 파라미터 객체를 읽는 순서
1. className : UTF8.readString(id) 로 클래스명을 읽음
                      클래스명은 in.readUnsignedShort() 로 클래스명이 차지하는 byte 수를 읽고 
                      그 클래스명 크기만큼 읽어들임
2. 자기 클래스에 맞는 크기 만큼 읽어 들임.
    - null 이면 NuuInstance 의 readFields(in) 를 읽음
    - 원시타임(char, int, long 등등)은 in.readChar() 등으로 읽음
    - Array 는 in.readInt() 로 배열크기를 읽은 다음 recursive call로 readObject() 를 다시 읽음
    - String 은 UTF8.readString(in) 으로 읽음
    - 그외 객체는 1번으로 읽어들인 클래스명으로 인스턴스를 만들어 객체가 Writable 인터페이스를 구현한
       writable.readFields(in) 로 읽어들임
Posted by Kubernetes Korea co-leader seungkyua@gmail.com
DatanodeInfo 속성은?
1. UTF8 name : <host>:<port> 로 구성된 값
2. long capacityBytes : 총 수용 가능한 bytes 수
3. long remainingBytes : 수용 가능한 남은 bytes 수
4. long lastUpdate : capacityBytes, remainingBytes 값을 세팅한 시간 System.currentTimeMillis()
5. TreeSet blocks : Block 타입의 데이터를 저장

Block 타입의 속성은?
1. long blkid : "blk_" 시작하는 파일명 뒤의 long 값을 저장
2. len : block 파일의 크기

Block 을 write 할 때의 순서
1. out.writeLong(blkid); 
2. out.writeLong(len);

DatanodeInfo 를 write 할 때의 순서
1. name.write(out);
2. out.writeLong(capacityBytes);
3. out.writeLong(remainingBytes);
4. out.writeLong(lastUpdate);

여기서 UTF8 은 어떻게 write 할까?

UTF8 타입의 속성?
1. byte[] bytes : byte 값
2. length : String 을 utf8 bytes 로 변환할 때 char 가 1,2,3 byte 로 변환될 수 있으므로 변환한 String의 길이

UTF8 write 순서
1. out.writeShort(length);
2. out.write(bytes, 0, length);
Posted by Kubernetes Korea co-leader seungkyua@gmail.com
사람들이 하도 hadoop이야기를 많이 하길래 한 번 살펴봤다..
마침 회사에서 클라우데라(구글GFS 개념으로 클라우드컴퓨팅을 주장하여 적용한 사람들이 창업한 회사로 hadoop을 이용한 클라우드컴퓨팅 구축 및 컨설팅하는 회사)랑 MOU도 맺었겠다....

현재 첨부를 저장하는 NAS나 DAS 대용으로도 가능하네...
역시 분산/병렬시스템을 지원하는 오픈소스라 가능하구나..

NAS의 경우 장애가 나면 전체 서버의 장애로 이어지는 개념때문에 HA, 고가의 디스크를 쓰면서 돈도 많이 드는데...
사무실 리눅스 서버에 오픈메일서버 구축하고 파일시스템을 hadoop으로 한 다음에 내 메일을 이리로 포워딩하면~~ 메일 저장을 hadoop 기반으로 할 수 있겠는데?

가장 큰 문제는 마스터서버 장애시 HA 방법이네..
이걸 짜볼까??

전에 Sun One Ldap 도 마스터 ldap을 HA로 했을 경우 프로세스는 살아있었지만 실제로는 마스터가 작동을 안해서 HA에 실패한 적이 있는데..
마스터가 비정상적으로 동작하는데 heart beat은 살아있는 경우도 있고..
또 잠시 연결이 안되 다운된 줄 알고 HA가 가동되어 2개의 마스터가 작동된 적도 있었는데..

재미는 있겠다.. 우선 소스부터 봐야지..^^
Posted by Kubernetes Korea co-leader seungkyua@gmail.com
TAG Hadoop, 하둡