[NoSQL/Cassandra] Java용 가장 유명한 클라이언트 Hector 소개

사용자 삽입 이미지

Introduction

그리스 신화에서 카산드라의 형제로 나오는 헥터(Hector)는 가장 위대한 전사였고 트로이를 건설한 인물로 묘사됩니다. 하지만 현재의 IT세계에서는 이둘을 확장성이 뛰어난 데이터베이스와 여기에 쓰이는 자바 클라이언트 라이브러리에 이름을 붙였군요. 실제로 Cassandra를 사용함에 있어 자바를 선택하셨다면 가장 범용적으로 사용되는 라이브러리가 바로 이 Hector입니다. 가장 꾸준히 업그레이드 되고 있고 레퍼런스 역시 잘 구축되어있습니다.

지금까지 나온 다양한 Raw Thrift 클라이언트들은 대체적으로 실제의 클라이언트가 요구하는 필수적인 기능들은 부족한 상황입니다. 이러한 갭을 채우기 위해서 Hector를 만들었습니다.

Cassandra를 위한 하이 레벨 객체 지향 인터페이스를 제공합니다. 기존의 클라이언트들은 항상 멋지고 깔끔한 작업이 가능하도록 하지는 못했습니다. 좀 더 높은 레벨의 깔끔한 API를 제공하는 자바 클라이언트가 바로 이 Hector입니다.

Hector는 Failover를 지원합니다. Cassandra는 데이터를 분산하여 저장하며 어떤 경우에는 매우 잘 동작하겠지만 하나의 노드 또는 다수의 노드가 다운될 수 있습니다. 그러나 기존의 Thrift는 이러한 문제에 아무런 처리를 제공하지 않습니다. 그러나 Hector는 특정 노드가 죽을 경우 자동으로 실패한 명령을 수행할 수 있는 사용가능한 다른 호스트를 검색하고 사용자에게 에러를 알립니다. Failover 를 위한 3가지 정책을 제공하는데 FAIL_FAST(재시도 없음, 에러 발생시 바로 실패, 스마트하지 않음), ON_FAIL_TRY_ONE_NEXT_AVAILABLE(포기하기전에 다른 호스트에 한번 더 시도), ON_FAIL_TRY_ALL_AVAILABLE(포기하기 전에 모든 호스트에 시도)를 제공합니다.

Hector는 커넥션 풀링을 제공합니다. 이 기능은 대규모 어플리케이션에 필수적인 부분입니다. 이런 어플리케이션은 일반적으로 사용되는 DAO패턴을 통해 엄청난 횟수의 작은 규모의 읽기/쓰기가 발생합니다. 클라이언트들은 매번의 요청에 대해 새로운 커넥션을 열만큼의 여력을 가지지 못합니다(TCP 핸드쉐이크 오버헤드). 이에 Hector는 커넥션풀링을 제공하며 매우 멋진 프레임워크 입니다.

Hector는 JMX를 지원하면 이를 이용해서 실행 레벨에서 Metric, 사용가능한 커넥션 수, 유휴 커넥션수, 에러통계등의 정보를 가져올 수 있습니다. Hector는 Command 디자인패턴을 지원하며 사용자는 자신의 비지니스 로직에만 집중할 수 있도록 설계되어있습니다.

Getting Started (5 minutes)

Fully Mavenized
이 저장소를 사용하기 위해서는 다음의 의존성 선언을 당신의 POM파일에 추가하십시오
[code]<dependency>
    <groupId>me.prettyprint</groupId>
    <artifactId>hector-core</artifactId>
    <version>0.8.0-2</version>
</dependency>[/code]
Initializing a Cluster
이제 처음으로 Cassandra 클러스터를 나타내는 클러스터 객체를 생성할 것입니다. 여기서 정의하는 클러스터 이름은 Hector에서 식별하기 위해 사용되며 실제 클러스터의 이름과는 무관합니다. 코드를 좀더 깔끔하게 보이기 위해 API 패키지 전체를 임포트 하였습니다.
[code]import me.prettyprint.hector.api.*;
    …..
Cluster myCluster =
    HFactory.getOrCreateCluster(“test-cluster”,”localhost:9160″);[/code]
스키마를 정의해 봅시다.
[code]ColumnFamilyDefinition cfDef =
HFactory.createColumnFamilyDefinition(
“MyKeyspace”,
“ColumnFamilyName”,
ComparatorType.BYTESTYPE);

KeyspaceDefinition newKeyspace =
HFactory.createKeyspaceDefinition(
“MyKeyspace”,                
ThriftKsDef.DEF_STRATEGY_CLASS,  
replicationFactor,
Arrays.asList(cfDef));

// 클러스터에 스키마 추가
// 두번째 파라미터인 “true”는 모든 클러스터에 변화가 완료될때까지 블록이 됨을 의미
cluster.addKeyspace(newKeyspace, true);[/code]
한번 스키마가 생성되고 나면 이전의 호출은 스키마가 이미 존재함을 알리는 예외를 발생시킵니다. 이 문제를 해결하기 위해서 위의 코드를 createSchema()라는 메소드로 래핑하여 다음과 같이 변경하였습니다.
[code]KeyspaceDefinition keyspaceDef = cluster.describeKeyspace(“MyKeyspace”);

// Keyspace가 존재하지 않는다면 생성합니다.
if (keyspaceDef == null) {
    createSchema();
}[/code]
이제 생성된 Keyspace를 다음과 같은 명령으로 꺼내 쓸 수 있게 되었습니다. “MyKeySpace”는 반드시 이전에 생성된 Keyspace여야 합니다.
[code]Keyspace ksp = HFactory.createKeyspace(“MyKeyspace”, myCluster);[/code]

Creating a template
템플릿은 Keyspace를 조작하기 위한 객체입니다. 이론적으로 비지니스 로직에 대한 접근을 용이하게 하기 위해 사용됩니다.
[code]import me.prettyprint.cassandra.service.template.ColumnFamilyTemplate;
    ……
ColumnFamilyTemplate<String, String> template =
new ThriftColumnFamilyTemplate<String, String>(
ksp,
columnFamily,
StringSerializer.get(),        
StringSerializer.get());[/code]
Accessing data
* Update
[code]// <String, String> 는 키와 값을 뜻함
ColumnFamilyUpdater<String, String> updater =
    template.createUpdater(“a key”);
updater.setString(“domain”, “www.datastax.com”);
updater.setLong(“time”, System.currentTimeMillis());

try {
    template.update(updater);
} catch (HectorException e) {
    // do something …
}[/code]
* Read
[code]try {
    ColumnFamilyResult<String, String> res =
        template.queryColumns(“a key”);
    String value = res.getString(“domain”);
    // 이전에 저장했던 “www.datastax.com” 가 반환됨
} catch (HectorException e) {
    // do something …
}[/code]
* Delete
[code]try {
    template.deleteColumn(“key”, “column name”);
} catch (HectorException e) {
    // do something
}[/code]

참고 :
http://prettyprint.me/2010/02/23/hector-a-java-cassandra-client/ 
https://github.com/rantav/hector/wiki/Getting-started-%285-minutes%29
https://github.com/rantav/hector/downloads  (다운로드)