반응형
HBase eclipse 환경 세팅

1. 새로운 워크스페이스를 만든다.
2.  HBaseEmptyWorkspace.tar.gz 을 다운받아 새로운 워크스페이스에  .metadata 드렉토리를 푼다.
3. 서브버전을 eclipse software install로 설치한다.  (SubClipse Site 에 것을 설치하면 됨)
4. Subclipse 를 설치하면 CollabNet Subversion 을 다운받아 JavaHL을 추가로 설치한다.
    CollabNet Subversion은 /opt/subversion 경로로 설치된다.
5. SVN Repositoty 에서 http://svn.apache.org/repos/asf/hbase/ 를 Root URL로 세팅한다.
6. eclipse 의 Project -> Build Automatically 를 해제.
7. checkout 으로 New Project Wizard 를 선택 ->  Java Project -> HBase-trunk로 프로젝트 이름을 세팅
8. 디폴트 아웃풋 폴더로 PROJECT_HOME/build/eclipse-classes 로 폴더를 생성하여 지정 

9. cmd 로 워크스페이스의 HBase-trunk 폴더로 이동하여 mvn eclipse:eclipse 를 치면 .project 파일이 다시 생성됨


Ant 스트립트

<project name="EmpRelationHadoop" default="compile">

<property name="classes.dir" value="build/classes"/>

<property name="jar.dir" value="build/jar"/>

<property name="library.dir" value="/Users/skanddh/.m2/repository"/>


<path id="libraries">

        <fileset dir="${library.dir}">

            <include name="**/*.jar"/>

        </fileset>

    </path>

    <target name="clean">

        <delete dir="build/classes"/>

    <delete dir="build/jar"/>

    </target>


    <target name="compile">

        <mkdir dir="${classes.dir}"/>

        <javac srcdir="src" destdir="${classes.dir}" classpathref="libraries"/>

    </target>


    <target name="jar" depends="compile">

        <mkdir dir="${jar.dir}"/>

        <jar destfile="${jar.dir}/EmpRelationHadoop.jar" basedir="${classes.dir}">

            <manifest>

                <attribute name="Main-Class" value="hbase.RelationCalculator"/>

            </manifest>

        </jar>

    </target>


    <!-- target name="run">

        <java jar="${jar.dir}/EmpRelationHadoop.jar" fork="true"/>

    </target -->


</project>




반응형
Posted by seungkyua@gmail.com
,
반응형
ssh 키 만들기
localhost:~ skanddh]$ssh-keygen -t rsa -N ""

[출처] ssh 자동 로그인 관련|작성자 김원기


localhost:~ skanddh]$cd .ssh

공개키 서버에 복사하기
localhost:.ssh skanddh]$scp id_rsa.pub <id>@<server>:.ssh/authorized_keys

alias 등록하기
localhost:~ skanddh]$vi .profile

alias ssh01='ssh <id>@<server>'

localhost:~ skanddh]$touch .profile


[서버에서 rsa 키를 생성하여 여러 클라이언트가 접속하게 배포할려면]
1. 서버의 id_rsa.pub 를 authorized_keys 로 복사한다.
2. 클라이언트에 서버의 id_rsa 개인키를 가져온다. 
반응형
Posted by seungkyua@gmail.com
,
반응형
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 seungkyua@gmail.com
,
반응형
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 seungkyua@gmail.com
,
반응형
configuration 의 "dfs.data.dir" 의 값으로 DataNode와 그에 속한 쓰레드를 실행하며 값은space 나 comma 로 분리되고 분리된 갯수 만큼 DataNode를 실행한다. (ServerSocket 을 전달함)

DataNode 생성자에서 서버소켓을 실행, 서버 포트는 "dfs.datanode.port" 의 값으로 시작되며 디폴트는 50010 이고 서버가 갯수 만큼 실행 될 때 +1 씩 포트가 증가한다.

DataNode 가 갖는 쓰레드
1. 자체 Thread : Namenode에 Heartbeat, blockReport 를 보냄
2. DataXceiveServer : ServerSocket 을 전달받아 클라이언트 접속이 있으며 DataXceiver 스레드를 만든다.
3. DataXceiver  : 클라이언트가 보낸 데이터를 읽는다. (in : InputStream, reply : OutputStream)
    1. in.read() : 1 byte 를 읽어서 operation 을 알아낸다.
    operation 이 write block 일 경우
    2. in.readBoolean() : 리포트를 해야할 블럭인지 boolean 값을 읽어낸다.
    3. block.readFields(in) : block id와 block의 길이 len 을 읽는다.
    4. in.readInt() : block 을 복사할 타켓의 갯수를 읽는다.
    5. DatanodeInfo.readFields(in) : 데이터 노드명, 용량, 남은용량, 마지막 업데이트 값을 타겟수만큼 읽는다.
    6. in.read() : 인코딩 타입을 1 byte 읽는다.
    7. in.readLong() : 이후 읽어야할 실제 데이터 길이 len 을 읽는다.

    현재 데이터노드 서버에 파일을 생성하여 outputstream 을 만든다. 
    첫번째는 자신의 데이터 노드 이므로 다음 타겟인 데이터노드와 소켓으로 접속하여 out2 와 in2 를 생성한다.
    1. out2.write(OP_WRITE_BLOCK) : 1 byte 값이 block write operation을 보낸다.
    2. out2.writeBoolean(shouldReportBlock) 으로 리포트 해야할 블럭인지를 보낸다.
    3. block.wirte(out2) : block id와 block의 길이 len 을 쓴다.
    4. out2.writeInt(target.length -1) : 복사해야할 남은 타겟의 갯수를 쓴다.
    5. DatanodeInfo.write(out2) : 루프를 돌면서 남은 데이터노드의 정보를 보낸다.
    6. out2.write(encodingType) : 1 byte 의 인코딩 타입값을 쓴다.
    7. out2.writeLong(len) : 데이터 길이 len 을 쓴다.

    8. in.read(buf, 0, len) : 루프를 돌면서 데이터를 다 읽는다.
    9. out.write(buf,0, len), out2.write(buf, 0, len) : 루프를 돌면서 로컬 파일(out) 과 out2 에 데이터를 쓴다.

    10. out2.flush() : 복사하는 타겟 out2 를 flush 한다.
    11. in2.readLong() : long 값의 WRITE_COMPLETE 를 읽는다. 복사된 타겟이 잘 전달됐는지 확인
    12. LocatedBlock.readFields(in2) : block 을 읽고 DatanodeInfo의 갯수를 읽고 루프돌면서 DatanodeInfo 읽음
                                                     이것으로 복사된 타겟의 정보를 얻을 수 있음
    13. data.finalizeBlock(b) : DataNode 의 속성인 FSDataset 의 dirTree 에 block과 파일을 저장
    14. receivedBlockList.add(b) : Namenode에 보고할 block을 리스트에 저장한다. 
                                               리스트에 저장되면 Datanode 자체쓰레드에서 관련 정보를 Namenode에 보냄
    15. reply.writeLong(WRITE_COMPLETE) : 클라이언트에게 complete 메세지를 보냄
    16. LocatedBlock.write(reply) : block, DatanodeInfo 갯수, 루프를 돌면서 DatanodeInfo.write 를 보낸다.
반응형
Posted by 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 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 seungkyua@gmail.com
,
반응형
UTF8 타입에는 byte[] 와 length 를 가지고 있다.

1. set(String string) 을 사용하여 string -> byte[] 로 저장할 때 DataOutputBuffer 사용
    String -> charAt(i) 루프를 돌면서 utf8 byte 로 변환하여 DataOutputBuffer 의 byte[] 에 저장 ->
    System.arraycopy로 UTF8 byte[] 에 복사

2. toString() 으로 byte[] -> String 으로 리턴할 때 DataInputBuffer 와 DataOutputBuffer 사용
    UTF8 byte[] -> DataInputBuffer 의 byte[] 에 저장 -> 
    DataInputBuffer를 argument로  DataOutputBuffer 의 byte[] 에 저장 (out.write(in)) -> 
    DataOutputBuffer의 byte[] 를 StringBuffer에 append 하여 리턴

여기서.. 의문.. 왜 2 번에서 UTF8 byte[] 를 DataOutputBuffer byte[] 에 arraycopy를 하지 않을까?

간단함.. 그냥 그런 api 를 만들지 않았음.. byte[] 를 받아서 저장하는 것은 DataInputBuffer 에만 존재
DataOutputBuffer 는 DataInputBuffer 를 이용해서 byte[] 를 저장.

중요한 것은 DataOuputBuffer 는 DataOutputStream 을 상속받았지만 DataOutputStream 에는 없는 buffer 기능을 추가하였음. (내부 클래스로 ByteArrayOutputStream 을 상속받은 Buffer 클래스가 존재)

DataInputBuffer 도 DataInputStream 을 상속받있지만 똑같이 buffer 기능을 추가.

반응형
Posted by seungkyua@gmail.com
,
반응형
Safari Javascript Debug Console

defaults write com.apple.Safari IncludeDebugMenu 1
반응형
Posted by seungkyua@gmail.com
,
반응형
ie 인지 판별하는 법

var userAgent = navigator.userAgent.toLowerCase();
var isIE = (/msie/gi.test( userAgent ) && !/opera/gi.test( userAgent ));


로딩 이벤트 등록하기

if (isIE) {
    iframe.attachEvent('onload', 함수명);
} else {
    iframe.addEventListener('load', 함수명, false);
}
반응형
Posted by seungkyua@gmail.com
,