블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

HBase 와 구글의 빅테이블

#1 아키텍쳐


조대협 (http://bcho.tistory.com)

HBase

HBase 는 아파치 오픈소스 NoSQL 솔루션으로 구글의 빅테이블  (https://research.google.com/archive/bigtable.html) 논문을 기반으로 개발되었다.

Key/Value Store 기반의 NoSQL이며, 대용량 데이타를 빠르게 처리할 수 있는 기능을 가지고 있다.

데이타 모델

HBase는 컬럼 패밀리라는 데이타 모델을 사용하는데, 대략적인 구조를 보면 다음과 같다.

각 행은 하나의 로우키(rowkey)를 가지고 있다. 이 키는 RDBMS의 프라이머리 키와 같은 키라고 보면 된다.

각각의 행에는 컬럼이 정의되어 있는데, RDBMS 테이블의 일반 컬럼과 같은 개념이라고 보면 된다. 특이 사항은 이 컬럼들이 컬럼 패밀리 (Column family)라는 것으로 묶이게 되는데, 이렇게 컬럼 패밀리로 묶인 컬럼의 데이타는 물리적으로 같은곳에 저장이 된다. 그래서, 데이타 접근시에 한꺼번에 접근되는 데이타의 경우에는 컬럼 패밀리로 묶는 것이 유리하다.

위의 그림은 name과 contact, 그리고 company라는 컬럼 패밀리를 가지고 있고,

  • name 컬럼 패밀리는 lastname,firstname 컬럼

  • contact 컬럼 패밀리는 phone, mobile, email 컬럼

  • company 컬럼 패밀리는 company라는 컬럼

을 가지고 있다.

내부적으로 데이타는 rowkey에 의해서 오름차순으로 정렬이 되서 저장이 된다.



각 컬럼의 값을 셀이라고 하는데, 데이타 셀에는 timestamp가 있어서 이전의 값이 같이 저장되며, 일정 기간까지 그 값을 유지하도록 한다.


조인이나 인덱스등을 지원하지는 않지만 대용량 데이타를 안전하고 빠르게 저장 및 억세스가 가능하기 때문에, 광고 클릭 데이타나, 사용자 행동 데이타 수집, 로그 수집, IOT의 센서 데이타, 금융에서 시계열 데이타 등을 저장하는데 유용하게 사용할 수 있다.

아키텍쳐

아래 아키텍쳐는 HBase의 원조인 빅테이블의 아키텍쳐이다.




주키퍼등 몇몇 시스템들이 빠져 있지만, 큰 구조는 유사하다고 보면 된다.

데이타 노드에 SSTable 이라는 파일 형태로 데이타가 저장되어 있고, 위에 연산 노드가 붙어서 클러스터를 이룬다. 각 노드는 데이타를 저장하고 있는데, 로우키에 따라서 그 데이타가 분산되어 저장된다. 예를 들어 키가 1~3000의 범위를 가지고 노드가 3개이면 1번 노드는 1~1000, 2번은 2~2000, 3번은 3~3000 데이타를 저장하고 처리하게 된다.


각 노드의 구조는 다음과 같다.

쓰기 연산이 들어오면, 쓰기에 대한 로그를 tablet log 라는 파일에 남긴다. RDBMS의 백로그와 같은 개념으로 보면 되는데, 장애가 나더라도, tablet log가 남아 있기 때문에 이를 통해서 디스크에 쓰여지지 않은 데이타를 복구할 수 있게 된다.




데이타 로그를 쓰고 나면, 실제 데이타는 memtable 이라는 메모리 기반의 중간 저장소에 저장이 되고, 이 memtable이 꽉차게 되면, 데이타를 SSTable로 플러슁하고, tablet log에 있는 데이타를 지우게 된다. 이 과정을 Minor compaction이라고 한다.


읽기 연산이 들어오면, 먼저 memtable을 뒤져보고, 없을 경우 SSTable을 뒤져서 데이타를 읽게되는데, SSTable은 물리적으로 다음과 같은 모양을 하고 있다.

name,address,gender 라는 컬럼은 실제 SSTable 내에서 각 셀단위로 쪼게 져서 셀단위로 row key와 컬럼패밀리, 컬럼 명을 키로 하고, 그 안에 값을 저장한다. 만약에 같은 키의 셀을 업데이트 하더라도 그 데이타 셀을 업데이트 하는것이 아니라 새로운 시간 timestamp를 달아서, append 하는 방식으로 데이타를 저장한다.


계속 append 만하면, 저장 공간이 부족해지기 때문에, 어느 일정 시간이 되면 오래된 데이타를 지워야 하는데 이를  compaction이라고 하며 주기적으로 이 작업이 일어나게 된다.

핫스팟

아키텍쳐를 이해하면, 데이타가 어떻게 분산되는지를 이해할 수 있는데, 그래서 생기는 문제가 HOTKEY라는 문제가 발생한다.

예를 들어 주민등록 번호를 로우키로 사용하는 서비스가 있는데 98년생~08년생들에게 특히 인기가 있다고 하면, 그 키 범위내에 데이타가 다른 연령대에 비해서 많을 것이고, 98~08년 로우키 범위를 담당하는 노드에 부하가 많이 갈것이기 때문에 제대로 된 성능을 내기 어려워진다. 이와 같이 특정 로우키범위에 데이타가 볼리는 곳을 핫스팟이라고 하는데, 이를 방지하기 위해서는 키의 값을 UUID와 같은 랜덤 스트링이나 해쉬값등을 사용하여 전체적으로 분포가 골고를 키를 사용하는 것이 좋다.

구글 빅테이블

구글의 빅테이블은 HBase의 원조가 되는 서비스로, 구글 내부에서 지메일과 광고플랫폼등 여러 분야에 사용되고 있으며, 현존하는 단일 데이타베이스 시스템중 가장 큰 데이타 시스템이다.

개발 초기 당시에는 GFS (하둡파일 시스템 HDFS의 전신)을 사용하였으나, 콜러서스라는 고속 파일 시스템으로 변경하면서 매우 빠른 성능을 낼 수 있게 되었다.

구글 빅테이블은 구글 클라우드 (http://cloud.google.com)을 통해서 서비스가 제공되며, HBase API와 호환이 되기 때문에, 별도의 변경 없이 기존 HBase 애플리케이션 및 HBase 관련 도구를 사용할 수 있다는 장점이 있다.

성능은 HBase에 비해서, 초당 처리 성능은 대략 2.5배, 응답 시간은 50배 정도 빠르다.


(성능 비교 자료 http://www.i-programmer.info/news/197-data-mining/8594-google-cloud-bigtable-beta.html)


수십 페타의 데이타를 저장하더라도 일반적인 읽기나 쓰기의 경우 한자리 ms (~9ms)내의 응답성을 보장하기 때문에 빅데이타 핸들링에 매우 유리하며, 안정적인 구조로 서비스가 가능하다. 빠른 응답 시간 때문에 앞단에 캐쉬 서버를 두지 않아도 되서 전체 시스템 아키텍쳐를 단순화할 수 있는 장점을 가지고 있다.


빅테이블의 내부 아키텍쳐는 다음과 같은 모양으로 되어 있다.





성능 저하 없는 안정적인 확장

HBase와 유사한 구조이지만, 큰 특징이 데이타 노드와 연산노드 (Bigtable node)가 물리적으로 분리되어 있고, 하단의 파일시스템이 무제한 확장 구조를 갖는 구조를 가지고 있다.


즉 무슨 이야기인가 하면 데이타 파일이 콜로서스 파일 시스템 내에 아래와 같이 배치 되어 있고, 연산 노드는 자기가 관리한 SSTable 파일을 포인팅 하는 구조로 되어 있다.


이게 무슨 장점을 가지냐 하면, 보통 NoSQL이나 분산 시스템은 리밸런성이라는 작업을 하게 되는데, 데이타가 점점 쌓여가면, 그 연산노드와 데이타 노드에 데이타가 부하가 몰리기 때문에 그 데이타 청크를 나눠야 하는 일이 발생을 하게 되는데 이를 리밸런싱이라고 한다. 이때 물리적으로 데이타 노드의 데이타를 다른 노드로 이동해야 하기 때문에, 이 이동/복사 작업이 부하를 일으켜서 전체 시스템의 성능에 영향을 주게 된다.


아래 그림을 예로 들어보자




첫번째 노드에서 데이타 파티션, A,B,C를 관리하고 있다가 데이타가 많아져서 C를 두번째 노드로 이동하고자 하면, C데이타를 물리적으로 복사하여 두번째 노드의 저장소로 옮겨줘야 한다.

그러나 빅테이블의 경우 콜로서스에 파일이 공유 스토리지 형식으로 저장되어 있기 때문에, 물리적인 파일 이동은 필요없고,  연산 노드에서 어떤 데이타 파티션을 처리할지에 대한 포인터만 변경해주면 된다.



이런 이유 때문에, 내부적으로 리밸런싱이 일어나더라도, 리밸런싱에 의한 성능 저하나 충격이 전혀 없다는 장점을 가지고 있다.

마찬가지 원리로 연산 노드가 추가되거나 삭제될때도 HBase의 경우에는 리밸런싱에 의한 실제 데이타 이동 부하가 발생하는데, 빅테이블의 경우에는 새로운 노드를 추가하고, 각 노드에서 처리하는 데이타 포인트만 변경하면 되기 때문에, 성능 저하 없이 안정적으로 확장이 가능하다.


다음글에서는 HBase 를 로컬에 설치하는 방법과, 구글 클라우드 빅테이블을 설정하는 방법을 알아보고 CLI 명령을 이용하여 간단한 테이블 생성 및 데이타를 조작하는 방법에 대해서 알아보겠다.


대용량 시스템 레퍼런스 디자인


SSAG - Face book Server Side Architecture Group

http://www.facebook.com/groups/serverside

조대협 (bwcho75 골뱅이 지메일닷컴)


I. 배경

웹로직,JBOSS 가 유행이던, J2EE 시대만 하더라도, 웹서버+WAS+RDBMS면 대부분의 업무 시스템을 구현할 수 있었다. 오픈소스가 유행하면서 부터는 프레임웍 수는 다소 많기는 했지만 Spring,IBatis or Hibernate,Struts 정도면 대부분 구현이 가능했다.

그러나 근래 수년 동안 벤더 중심에서 오픈소스 중심에서 기술의 중심이 구글,페이스북이 주도하는 B2C 기반의 서비스의 유행과 더불어 대규모 분산 시스템을 위한 대용량 아키텍쳐가 유행하게 되었는데, 이 아키텍쳐의 특징이 오픈소스 중심에 상당히 다양한 수의 솔루션이 사용 되었다.


II. 내용

이 글에서는 일반적인 대용량 시스템을 구축하기 위한 레퍼런스 아키텍쳐를 소개한다.

일반적인 웹이나 서버 플랫폼을 개발할 수 있는 레퍼런스 아키텍쳐이며, 자주 사용되는 오픈 소스 솔루션을 조합하였다.


또한 이 아키텍쳐는 데이타 분석등의 용도가(OLAP)이 아니라 온라인 트렌젝션 처리 (OLTP)성 업무를 위해서 디자인된 아키텍쳐이다.


III. 레퍼런스 아키텍쳐



1. Reverse Proxy Layer - Routing & Load Balacing

첫번째 계층은 Reverse Proxy 계층으로, 첫번째에 들어오는 HTTP Request에 대한 관문 역할을 한다.

이 Reverse Proxy에서는 초기 Request에 대한 Logging, 필요하다면, Authentication & Authorization 처리를 수행하고, 뒷쪽에 Request를 보낼때, 뒷단의 Node로 Routing 또는 Load Balancing을 한다.

뒷단에 클러스터가 업무에 따라서 여러 클러스터로 나뉠 수 있기 때문에 이에 대한 라우팅을 수행하거나, 같은 업무에 대해서는 단일 클러스터에 대해서 여러 서버에 대한 로드 밸런싱을 수행한다.


뒤에 살아 있는 서버에 대한 리스트나 클러스터에 대한 정보는 ZooKeeper에 저장하며, Scale In/Out시 또는 장애시에는 이 정보를 ZooKeeper에 업데이트 하여, ZooKeeper에 저장된 클러스터 정보를 기준으로 라우팅을 한다.


사용할만한 솔루션으로는 Apache,NginX,HA Proxy등이 있다.

성능 상으로는 NginX가 가능 높다. 그러나 NginX는 대용량 HTTP Request에 대해서 아직 제대로 지원하지 않는 부분이 있다. 파일 업다운 로드의 경우 성능이 급격하게 떨어지는 부분이 있다. 위에서 설명한 ZooKeeper연동이나 Routing 기능들은 module을 구현하여 plug in해야 한다.


2. [Optional] Enterprise Service Bus (ESB) Layer - Cross Cutting Concern, Mash up,Routing,MEP (Message Exchange Pattern Converting),Integration, SLA management,Protocol Converting

이 계층은 필요에 따라 넣거나 뺄 수 있는 Optional 한 부분이다. Enterprise Service Bus는 시스템으로 들어오는 메세지에 대해서 좀 더 확장된(진보된) 기능을 제공하는 계층으로, SOA (Service Oriented Architecture)에서 따온 계층이다. 키 포인트는 성능이다. BY PASS의 경우 10~50ms 이내에 통과(IN/OUT 포함), 몬가 작업을 할 경우에는 100ms 이하에 통과되어야 한다.

ESB 계층에서 다루어야 하는 일들은 다음과 같다.

  • Cross Cutting Concern 처리 : Cross Cutting Concern는 횡종단 처리라고 하는데, 모든 메세지에 대해서 뒷단의 비지니스 로직이 공통적으로 처리해야 하는 부분을 이야기 한다. 대표적인 예로, Logging, Authentication & Authorization 등이 있다. 
  • Routing 처리 : Reverse Proxy 보다 향상된 Routing 기능을 제공할 수 있다. 보통 Reverse Proxy에서는 HTTP Header나 URI등의 최소한의 정보를 바탕으로 라우팅을 하는데 반해서, ESB 계층에서는 Message 본문의 Header나 Message 자체의 내용을 가지고 라우팅을 할 수 있다. 예를 들어 VIP 회원에 대해서는 Dedicated 된 서버로 라우팅을 하는지 등의 처리가 가능하다.
  • Protocol Converting : ESB 계층에서는 또한 Protocol 변환을 할 수 있다. 예를 들어 뒷단의 비지니스 컴포넌트가 XML/REST를 지원하는데, 전체 표준을 JSON/REST를 사용한다면, ESB 계층에 프로토콜 변환 기능을 넣어서 JSON to XML 변환을 수행할 수 도 있고, 또 다른 예로는 통신사의 경우 종종 HTTP 메세지를 손을 대는 경우가 있다. Header에 통신사 고유의 헤더를 삽입하는 등의 일이 있는데, 이런 경우 범용으로 디자인 된 시스템은 
  • Mash Up : Mash Up은 뒤의 비지니스 로직 여러개를 합쳐서 하나의 비지니스 로직을 만들어 내는 것을 이야기 한다. 쉬운 예로 기존 서비스가 "구매" 라는 Function이 있었는데, "포인트 적립" 이라는 기능이 새롭게 추가 되었을때, 비지니스 로직 자체를 변경하는 것이 아니라 기존 "구매" 라는 기능에 +"포인트 적립" 이라는 기능을 Mash up으로 더해서 기능을 변경하는 것이다. 이렇게 하면 비지니스 로직 변화 없이 새로운 기능을 구현할 수 가 있다.
  • MEP Converting : MEP란 Message Exchange Pattern의 약자로 메세지의 호출 방식을 이야기 한다. 쉽게 말하면 Sync,Async 와 같은 호출 방식을 정의하는데, 비지니스 로직이 Long Running 하는 Sync 형식의 서비스 였을 때, ESB를 이용하여, Sync 호출을 Async 형태로 변경할 수 있다. (ESB에서 응답을 먼저 보내고, ESB에서 비지니스 컴포넌트로 ASync로 보내는 형태)
  • Integration : 타 시스템과의 통합을 이야기 한다. 일종의 EAI (Enterprise Application Integration) 기능인데, 앞에서 언급된 Mash up + Protocol Conversion + MEP Converting을 합쳐놓은 기능과도 비슷하다. 크게 대내 시스템간의 통합과 대외 시스템과의 통합등으로 나뉘어지며, 대내 시스템과의 통합은 Legacy (SAP와 같은 ERP, Siebel과 같은 CRM과 같은 패키지 형태의 Application)과 통합 하는 경우가 많으며 이런경우 전용 아답터를 사용하는 경우가 많다. 대외 시스템 통합의 경우 예를 들어 전자 결재나 PUSH 서비스 등과  통합하는 경우이며 이 경우 필요에 따라 프로토콜 변환이나 Authentication & Authorization 처리를 하는 경우가 많으며 특히 과금이 연동되는 경우에는 향후 Audit을 위해서 로그를 기록하고 향후 비교하는 경우가 많다.
  • SLA management : SLA (Service Level Agreement)로, Service의 품질을 보장 하는 기능이다. 정확하게는 SLA를 보장한다기 보다는 SLA에 문제가 생겼을때 이를 빠르게 감지하여 후처리를 할 수 있다. ESB는 시스템으로 들어오는 모든 메세지에 대한 관문 역할을 하기 때문에 응답 시간이나 TPS에 대한 변화가 생겼을때 이를 검출할 수 있는 단일 지점으로, 장애 상황에 대한 검출이 있었을때 이에 대한 후처리를 하도록 관리자에게 통보할 수도 있고, 또는 ZooKeeper를 통해서 성능이 떨어지는 노드들에 대한 Scale Out등을 지시할 수 있다.

ESB는 설계시에 적용을 해놓으면 후에 시스템의 변화가 있을 경우에 도움이 많이 되는 계층이다. 시스템 초기 운영시에는 오히려 큰 이득을 보지 못한다. 왜냐하면 처음에는 모든 비지니스 컴포넌트가 초기 요구 사항에 맞춰서 구현이 되었고, 위의 기능들은 시스템을 운영하면서 요구사항이나 환경적인 변화에 따라 발생하는 요구 사항이기 때문이다. 

앞에서도 언급했으나, ESB는 메세지가 지나가는 중간에 위치 하기 때문에 전체 시스템의 성능에 영향을 주게 되기 때문에 성능에 각별한 신경을 써서 디자인을 해야 하며, 특히 메세지의 파싱하는 과정과 메세지 자체 설계에 신경을 많이 써야 한다. 예를 들어 일반적인 경우 메세지의 BODY 부분을 파싱할 일이 없는데 모든 요청에 따라서 BODY 부분을 파싱하게 한다면 이에 대한 오버로드가 상당히 크게된다.


사용 가능한 솔루션으로는 Apache Mule이나 Oracle사의 Oracle Service Bus등이 있고, 재미있는 장비중의 하나는 Oracle Service Bus 제품중에 XML 기반의 메세징을 파싱하는 부분을 Hardware로 구현해놓은 제품이 있다. Oracle Service Bus도 내부적으로 JAXP 기반의 XML Parser를 이용하는데, 이 구현 부분을 ASIC으로 구현해 놓은 제품이 있는데 이 제품의 경우 메세지 처리 속도를 많이 높일 수 있다.


3. WAS Layer - Business Logic

이 계층은 비지니스 로직을 핸들링 하는 계층이다.

Web Application Server (WAS)로 구현이 가능하며, 고속 멀티플렉싱 기반의 고속 처리가 필요한 경우나 대규모 Stateful Connection이 필요한 경우에는 Netty와 같은 네트워크 서버를 사용한다.

이 계층 구현시 중요한점은 Shared Nothing 아키텍쳐를 적용하는 것을 권장한다.

Shared Nothing이랑 WAS 인스턴스끼리 클러스터링등을 통해서 묶지 않고 각각의 WAS를 독립적으로 돌아가게 설계하는 것이다. (대표적으로 Session Clustering을 사용하지 않는것)

이렇게 하는 이유는 특정 인스턴스가 장애가 났을 때 클러스터를 타고 전파되는 현상을 방지하고 또한 횡적인 확장 (Horizontal Scalability )를 보장하기 위해서이다.

참고 자료 

- WAS 기반의 아키텍쳐 http://bcho.tistory.com/373

- J2EE 그리드 아키텍쳐 http://bcho.tistory.com/330


4. Async message Handling

WAS 계층이 Sync 형태의 동기 (Request/Response) 메세지를 처리한다면, 비동기 메세징 처리나 Publish/Subscribe와 같은 1:N 기반의 비동기 메세지 처리를 하는 계층이 필요하다.

예전에는 MQ나 JMS를 많이 사용했으나, 근래에는 좀더 향상된 프로토콜인 AMQP를 기반으로 한 RabbitMQ가 많이 사용된다.


RabbitMQ의 경우에도 수억명의 사용자를 커버하기에는 클러스터의 확장성이 문제가 있기 때문에 이런 경우에는 MySQL등의 DBMS의 테이블을 큐 처럼 사용하고, 메세지를 읽어가는 부분을 Quartz등을 이용해서 주기적으로 읽어가서 처리하는 구조로 만들게 되면 확장성을 보장할 수 는 있으나, 복잡한 비동기 메세징 (에러처리, Pub/Sub)을 구현하기에는 난이도가 높기 때문에, RabbitMQ를 복수의 클러스터로 묶는 Sharding이나 분산큐(Distributed Queue) 개념을 고려할 필요가 있다.


5. Temporary Storage Layer - Temporary space

다음 계층은 Temporary Storage Layer - 작업 공간이다.

이 작업 공간은 4번의 WAS들이 서로 데이타를 공유할 수 있는 "휘발성", 작업 공간이다. 

필수 조건은 높은 성능을 보장해야 하며, 모든 WAS Node가 접근할 수 있어야 한다. 저장 매체가 Memory냐, Disk냐에 따라서 다음과 같이 나눠볼 수 있다.


1) Data Grid (Memory)

데이타 그리드는 쉽게 생각하면 자바의 HashTable 같은 Key/Value Store 기반의 메모리 Store이다. 단.. 이 그리드는 클러스터 구성을 통해서 용량 확장이 가능하고, 별도의 서버 클러스터로 구성되어 여러개의 WAS 노드들이 접근할 수 있다. 일종의 WAS간의 공유 메모리라고 생각하면 된다.

솔루션으로는 Oracle Coherence (예산만 넉넉하다면 이걸 쓰는게 맘편하다), Redis, memecahed, Terracota 등이 있다.

참고 자료 

- Redis 소개 - http://bcho.tistory.com/654

- Coherence를 활용한 아키텍쳐 설계 - http://bcho.tistory.com/327


2) Working Space (DISK)

트렌젝션을 처리하다 보면, 종종 임시적인 작업 공간이 필요할때가 있다. 예를 들어 드롭 박스와 같은 파일 서비스를 이야기 해보자, 드롭박스는 이미지 파일을 하나 올리면, 모바일 디바이스의 화면 해상도에 맞게 5개의 썸네일 이미지를 재 생산한다. 이런 작업을 하기 위해서는 이미지 파일을 저장하기 위해서 임시로 저장해놨다가 썸네일을 추출하는 공간이 필요한데 이를 임시 작업 공간이라고 한다.

데이타 그리드와 마찬가지로, 여러 노드들이 해당 공간을 공유할 수 있어야 한다. 그래서 NFS (Network File System)이 많이 사용되며, Gluster와 같은 소프트웨어 기반의 NFS나 NetApp社의 NFS appliance server (하드웨어) 등이 있다.

참고 자료

- Amazon에서 Gluster 성능 비교 자료 - http://bcho.tistory.com/645


6. Persistence Layer

다음은 영구 저장 공간이다. 영구 저장 공간은 우리가 일반적으로 생각하는 데이타가 저장되는 공간이라고 보면된다.  쉽게 예를 들 수 있는 공간으로는 데이타 베이스와 파일 시스템을 들 수 있다. 이러한 영구 저장소는 대용량 B2C 시스템의 유행과 함께 새로운 DBMS들이 등장하였는데, DBMS 측면에서는 Key Value Store 기반의 NoSQL이나, 대용량 파일을 저장할 수 있는 Object Store등을 그 예로 들 수 있다.


1) Relational Data

개체간의 관계가 있는 경우에 대한 데이타를 관계형 데이타라고 하고, 이를 핸들링 하기 위해서는 관계형 데이타 베이스 RDBMS를 사용한다. 우리가 지금까지 일반적으로 사용해왔던 데이타 베이스가 이 RDBMS이다. RDBMS는 대용량 서비스를 위해서는 태생적인 한계를 가지고 있는데, 예를 들어 MySQL의 경우 하나의 데이타베이스에서 저장할 수 있는 레코드의 수가 10억개 정도가 최적이다. 

이런 문제를 해결하기 위해서는 대용량 시스템에서 몇가지 기법을 추가로 사용하는데 "Sharding" 과 "Query Off Loading"이다.


Sharding이란, 데이타의 저장용량의 한계를 극복하기 위한 방안으로

데이타를 저장할때 데이타를 여러 데이타 베이스에 걸쳐서 나눠 저장하는 방법이다. 예를 들어 "서울","대구","대전"등 지역별로 데이타베이스를 나눠서 저장하거나(이를 횡분할 Sharding) 또는 10대,20대,30대 식으로 데이타를 나눠서 저장하는 방식(이를 수직분할 Sharding)을 사용한다. 이러한 Sharding은 데이타베이스 계층에서 직접적으로 지원하기가 어렵기 때문에, 애플리케이션 레벨에서 구현해야 한다.


다음으로 Query Off Loading이라는 기법으로, 이 기법은 성능의 한계를 높이기 위한 기법이다. 

"Master DB → Staging DB → Slave DB 1,Slave DB 2,....N"

    1. Create/Update/Write/Delete는 Master DB에서 수행하고
    2. Master DB의 데이타를 Staging DB로 고속 복사한후
    3. Staging DB에서 N개의 Slave DB로 데이타를 복사한다.
    4. Read는 Slave DB에서 수행한다.

일반적인 DBMS 트렌젝션은 10~20% 정도가 Update성이고, 나머지 80~90%가 Read성이기 때문에, Read Node를 분산함으로써, 단일 DBMS 클러스터의 임계 처리 성능을 높일 수 있다.


이때 Master/Staging/Slave DB로 데이타를 복제하는 방식이 매우 중요한데, 여기서 일반적으로 사용하는 방식을 CDC (Change Data Capture)라고 한다.

RDBMS는 데이타 베이스 장애에 대한 복구등을 위해서 모든 트렌젝션을 파일 기반의 로그로 남기는 데 이를 Change Log라고 한다. CDC는 이 Change Log를 타겟 DB에 고속으로 복사해서 다시 수행(Replay)하는 형태로 데이타를 복제한다.


MySQL의 경우 Clustering에서 이 CDC 기능을 기본적으로 제공하고 있고, Oracle의 경우 Oracle Golden Gate라는 솔루션을 이용한다. (비싸다..) 중가격의 제품으로는 Quest의 ShareFlex들을 많이 사용한다.


2) Key/Value Data

다음으로 근래에 들어서 "NoSQL"이라는 간판을 달고 가장 유행하는 기술중의 하나가 Key/Value Store이다.

데이타 구조는 간단하게 Key에 대한 데이타(Value)를 가지고 있는 형태이다. RDBMS와 같이 개체간의 관계를 가지지 않는다.

오로지 대용량,고속 데이타 억세스,데이타에 대한 일관성 에만 초점을 맞춘다. (이중에서 보통 2개에만 집중한다. 이를 CAP 이론 - Consistency, Availability, Performance)


이 기술은 태생 자체가 B2C 서비스를 통해서 탄생하였다.

블로그나 트위터, 페이스북 처럼 데이타의 구조 자체가 복잡하지 않으나 용량이 많고 고성능이 필요한 데이타들이다. 태생 자체가 이렇기 때문에 복잡한 관계(Relationship)을 갖는 복잡한 업무 시스템에는 잘 맞지 않는 경우가 많으며, 트렌젝션 처리나 JOIN, SORTING 등이 어렵기 때문에 애플리케이션의 구현 복잡도가 올라간다.


참고 자료

- 사람들은 왜 NoSQL에 열광하는가? - http://bcho.tistory.com/658

- Amazon Dynamo 계열의 NoSQL 장단점 - http://bcho.tistory.com/622

- NoSQL Riak - http://bcho.tistory.com/621

- NoSQL 계보 정리 - http://bcho.tistory.com/610

- Cassandra 소개 - http://bcho.tistory.com/440


3) Object Data

Object Data는 File과 같이 대용량 데이타 파일 저장을 할 수 있는 Storage이다.

10M,1G와 같은 대용량 파일을 저장할 수 있는 저장소로, Amazon의 S3, Openstack SWIFT등이 대표적인 예이며, 하드웨어 어플라이언스 장비로는 애플의 iCloud로 유명해진 EMC의 isilion등이 있다.

Object Data 저장에 있어서 중요하게 생각하는 부분은 대용량의 데이타를 저장할 수 있는 용량에 대한 확장성과 데이타 저장에 대한 안정성이다. 

이러한 Object Data는 Quorum이라는 개념을 적용하여, 원본을 포함하여 N개의 복사본을  유지한다. 일반적으로는 N+3 (3개의 복사본)을 저장하여 데이타에 대한 안정성을 보장한다. 


4) Document Data

Document Data는 Key/Value Store에서 조금 더 발전한 데이타 저장 방식으로

Key 자체는 동일하나 Value에 해당하는 부분이 Document가 저장된다. Document 는 JSON이나 XML 문서와 같이 구조화된 데이타를 저장한다.

RDBMS가 다양한 select, where, group, sorting,index 등 여러가지 데이타에 대한 기능을 제공한다면, Key/Value Store는 이런 기능은 거의 제공하지 않는다. Document Data를 저장하는 제품들은 RDBMS와 Key/Value Store의 중간정도에서 데이타에 대한 핸들링 기능을 제공한다. (부족한 Indexing 기능, 부족한 Group 기능, 부족한 Sorting 기능등)


대표적은 솔루션으로는 MongoDB,CouchDB, Riak등이 있다.


요즘 들어서 자주 사용되는 대표적인 Persistence Store에 대해서 간단하게나마 집고 넘어갔지만, 사실 이 보다 더 많은 형태의 Persistence Store들과 기능들이 있다.


7. Configuration management & Coordinator

대용량, 분산 시스템으로 발전하면서 풀어야되는 문제중의 하나가 "분산되어 있는 노드들에 대한 설정(Configuration)정보를 어떻게 서로 동기화하고 관리할것인가? (이를 Configuration Management라고 한다.) " 인다. 거기에 더해서 클라우드 인프라를 사용하면서 "전체 클러스터내의 서버들의 상태를 모니터링 해서, 서버의 수를 느리고 줄여야 하며 서버들간의 통신을 중재해야 한다. (이를 Coordination 이라고 한다.)"  


여기에 필요한 기능이 작은 량의 데이타(Configuration Data)를 여러 서버가 공유해서 사용할 수 있어야 하며, 이 데이타의 변화는 양방향으로 클러스터 노드내에 전해져야 한다.

즉 Configuration 정보를 각 서버들이 읽어올 수 있어야 하며, 이 Configuration 정보가 바뀌었을 경우 다른 서버들에게 데이타가 변했음을 통지해줄 수 있어야 하며, 중앙 집중화된 Configuration 정보 뿐만 아니라, 서버의 상태가 변했음을 다른 서버들에게 빠르게 알려줄 수 있어야 한다.


이런 역할을 하는 대표적인 솔루션으로는 ZooKeeper 많이 사용된다.


8. Infrastructure

마지막으로 이런 소프트웨어 스택을 구동하기 위한 하드웨어 인프라가 필요한데, 예전에는 일반적인 서버를 Co-Location이나 Hosting 형태로 사용하는 것이 일반적이었으나, 요즘은 가상화 기술을 기반으로 한 클라우드 (Infrastructure as a service)를 사용하는 경우가 많다.

클라우드의 특징은 "Pay-as-you-go" 로 자원을 사용한 만큼에 대해서만 비용을 지불하는 구조이다. CPU를 사용한 만큼, 디스크를 사용한 만큼, 네트워크 대역폭을 사용한 만큼만 비용을 지불한다.


Amazone WebService (AWS), Microsoft Azure, Google App Engine등이 대표적인 예인데, 이러한 클라우드의 장점은 Time To Market (시장 진입 시간)이 매우 짧다는 것이다. 앉아서 신용카드와 PC만 있다면 인터넷에 접속해서 30분내에 서버,디스크,네트워크등을 설정해서 사용할 수 있다.

단 이러한 클라우드 인프라는 Public 한 서비스 형태로 공유되서 서비스 되기 때문에 일반적인 호스팅과는 달리 성능등에 대한 한계를 가지고 있다. 예를 들어 서버와 디스크간의 네트워크 대역폭이 보장되지 않기 때문에 디스크 IO가 많은 애플리케이션 (DBMS와 같은)에 대한 성능을 보장하기가 쉽지 않고, LAN 설정이 자유롭지 않기 때문에 UDP등을 이용해서 클러스터링을 하는 제품의 경우 클러스터링을 사용할 수 없는 경우가 있다.  이런 이유로, 클라우드위에서 구현되는 시스템의 경우에는 해당 클라우드의 기술적인 특징을 제대로 이해하고 구현해야 한다.


또한 클라우드가 "Pay-as-you-go" 형태로 사용한만큼 비용을 지불한다는 것이 어떻게 보면 "싸다"라고 느껴질 수 있지만, 네트워크,IP 등등 모든 자원에 대해서 비용을 지불하기 때문에 실제적으로 계산해보면 싸지 않은 경우도 많고 기술적인 제약 때문에, 초기 시장 진입을 하는 경우에는 클라우드를 사용하는 경우아 많지만 규모가 커진 서비스의 경우에는 다시 자체 데이타 센타를 구축하는 경우가 많다. (예 소셜 게임 서비스인-Zinga, VOD 서비스인-Netflix)


운영 측면에서 인프라에 대한 관리를 클라우드 업체에 대행시킴으로써 얻는 이득도 있지만 불필요한 비용이 낭비되지 않게 클라우드 인프라에 대한 배포 구조를 끊임 없이 최적화 하는 노력도 필요하다.


IV. 결론

지금까지 현재 유행하는 대용량 고성능 시스템에 대한 레퍼런스 아키텍쳐에 대해서 설명하였다. 사실 이 글을 정리한 이유는 글을 쓰는 본인도 기술이 변화함을 느끼고 있었고, 이에 대한 공부와 개념 정리가 필요하다고 느껴서인데, 확실하게 기술 구조는 변했다. 유행하는 기술도 변했다. 대용량 시스템은 이런 구조로 구현하는게 하나의 모범 답안 (정답이 아니라는 이야기)은 될 수 있으나, 대부분의 IT 시스템은 이런 대용량 아키텍쳐 구조 없이도 WAS + RDBMS 구조만으로도 충분히 구현이 가능하다.

그럼에도 불구하고 이러한 레퍼런스 아키텍쳐에 대한 글을 쓴 이유는 레퍼런스 아키텍쳐를 이해하고, 이런 아키텍쳐가 왜 필요한지 어디에 쓰이는지를 이해한 후에 제대로 적용하기를 바라는 마음에서 정리 하였다. 이러한 대용량 기술은 유용한 기술임에는 분명하지만, 닭잡는데 소잡는 칼을 쓸 필요는 없지 않은가?


누락된 부분

※ node.js 를 이용한 Long Running Connection Service : 예-Push 등을 추가 할것.

※ Map & Reduce를 이용한 분산 처리

※ 데이타 분석을 위한 Hadoop 또는 OLAP성의 처리 아키텍쳐


P.S. 요즘 제 포스팅들이 읽이 어려운가요? 내용은 어떤지요? 피드백을 못 받아서 궁금합니다. 요즘 글들이 축약적인 내용이나 추상적인 개념들을 많이 이야기 하는 것 같아서요. 


Cassandra Node CRUD Architecture

이번 글에서는 Cassandra 클러스터를 구성하는 각 노드에서 Local Read/Write가 어떤 원리로 이루어지는 지 설명한다.
Cassanda에 대한 기반 지식은 아래 예전 포스팅을 참고하기 바란다.


Insert Record

큰 흐름의 Write 시나리오는 다음과 같다.
  1. Cluster에 Write 요청을 받으면, Insert하고자 하는 Record의 Key 값에 따라 Cassandra의 어느 Node에 데이타를 저장할 지, Hash 값을 가지고 판단하여, 데이타를 저장할 Node를 찾는다.
  2. 해당 Node에 데이타를 저장한다.
  3. 저장된 데이타를 Replication 정책에 따라 다른 Node에 복제 한다.
여기서 설명할 Write 로직은 2번의 한 Node에 데이타를 내부적으로 어떻게 저장하는 가에 대해서 설명한다.
  1. Node로 Write Request가 들어오게 되면, 먼저 Local의 Commit Log에 Write Request를 기록한다. 이는 서버가 갑자기 죽어버리는 경우 데이타 유실을 막기 위해서, Write Request 전체를 기록해놓고, 서버 장애시 다시 Restart되었을 때, 데이타 저장소에 저장되지 않은 데이타를 이 Commit Log로 부터 읽어서 복구하기 위함으로, Oracle과 같은 RDBMS나 다른 NoSQL도 비슷한 구조를 사용하고 있다.
  2. Insert가 요청된 데이타는 DISK에 바로 기록되지 않고 메모리 내의 MemTable이라는 곳에 기록이 된다. (뒤에 설명하겠지만, READ시에는 이 MemTable과 Disk 양쪽을 뒤져서 데이타를 READ한다. )
  3. MemTable이 어느정도 꽉 차면, 이 MemTable 전체를 통채로 Disk에 Write하는데, 이 과정을 Flushing이라고 한다. 이때 Disk로 Write되는 파일을 SSTable (Sorted String Table)이라고 하는데, 이 파일은 한번 저장되면 절대 삭제나 변경이 불가능하다. 
  4. MemTable을 SSTable로 쓰고 나면 CommitLog를 비워준다.
이렇게 Write는 Memtable 내용을 통째로 dump 하는 방식으로 이루어 지며, 절대 수정되지 않는다. 내부 구현상에서도 file sequential write로 구현되기 때문에 disk seek time이 없어서 매우 빠른 write 성능 실현이 가능하다. (random access를 하면 매번 위치를 찾기 위해서 disk seek 과정을 거쳐야 하기 때문에 성능 저하가 발생한다.)

Select Record


데이타를 읽는 큰 흐름은 다음과 같다.
1. 클러스터로 들어온 Read 요청의 Key값을 이용하여 Hash를 생성하고, 이 Hash 값을 기반으로 클러스터 링(Ring)내에 데이타가 저장된 Node를 찾아낸다.
2. 데이타를 해당 노드로 부터 읽어온다.
3. 복제된 다른 노드로 부터도 데이타를 읽어 온후에, 이 값을 비교하여 리턴한다. 이 부분에 대한 자세한 설명은 Cassandra Consistency와 Quorum에 대한 개념을 읽어보도록 한다.

여기서는 각 노드에서 READ가 어떻게 실행되는지 위의 2번 과정에 대해서 설명한다.

  1. 노드에서 READ 요청을 받으면 먼저 MemTable 내에 데이타가 있는지 찾아보고, 있으면 그 데이타를 리턴하고 끝낸다.
  2. 만약 MemTable에 데이타가 없다면, 디스크를 검색해야 하는데, 디스크의 SSTable이 실제 데이타가 저장되어 있는 곳이다. 
    SSTable에 저장되는 정보는 용도에 따라서 크게 3가지로 나뉘어 진다.
    1) Bloom Filter File - Bloom Filter는 통계적 로직을 이용하여, 해당 Key의 데이타가 SSTable에 저장되어 있는지 없는지만 판단하여 리턴한다. 각 SSTable의 Bloom Filter의 데이타는 메모리에 로딩이 되어 있는데, SSTable을 접근하여 Disk IO를 발생시키기전에 먼저 해당 SSTable에 데이타가 있는지 없는지를 먼저 검사하는 것이다.
    2) Index File - SSTable에 데이타가 있는 것으로 판단이 되면, Index File을 검색한다. Index 파일은 해당 Key에 해당하는 데이타가 Data File의 어느 위치에 있는 지에 대한 포인팅 정보를 가지고 있다. 이 Index File에서 Data File상의 레코드의 위치(Offset 정보)를 얻는다.
    3) Data File - 실제로 데이타가 저장되는 파일로 Index File에 의해서 얻은 Offset 정보를 가지고 레코드를 찾아서 리턴한다.
※ 근래 버전에는 SSTable에 Secondary Index를 지원하기 위한 Bitmap Index 파일등 기타 파일들이 추가되어 있다.

여기서는 언급하지 않았지만, 실제고 Read Operation의 성능 향상을 위해서 Index와 Data Record는 메모리에 캐슁 된다.

Record Update/Delete


앞에서 Insert & Select 구조에 대해서 알아보았다. 그렇다면 나머지 Update & Delete 는 어떤 방식으로 수행 될까?
먼저 Update의 경우에는 Delete & Insert 방식으로 내부 구현되어 있다.
Delete의 경우, 앞에서도 잠깐 언급했듯이, 한번 Write된 SSTable은 그 내용을 변경할 수 없다. (immutable) 그래서 tombstom 이라는 marking 방식을 이용하는데, 해당 record를 insert하고, tombstob 마크 (이 레코드는 삭제 되었다)라고 마킹을 한다.


위의 그림과 같이 각 레코드는 Deleted Mark와 Time Stamp를 가지고 있는데, 삭제된 레코드는 이 Delete Mark를 "True"로 표시해서 Insert하게 된다.

그러면 여기서 새로운 의문점이 생기는데, Delete란 기존의 데이타를 지우는 것이고 SSTable은 immutable (변경 불가)라고 했으니 기존의 데이타가 해당 SSTable이나 다른 SSTable에 남아 있지 않은가?

이에 대한 처리를 하기 위해서 Timestamp가 존재하는 것인데, 여러 SSTable에 걸쳐서 동일 데이타가 존재할 경우 이 Timestamp를 이용하여 최신의 데이타를 사용하게 되고, 최신의 데이타의 [Deleted Mark]가 True로 되어 있으면 데이타가 삭제 된것으로 간주한다.

Compaction
이렇게 Delete시에도 실제로 파일에서 데이타를 지우지 않고 계속 Insert만 한다면 어떻게 될까? 실제 삭제된 데이타가 계속 Disk에 남아 있기 때문에 디스크 용량이 낭비될 수 밖에 없다. 언젠가는 실제로 데이타를 지워야 하는데, Cassandra는 이를 Compaction이라는 작업을 통해서 해결한다.
SSTable내에는 유효한 데이타 뿐만 아니라 실제로 삭제된 데이타가 존재한다. 이런 공간을 없애야 하는데, 
두 개의 SSTable을 병합하면서 삭제된 레코드는 빼고 새로운 SSTable을 만든다. 새로운 SSTable에는 삭제된 레코드가 존재하지 않는다.
SSTable은 Sorting이 된 상태이기 때문에 병합 역시 매우 빠르게 이루어진다. 

결론
간략하게 각 Node의 CRUD 메커니즘에 대해서 알아보았다.
이를 소개하는 이유는 Cassandra를 사용할 때 내부 메커니즘을 이해함으로써, 어떤 형태의 데이타 설계나 API 사용이 올바른지에 대한 이해를 돕고 제대로된 Cassadra의 사용을 돕기 위함이다.
Cassandra는 기본적으로 빠른 write에 최적화가 되어 있고, delete를 tombstorm 방식을 이용하기 때문에, 이 tombstorm이 다른 노드에 복제 되기 전까지는 데이타의 불일치성이 발생한다.
또한 Key/Value 저장 방식에 최적화 되어 있기 때문에, 설사 Index를 사용한다 하더라도 Range Query나 Sorting등에는 그다지 적절하지 않으며 굉장히 빠른 Write 성능과 Commit Log 기반의 장애시 데이타 복구 능력을 보장함을 알 수 있다.

참고 자료


Introduction of Cassandra

카산드라는 구글의 BigTable 컬럼 기반의 데이타 모델과 FaceBook에서 만든 Dynamo의 분산 모델을 기반으로 하여 제작되어 Facebook에 의해 2008년에 아파치 오픈소스로 공개된 분산 데이타 베이스 입니다. 기존의 관계형 데이타 베이스와 다르게 SQL을 사용하지 않는 NoSQL의 제품중의 하나이며, 대용량의 데이타 트렌젝션에 대해서 고성능 처리가 가능한 시스템이다.(High-Scale). 노드를 추가함으로써 성능을 낮추지 않고 횡적으로 용량을 확장할 수 있다.

 얼마전에 트위터도 MySQL에서 Cassandra로 데이타베이스를 전환하였다고 한다..

자바로 작성되었음에도 불구하고, 데이타베이스라는 명칭에 걸맞게 여러 프로그래밍 언어를 지원합니다. Ruby,Perl,Python,Scala,Java,PHP,C# 

데이타간의 복잡한 관계 정의(Foreign Key)등이 필요없고, 대용량과 고성능 트렌젝션을 요구하는 SNS (Social Networking Service)에 많이 사용되고 있습니다. 성능이나 확장성과 안정성이 뛰어나지만 안타깝게도 Global Scale (여러 국가에 데이타 센터를 분리 배치하여 배포하고, 데이타 센타간 데이타를 동기화 하는 요구사항) 은 지원하지 않습니다. Global Scale이 필요하다면, MySQL기반의 geo replication Sharding이 아직까지는 가장 널리 쓰이는 아키텍쳐 같습니다

Data Model

카산드라의 데이타 모델은 다음과 같다.

전통적인 관계형 데이타 베이스와 다른 구조를 가지고 있다.먼저 데이타 모델에 대한 개념을 잡아보면

Column
컬럼은 컬럼 이름과, 값으로 이루어진 데이타 구조체이다.

{name: “emailAddress”, value:”cassandra@apache.org”}
{name:”age” , value:”20”}

Column Family

컬럼 패밀리는 컬럼들의 집합이다. 관계형 데이타 베이스의 테이블을 생각하면 되는데, 약간 그 개념이 다르다. 차이점은 나중에 설명하기로 하고, 컬럼 패밀리는 하나의 ROW를 식별하기 위한 Key를 갖는다. 하나의 Key에 여러개의 컬럼이 달려 있는 형태가 컬럼 패밀리이다.

하나의 Row를 예를 들어보면

Cassandra = { emailAddress:”casandra@apache.org” , age:”20”}

과 같은 형태이다. Cassandra가 해당 Row에 대한 Key가 되고, emailAddress age라는 이름의 두개의 컬럼을 가지고 있으며 각 컬럼의 값은 “casandra@apache.org” “20”이다.

여러개의 Row를 가지고 UserProfile이라는 이름의 컬럼 패밀리를 보면

UserProfile={
  Cassandra={ emailAddress:”casandra@apache.org” , age:”20”}
  TerryCho= { emailAddress:”terry.cho@apache.org” , gender:”male”}
  Cath= { emailAddress:”cath@apache.org” , age:”20”,gender:”female”,address:”Seoul”}
}

과 같이 표현할 수 있다. 여기서 주목할만한 점이 각 Row의 데이타 스키마가 다르다는 것이다. Cassandra Row emaillAddress age라는 컬럼을 가지고 있고, Terry.Cho emaillAddress gender라는 컬럼을 가지고 있다. 이 처럼 카산드라는 각 Row마다 다른 형태의 데이타 스키마를 가질 수 있는데, 이러한 특징은 “Schemeless”라고 한다.(키에 바인딩되는 데이타 구조는 같은 컬럼 패밀리라도 각 키별로 다를 수 있다.)

KeySpace

KeySpace는 논리적으로 ColumnFamily를 묶어주는 개념입니다. 단지 묶어만 줄뿐 데이타 구조나 관계에서는 별다른 영향을 주지 않습니다.

Super Column & Supper Column Family

앞에서 설명드렸던 컬럼에서 컬럼의 Value String이나 Integer와 같은 Primitive형 뿐만 아니라 컬럼 자체가 다시 들어갈 수 있습니다. 예를 들어 이런 구조입니다.

{name:”username” 
 value: firstname{name:”firstname”,value=”Terry”} 
 value: lastname{name:”lastname”,value=”Cho”} 
}

username이라는 컬럼 안에 firstname lastname이라는 두개의 컬럼이 들어가 있는 구조입니다.

마찬가지 형태로 Column Family 안에도 Column Family가 들어가는 Super 구조가 가능합니다.

UserList={ 
   Cath:{ 
       username:{firstname:”Cath”,lastname:”Yoon”}
       address:{city:”Seoul”,postcode:”1234”}
           }
    Terry:{ 
       username:{firstname:”Terry”,lastname:”Cho”}
       account:{bank:”hana”,accounted:”1234”} 
           }
 }

UserList라는 Column Family 안에, 각각 Cath Key username address라는 Column Family를 가지고 있고, Terry라는 Key username account라는 Column Family를 가지고 있습니다.  

Data Model for Java Developer

간단하게 카산드라의 데이타 구조에 대해서 살펴보았는데, 자바 개발자분이시라면 HashTable이 떠오를겁니다. 데이타 모델을 HashTable과 비교해서 설명해보면 다음과 같은 형태가 됩니다.코드로 이야기 하면 대략 다음과 같은 형태가 되겠지요


앞서 들었던 Column Family의 데이타 구조를 자바 코드로 표현하면 다음과 같은 구조가 됩니다.

UserProfile={
  Cassandra={ emailAddress:”casandra@apache.org” , age:”20”}
  TerryCho= { emailAddress:”terry.cho@apache.org” , gender:”male”}
  Cath= { emailAddress:”cath@apache.org” , age:”20”,gender:”female”,address:”Seoul”}
}

자바 코드

class Keyspace{
           HashTable keyspaces = new HashTable();          

           createColumnFamily(String name){
                     keyspaces.put(name,new HashTable);
           }

           putValue(String columnFamily,String key,Object value){
                     Hashtable cf = keyspaces.get(columnFamily);
                     cf.put(key,value);
           }
}

 

class TerryVO{ // Terry is a Key
           String emailAddress; // each column
           String gender;
           // setter & getter
}

 class CathVO{ // Cath is a Key

           String emailAddress;
           String age;
           String gender;
           // setter & getter 
}

KeySpace myspace;
myspace.createColumnFamily("UserProfile");
myspace.putValue("UserProfile","TerryCho",new TerryVO("terry.cho@apache.org","male");
myspace.putValue("UserProfile","Cath",new CathVO("cath@apache.org","20","female")

 자바 개발자분들이시라면 쉽게 이해하실 수 있을것 같고
구조를 분석하다보니 오라클의 데이타 그리드 솔루션은 Coherence와 데이타 구조가 매우 유사합니다. 요즘 이게 유행인가 보네요

Cassandra Test

개념을 이해했으면 실제 테스트를 한번 해보도록 하겠습니다.

먼저 아파치 카산드라 프로젝트(http://incubator.apache.org/cassandra/) 에서 카산드라를 다운 받습니다. 압축을 푼후에 bin/cassandra.bat를 실행시킵니다. (클러스터로 기동할 수 도 있으나 여기서는 단순하게 하나의 노드만 뛰어보도록 합니다.)

이제 카산드라 커맨드 라인 인터페이스(CLI)를 시키고(/bin/cassandra-cli.bat) 다음 카산드라 노드에 연결합니다. 포트는 디폴트로 9160 포트가 지정되어 있으며 /conf/storage-conf.xml에서 Listen Address Port를 변경할 수 있습니다.  

/conf/storage-conf.xml 파일에는 default Keyspace1이라는 이름으로 Keyspace가 정의되어 있습니다. Keyspace1에 지정되어 있는 Column Family(CF) 형식은 다음과 같습니다.


Standard2 CF Terry이라는 Key Gender라는 Column Male이라는 값을 넣고 다시 조회해보겠습니다.


다음번에는 Java Code를 이용하여 카산드라에 접근하는 방법에 대해서 알아보도록 하겠습니다.

참고 할만한 자료