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


Archive»


 

'클라우드 컴퓨팅 & NoSQL/Cassandra'에 해당되는 글 4

  1. 2012.07.17 Cassandra Node CRUD Architecture (2)
  2. 2010.03.12 분산데이타 베이스 Cassandra vs HBase 에 대한 짧은 의견
  3. 2010.03.10 아파치 분산 데이타 베이스 Cassandra 소개 (5)
  4. 2010.03.08 Cassandra 분산 데이타 베이스 (1)
 

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 기반의 장애시 데이타 복구 능력을 보장함을 알 수 있다.

참고 자료


저작자 표시
신고
http://www.roadtofailure.com/2009/10/29/hbase-vs-cassandra-nosql-battle/comment-page-1/

Cassandra의 센터간 데이타 복제에 대한 자료를 찾다가 발견했는데,
Cassandra 소개 페이지에 들어가보면 inter-data-center 복제가 가능하다고 명시되어 있다.
그런데 위의 링크된 문서를 보니

방식이 Coordinator가 변경된 내용을 실시간으로 복제하는 방식이다. 
문제는 전제 조건이 센터간 Fiber 망을 사용하는 low latency 환경이라야 하는것.. 이래서야 센터간의 망 구축 비용이 더 들테니까는 PASS, 거기에 아직 검증된 사례가 없다.

반면에 HBase의 경우 Golden Gate와 같은 CDC나 MySQL georeplication과 유사한 원리로 Update Log를 Replication하는 방식으로 복제 성능은 Cassandra보다는 느릴지 몰라도 훨씬 합리적인 구조를 가지고 있다.

설치는 Cassandra가 쉽지만 관리 기능이 매우 미약하고, HBase는 관리 UI까지 이미 제공한다. 거기에 HBase는 Hadoop 기반으로 Map&Reduce를 적용하기가 용이하지만, Cassandra는 데이타가 논리적으로 나누어지지 않기 때문에 Map&Reduce를 이용한 데이타 Processing등에는 용이하지 않다.

결과적으로 Local 데이타 Stroage로 간단하게 사용하려면 Cassandra가, 그게 아니라 지역간의 분산구조나 BI와 같은 데이타 Processing이 필요하다면 HBase가 적절할것 같다.

P.S. 어디까지나 개인의견임
저작자 표시
신고

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를 이용하여 카산드라에 접근하는 방법에 대해서 알아보도록 하겠습니다.

참고 할만한 자료

저작자 표시
신고

오늘 Facebook에 이어서 Twitter도 MySQL에서 Cassandra 데이타베이스를 사용한다는 기사를 봤습니다.


아마 오라클의 MySQL 인수와 관련이 있지 않는가 하는 생각도 듭니다.
예전 천리안,하이텔 PC통신 시절에는 RDBMS가 대용량의 게시물 처리에 맞는 성능을 내지 못해서 ISAM과 같은 파일 시스템 기반의 데이타 저장 구조를 가졌던 것을 기억합니다.

Facebook이나 Twitter도 상당히 많은 양의 트렌젝션을 가지고 있는 SNS 사이트중 하나입니다. (거의 대표급이라고 봐야져..) SNS는 복잡한 RDBMS 연산이 필요 없습니다. 오라클과 같은 관계형 데이타베이스의 복잡한 JOIN이나 Procedure등이 필요없습니다.
더군다나 요즘은 REST 아키텍쳐를 많이 쓰는 까닥에, 테이블간 Relation ship을 정의하지 않는 경우도 많기 때문에, RDBMS를 꼭 사용해야 하나? 하는 생각도 듭니다.
Hadoop 기반의 HBase나 Google의 Big Table등이 해외에서 인기있는 이유도 여기에 있지 않나 싶습니다.
요즘 전반적으로 Vendor를 필두로한 엔터프라이즈 진영보다, 서비스 진영의 기술들이 더 앞서가는 느낌이 듭니ㅏㄷ.
저작자 표시
신고