[HBase] Client 개발 참고 사항[HBase] Client 개발 참고 사항

Posted at 2014. 3. 12. 14:50 | Posted in Server
HTable
- 인스턴스는 한번만 생성하고, 프로그램이 끝날때까지 재사용하라.
- Thread 별로 만들어라.(HTablePool 사용 하라.)
- HTablePool 사용 예(HTableInterfaceFactory 인터페이스로 한번 감싸서 사용하면 편하다)
public class BaseHTableInterfaceFactory implements HTableInterfaceFactory {
	
	private HTablePool hTablePool;
	
	public BaseHTableInterfaceFactory(Configuration config, int maxSize) {
		hTablePool = new HTablePool(config, maxSize);
	}
	
	@Override
	public HTableInterface createHTableInterface(Configuration config, byte[] tableName) {
		return hTablePool.getTable(tableName);
	}

	@Override
	public void releaseHTableInterface(HTableInterface table) throws IOException {
		table.close();
	}
}
- 내부적으로 병렬처리 thread를 가진다. 
  public HTable(Configuration conf, final byte [] tableName)
  throws IOException {
    ...
    int maxThreads = conf.getInt("hbase.htable.threads.max", Integer.MAX_VALUE);
    if (maxThreads == 0) {
      maxThreads = 1; // is there a better default?
    }
    long keepAliveTime = conf.getLong("hbase.htable.threads.keepalivetime", 60);

    // Using the "direct handoff" approach, new threads will only be created
    // if it is necessary and will grow unbounded. This could be bad but in HCM
    // we only create as many Runnables as there are region servers. It means
    // it also scales when new region servers are added.
    this.pool = new ThreadPoolExecutor(1, maxThreads,
        keepAliveTime, TimeUnit.SECONDS,
        new SynchronousQueue(),
        Threads.newDaemonThreadFactory("hbase-table"));
    ((ThreadPoolExecutor)this.pool).allowCoreThreadTimeOut(true);

    /* 설명:
     기본 생성자의 설정이다.
     coreThread=1, maxThreads=Integer.MAX_VALUE 이고, SynchronousQueue를 사용한다.
     따라서 region 서버 수만큼 Thread를 생성하고 keepAliveTime 동안 유지했다가 Thread를 죽인다.
     뜨문 뜨문 호출되는 경우 Thread가 만들어졌다 없어졌다를 반복할 것이므로, 환경에 맞게 조정해서 사용하라.
    */
  ...
  }

- HTable은 HConnection을 사용해서 원격서버와 통신하고, HConnectionManager가 이 커넥션을 관리한다.
- HBase 내부에서는 연결들이 맵 안에 저장되는데 현재 사용중인 Configuration 인스턴스가 키가된다. 동일한 Configuration을 참조하는 HTable 인스턴스를 여러개 만들었다면, 이들 모두는 HConnection 객체를 공유한다.

Put
- 쓰기 버퍼 크기를 늘리면, 클라이언트 뿐 아니라, 서버에서도 많은 메모리를 소비한다. 서버에서도 전송받은 데이터를 인스턴스화 하기 때문이다.(P.148)
- 크기가 큰 셀만을 저장한다면 로컬 버퍼는 덜 유용하다. 실제 데이터 전송 시간이 대부분일 것이고, 이럴 경우는 버퍼 크기를 늘리지 않는 쪽이 권장된다. (p.148)

batch()
- 일괄처리 연산은 Put처럼 쓰기버퍼를 사용하지 않는다. 동기적이며 바로 바로 처리한다.
- 각 작업에 대한 결과를 따로 보고 받을 수 있다. (Object results[])
- 일괄처리 명령은 NotServingRegionException(리전 이동을 알리는 예외)와 같은 일시적인 에러에는 여러 번 시도해본다. hbase.client.retries.number 속성이며 기본값은 10이다.

RowLock/Scanner
- hbase.regionserver.lease.period = 60000 (1분) 락 만료 시간 또는 스캐너 임대 만료 시간에 모두 사용됨.
  - 이 설정은 클라이언트측 Configure에 해봤자 무용지물이다. 리전서버 hbase-site.xml에 설정되어야 한다. (p200)

Scan
- Scan.next() 호출 시 RPC가 일어난다.
- setCaching() / hbase.client.scanner.caching (default=1) 를 조정하여 한번의 RPC에서 여러개의 row를 가져오도록 할 수 있다.
  - 데이터 큰 경우 클라이언트에 전송되는 데이터량이 많아져 수행시간이 길어지고, 메모리 문제로 이어질 수 있다. (p.200)
- setBatch()를 조절하여 한번에 읽어올 컬럼개수를 정할 수 있다. setBatch(5)일 때 컬럼이 17개면 Result인스턴스를 총 4번 받게되고, 세번은 5개, 한번은 2개를 반환할 것이다.(p201) --> RPC 횟수를 조절할 수 있다(p.202)

Filter
- 필터는 클라이언트측에서 생성된 후 RPC를 통해 서버로 전송돼 실행된다. (p.210)
- 사용자 정의 Filter는 jar로 묶어 리전서버 classpath에 넣어줘야 한다(hbase-env.sh). 재시작 필요 (p.244)
- 필터 요약(p.246)

보조처리기(Coprocessor)
- preCreateTable(), postCreateTable(), preGet(), postGet() ... 등
- 정적, 동적 로드 가능하나 0.92 버전 현재 동적 로드 API는 아직 없음. (p.262)

HTablePool
- maxSize는 HTableInterface 인스턴스 개수의 상한선의 의미하지 않는다. 5로 지정하고 getTable()을 10번 실행하면 HTable이 10개 생성된다. 이들을 반환하면 5개까지만 남고 나머지는 버려진다. 즉, Pool에 남겨둘 인스턴스의 상한선이다. (p.289)

HConnectionManager (p.292)
- 동일한 설정의 HTable은 모두 같은 HConnection객체를 공유한다. 
  - 이 공유는 같은 Configure객체를 사용할 때 적용된다. (p.293)
- hbase.client.pause = 1000
- hbase.client.retries.number = 10
- hbase.client.rpc.maxattempts = 1
- hbase.rpc.timeout = 60000
- hbase.client.prefetch.limit = 10


참고: 소스분석 & O'Reilly - HBase 완벽 가이드

//