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


Archive»


 
 

첫 해외 잡지 기고

IT 이야기 | 2013.01.20 23:13 | Posted by 조대협

첫 해외 잡지 기고.. 
(http://sdjournal.org/) 에 Cassandra에 대한 아티클을 기고하였습니다.
2010년에.. 영어 공부겸 해서, 영문 블로그에 짧게 Cassandra에 대해서 소개한 글을 올렸는데, 운좋게도 기고 요청이 와서, 올렸습니다. (원문)
http://javamaster.wordpress.com/2010/03/22/apache-cassandra-quick-tour/



NoSQL 인기 순위

클라우드 컴퓨팅 & NoSQL/NoSQL 일반 | 2012.09.07 22:30 | Posted by 조대협

미국의 NoSQL 인기 순위를 분석해보니, mongodb가 앞도적인 1위, 2위권은 cassandra,hbase 그리고 다음이 redis 맨 아래로 riak,couchdb 등이 있다.

아무래도 기능이 편리한 mongodb 가 단연 인기고, 난이도는 있지만 확장성에 우위가 있는 cassandra,hbase가 그 뒤를 따른다. 


분석 방법은 indeed.com 이나 monster.com의 구인 광고중, 해당 기술별 구인 광고를 분석하였다.


<indeed.com 분석 결과>


  • mongodb 276
  • cassandra 149
  • hbase 146
  • redis 91
  • coherence 53
  • couchdb 40
  • riak 24

<monster.com 구직 분포>

NoSQL 데이타 모델링 #1

Facebook Server Side Architecture Group
http://www.facebook.com/groups/serverside
조대협

빅데이타,클라우드,NoSQL은 요즘 기술적인 화두중에 하나이다. 그중에서도 NoSQL은 많은 사람이 관심을 갖고 있음에도 불구하고, 기존의 RDBMS 데이타 모델링 관점에서 접근을 하기 때문에, 많은 문제를 유발한다. NoSQL은 데이타 베이스이기도 하지만 RDBMS와는 전혀 다른 성격을 가지고 있고, 접근 방식도 틀리다.

특히 테이블 구조를 정의 하는 데이타 모델에 따라서 NoSQL의 성능은 하늘과 땅차이만큼 차이가 난다. 이 글에서는 NoSQL의 데이타 모델링 기법에 대해서 소개하고자 한다.
※ 깨지는 그림은 클릭해서 봐주세요.

NoSQL 데이타 모델

데이타 모델링에 앞서서 NoSQL이 어떤 구조로 데이타를 저장하는지를 먼저 이해할 필요가 있다. NoSQL의 데이타 모델링 패턴은 아래와 같이 크게 3가지 패턴정도로 구분된다.

1.     Key/Value Store

가장 기본적인 패턴으로, 대부분의 NoSQL은 다른 데이타 모델을 지원하더라도, 기본적으로 Key/Value의 개념을 지원한다. Key/Value Store, Unique Key에 하나의 Value를 가지고 있는 형태를 이야기 한다. Put(Key,Value), Value := get(Key) 형태의 API로 접근한다.


Value String이나 Integer와 같은 Primitive 타입이 될 수 도 있지만, 이정도로는 우리가 일반적으로 사용하는 테이블 형태의 데이타를 저장할 수 없기 때문에, 조금 더 확장된 개념을 사용하는데, Column Family라는 개념을 사용한다. Key 안에 (Column,Value) 조합으로 된 여러개의 필드를 갖는데, 이를 Column Family라고 한다.


예를 들어, 사용자 프로필을 저장하는 시나리오가 있을 때, 사용자의 이름을 KEY로 한다면, 성별,주소,나이들은 각각의 Column이 될 수 있다. Key 필드는 RDBMS에서 Primary Key, Column 필드들은 RDBMS의 일반 데이타 필드로 이해하면 된다. 프로그램 언어와 비교해서 생각한다면, Key/Value Store Map 데이타 구조와 유사하다.
Oracle Coherence
Redis와 같은 NoSQL이 이 데이타 모델을 기본 모델로 사용한다.

2.     Ordered Key/Value Store

Key/Value Store의 확장된 형태로 Key/Value Store와 데이타 저장 방식은 동일하나, 데이타가 내부적으로 Key를 순서로 Sorting되서 저장된다.



Sorting이 별거 아닌것 같지만, NoSQL 관점에서는 대단히 중요한 기능을 제공하게 된다. 뒤에 데이타 모델링 기법에서도 다루겠지만, NoSQL RDBMS Order By와 같은 기능을 제공하지 않기 때문에 결과값을 업데이트 날짜등으로 소팅해서 보여주는 것은 이 Ordered Key/Value Store가 절대적으로 유리하다.

대표적인 제품으로는 Apache Hbase, Cassandra 등이 있다.

3.     Document Key/Value Store

Key/Value Store의 확장된 형태로, 기본적으로는  Key/Value Store이다. Key에 해당하는 Value 필드에 데이타를 저장하는 구조는 같으나, 저장되는 Value의 데이타 타입이 Document 라는 타입을 사용하는데, Document 타입은 MS-WORD와 같은 문서를 이야기 하는것이 아니라, XML,JSON,YAML과 같이 구조화된 데이타 타입으로, 복잡한 계층 구조를 표현할 수 있다.



아울러, Document Store 기반의 NoSQL은 제품에 따라 다르기는 하지만 대부분 추가적인 기능 (Sorting,Join,Grouping)등의 기능을 제공한다.

대표적인 제품으로는 MongoDB,CouchDB,Riak 등이 있다.


그리고 여기서는 구체적으로 다루지 않지만 Graph Tree구조와 같은 데이타 구조를 저장하기 위해서 최적화된 Neo4J등의 NoSQL이 있다. 만약에 테이블 구조의 데이타가 아니라 Graph 구조의 데이타를 저장하고자 한다면 Neo4J를 한번 체크해보기 바란다.


RDBMS NoSQL의 차이

NoSQL DBMS라고 생각해서 RDBMS와 같은, 또는 떨어지지만 유사한 기능을 제공할것이라고 생각하면 큰 오산이다. NoSQL은 데이타를 저장한다. 그리고 Key에 대한 Put/Get만 지원한다. RDBMS로 치자면

Put : Insert into TABLE VALUES(KEY,value1,value2,…,valuen)

Get : Select * from TABLE where KEY=”key”

만 딱 지원한다. 물론 제품에 따라서 기능에 대한 지원 범위는 다르기는 하지만, 공통적으로 고민해야 하는 기능은

Ÿ   Sorting (SQL Order By)

Ÿ   Join (RDBMS에서 두개의 Table Foreign Key를 이용하여 join)

Ÿ   Grouping (SQL문의 group by)

Ÿ   Range Query (where key>”start” and key<”end” 와 같이 일정 범위내의 내용을 쿼리해오는 기능)

Ÿ   Index (RDBMS Index를 지정하여 select query 성능을 높이는 기능)

이다. RDBMS에서는 너무나도 익숙하게 사용했던 기능들이기 때문에, 막상 이 기능들을 빼고 데이타를 다루고자 하면 매우불편하다. 여기서는 이러한 기능들을 “NoSQL 데이타 모델링 패턴소개를 통해서 NoSQL에서 어떻게 구현할 수 있는지 알아볼 것 이다.

NoSQL 데이타 모델링 시작하기

NoSQL 데이타 모델링이란, NoSQL에 저장할 데이타들의 구조, 즉 테이블 설계를 하는 것을 정의한다. NoSQL DBMS이기는 하지만, 우리가 지금까지 익숙하게 사용해왔던, RDBMS와는 그 특성이 매우 다르기 때문에 접근 방법을 바꿔야 한다.

NoSQL RDBMS의 데이타 모델링 차이

NoSQL을 사용해서 데이타 모델링을 하려면 근본적인 사상 2가지를 바꿔야 한다.

1)     개체 모델 지향에서 쿼리 결과 지향 모델링

RDBMS의 모델링 기법은, 저장하고자하는 도메인 모델을 먼저 분석한 후에, 개체간의 관계(relationship)를 식별하고, 테이블을 추출해내고, 테이블을 이용하여 쿼리를 구현하여 결과를 뽑아내는 방식이다.

NoSQL의 경우에는 이 접근 방법을 역순으로 진행해야 한다.

RDBMS가 도메인 모델 à [테이블 à 쿼리] 순서로 진행을 했다면, NoSQL은 도메인 모델 à [쿼리 결과 à 테이블] 순서로 테이블을 디자인해야 한다. RDBMS의 경우 여러가지 최적화된 기능으로 테이블을 가지고 자유롭게 쿼리 결과를 뽑아낼 수 있지만, NoSQL의 경우 복잡한 쿼리 기능이 없기 때문에, 반대로 도메인 모델에서 어떤 쿼리 결과가 필요한지를 정의한후에, 이 쿼리 결과를 얻기 위한 데이타 저장 모델을 역순으로 디자인해야 한다.

2)     정규화(Normalization)에서 비정규화(Denormalization)

RDBMS 모델링에서는 데이타의 일관성과 도메인 모델과의 일치성을 위해서 데이타 모델을 정규화한다. 그중에서도 같은 데이타가 두개 이상의 테이블에 중복되게 저장하는 것을 제거 하는데, NoSQL은 반대의 접근 방법이 필요하다. 쿼리의 효율성을 위해서 데이타를 정규화하지 않고, 의도적으로 중복된 데이타를 저장하는 등의 비정규화된 데이타 모델 설계 방식으로 접근해야 한다.

NoSQL 데이타 모델링 절차

그러면, RDBMS NoSQL의 두가지 결정적인 차이를 인식하고, NoSQL 기반의 데이타 모델링 절차를 살펴보자.

1.     도메인 모델 파악

먼저 저장하고자하는 도메인을 파악한다. 어떤 데이타 개체가 있는지 개체간의 관계는 어떻게 되는지등을 분석하고 ERD를 그려서 도식화 한다. RDBMS의 모델링 접근 방법이고, NoSQL에서는 이렇게 하지 않고 바로 애플리케이션 관점으로 접근하는 경우도 많은데, 도메인 모델 분석 없이 필자의 경우에는 이런 방식에는 반대이다. NoSQL도 데이타베이스이고 저장할 데이타에 대한 명확한 이해 없이는 제대로된 데이타 모델이 나올 수 없다.

다음은 간단한 블로그 시스템의 데이타 도메인 모델이다. 이 블로그 시스템은

Ÿ   사용자 ID 기반으로 블로그의 분류(Category)를 가지고 있고,

Ÿ   분류별로 글을 작성할 수 있으며,

Ÿ   글에 파일을 첨부할 수 있고,

Ÿ   댓글을 달 수 있는 블로그이다.

Ÿ   이번 예제에서는 검색이나 페이징 기능은 제외한다. (단순화 하기 위해서)



2.     쿼리 결과 디자인 (데이타 출력형태 디자인)

다음으로 가장 중요한 과정인 쿼리 결과 디자인이다. “도메인 모델을 기반으로 애플리케이션에 의해서 쿼리 되는 결과값을 먼저 정해야 한다.

앞서 예를 든 블로깅 시스템을 다시 살펴보자



     화면 좌측 상단에는 블로그 사용자의 포스팅 분류명들을 목록 식으로 출력한다.

     포스팅 출력 화면에는 상단에, 포스팅의 분류명과 제목을 출력하고 다음에는 포스팅 날짜, 본문 내용을 출력한다.

     다음에는 첨부파일들을 출력하는데, 첨부파일 업로드 날짜와 파일명을 차례대로 출력하고, 파일에 대한 링크를 출력한다.

     마지막으로 댓글을 출력하는데, 댓글에는 작성일과, 작성자 이름과 댓글 내용을 출력하고, 작성자 이름에는 이메일을 링크한다.

이 출력 형식을 기반으로, 어떤 쿼리가 필요한지를 정의해보자

     전체 분류 출력

select categoryID,name from Category where userID=”사용자ID”

     포스팅의 분류,제목,날짜,본문 출력

select po.postID,po.Contents,po.date,ca.name
from Category ca,Post po
where userID=”
사용자ID”
order by date desc

     첨부 파일 출력

select fileID,filename,date,fileLocation
from Attachment
where userID=”
사용자ID” and postID=”현재 포스팅 ID”
order by date desc

     댓글 출력
select userID,email,Contents,date
from Comment
where userID=”
사용자ID” and postID=”현재 포스팅 ID”
order by date desc

대략적으로 4개의 쿼리가 필요하다. (물론 RDBMS 실제 구현에서는 좀더 최적화 할 수 있겠지만, 이해를 돕기 위해서 단순 구현하였다.) 그러면, 어떤 형태의 데이타 테이블들이 출력되는가?



위와 같이 애플리케이션의 출력형태에 따른 데이타를 정리할 수 있다. 사실 이것이 가장 중요하다. 앞에서도 설명했듯이, NoSQL의 데이타 모델링은 도메인 모델을 중심으로 하는 것이 아니라, 이 애플리케이션의 데이타 출력 내용을 기반으로 하기 때문이다.

3.     패턴을 이용한 데이타 모델링

애플리케이션 데이타 출력 내용을 디자인 했으면, 이제 이 내용을 가지고 NoSQL에 정의될 데이타 모델링을 들어간다. NoSQL Sorting,Grouping,Join 등의 RDBMS 기능을 제공하지 않기 때문에 이를 배제하고 Put/Get으로만 데이타를 가지고 올 수 있는 형태로 데이타 모델 즉 NoSQL내의 테이블을 재 정의 해야 한다.

이 데이타 모델링을 돕기위해서 다음 챕터에서는 NoSQL 데이타 모델링 기법을 다시 설명한다. 이 때 가장 중요한것은 Demoralization이다. 데이타를 가급적 중복으로 저장하여, 한번에 데이타를 읽어오는 횟수를 줄이도록 한다. ( IO자체가 엄청난 부담이기 때문에)

위의 블로깅 시스템 데이타를 일반적인 NoSQL 스타일로 바꾸면 다음과 같다.



특히 Key 부분을 주목해 볼 필요가 있는데, Join을 없애기 위해서, 아예 userID postID“:”로 구분되는 deliminator로 하여 Key에 포함시켜 버렸다. 이는 Join을 없애는 것 이외에 다른 이유가 또 있는데, Ordered Key/Value Store의 경우에는 Key를 기반으로 소팅을 하기 때문에 첫번째, 포스트 ID Sequential하게 증가 시켜 나가면, 같은 사용자의 글의 경우에는 Sorting 이 가능하다. 두번째, Grouping인데, 포스팅을 출력하는 사용자에 대해서 posting을 쭈욱 출력해 나가면, 순차적으로 Post가 출력이 되다가, 해당 사용자의 포스팅 데이타가 끝이나면, Key의 맨앞 userID가 다른 사용자id로 바뀌기 때문에 where문장이 없이도, 특정 사용자의 포스팅을 순차적으로 출력할 수 있다. 뒤에서 설명한 데이타 모델링 패턴에서 Enumerable Key Composite Key Index 패턴을 참고하기 바란다.


4.     최적화를 위한 필요한 기능들을 리스팅

자아 이제 약간은 NoSQL스럽게 디자인이 되었다. 이제는 NoSQL의 특성을 반영하여, 조금 더 디테일한 디자인을 할 수 있다. 다시 애플리케이션 및 데이타의 특성을 다시 한번 들여다 보자

첨부 파일 (Attachment) 파일의 경우에는 포스팅이 작성되었을 때 레코드가 추가되며, 변경이 거의 없다. 그리고 첨부파일의 수는 그리 많지 않기 때문에, 하나의 필드에 모두 몰아서 저장할 수 있다. 이렇게 하나의 필드에 여러개의 데이타를 저장할 경우에는 Document Store를 고려해 볼 수 있다.

그리고 앞에서도 언급했지만 블로그 포스트,첨부파일,댓글은 소팅이 되어야 하기 때문에, Ordered Key 형태가 필요하다.

현재 데이타 모델은 포스팅이 포스트된 순서대로만 출력하는 형태인데, 분류 개념이 있기 때문에, 분류에 따라서 포스팅을 출력하려면 분류 필드가 별도 필드로 들어가야 하고, 이 필드에 따라 where문으로 select할 수 있는 기능이 있어야 한다. 마치 RDBMS Index같은 개념이 필요한데, 이러한 기능을 NoSQL에서는 Secondary Index라고 한다.



이런 옵션등을 적용해보면 Posting 테이블은 위와 같이 변경해볼 수 있다.

여기서 고려해야 할점 하나를 짚고 넘어가자..!!

NoSQL 제품들은 KV, Ordered KV, Document Store등 데이타 모델로는 3가지 분류로 분리가 되긴 하지만, 세세한 내부 아키텍쳐나 기능들은 매우 다르다아주 자세하게는 아니더라도, 어떤 NoSQL 제품군이 있고, 대략적인 기능이 어떻게 되는지를 알아야, 이 정도 수준의 설계를 할 수 있다. 물론 이 단계까지 설계되더라도 아직까지 완벽하지 않다.

솔루션들이 스펙상에 “OOO 기능이 있다.” 하더라도, 그 기능이 제대로 돌아가는 건 아니다. Secondary Index의 경우 Cassandra Riak에서 지원은 하지만 실제 부하를 줘 가면서 테스트를 해보면 성능이 잘 안나오는 경우가 많고, 내부 구조상으로도 고성능을 내기가 어려운 구조이다. 그래서 이런 부가 기능들은 직접 내부 구조를 분석하고, 테스트를 해봐야 사용 가능 여부를 판단할 수 있다.

예전의 RDBMS, 워낙 레퍼런스도 많고, 벤더 지원도 있기 때문에, 써야할, 쓰지 말아야할 기능이 명확하지만 NoSQL의 경우는 제품도 많을 뿐더라, 기술도 신기술이기 때문에 서적조차 드물다. 직접 분석하고 테스트해보는 방법 밖에 없다.


5.     후보 NoSQL을 선정 및 테스트

앞에서 언급한 바와 같이, 모델링한 데이타 구조를 효과적으로 실행할 수 있는 NoSQL을 찾아야 한다. 이는, NoSQL에 대한 구조 및 특성 분석 후에, 실제로 부하 테스트, 안정성, 확장성 테스트를 거친 후에, 가장 적절한 솔루션을 선택해야 한다.

경우에 따라서는 하나의 NoSQL이 아니라, 여러개의 NoSQL을 복합해서 사용할 경우도 있다. 트위터나,페이스북같은 대규모 서비스들은 하나의 NoSQL만을 사용하지 않고 데이타의 성격과 업무의 목적에 맞는 다수의 NoSQL을 선정하여 사용한다.


6.     데이타 모델을 선정된 NoSQL에 최적화 및 하드웨어 디자인

마지막으로 선정된 NoSQL을 기반으로 다시 데이타 모델을 최적화 하고, 이에 맞는 애플리케이션 인터페이스 설계와 하드웨어에 대한 디자인을 진행해야 한다.


지금까지 간단하게나마 NoSQL의 데이타 모델링 절차에 대해서 알아보았다. 다시 한번 강조하지만 NoSQL의 데이타 모델링 방식은 RDBMS가 데이타 자체의 관계를 중요시 하고, 데이타에서부터 출발한다면, NoSQL은 애플리케이션이 출력하고자 하는 데이타 출력 내용에 따라서 데이터 모델링이 완성된다. RDBMS와 역순으로 진행되어야 하고, 데이타 중심이 아니라, 애플리케이션 중심으로 모델링을 진행해야 한다.

그리고 NoSQL은 신 기술 분야이면서 오픈 소스 진영이 주를 이르고 있기 때문에, 기술 지원을 받기가 매우 어렵다. 물론 외국에는 NoSQL에 대해서 유상으로 기술 지원을 해주는 업체들이 있기는 한데, (Cassandra의 경우 DataStax가 기술 지원을 하고, Riak Basho, MongoDB 10gen 등이 기술 지원을 한다.). 국내 실정상 외국엔지니어를 불러다가 기술 지원을 받기도 힘들뿐더러, 기술 지원 회사의 규모가 작기 때문에 숙력된 엔지니어를 필요할때 마다 부르기도 어렵다.

그리고, Amazon등에서 검색해보면 알겠지만, NoSQL에 대한 서적도 그리 많지 않은 편이기 때문에 공부하기도 어렵다. 해외에서 이러한 NoSQL류를 쓰는 업체들은 스스로 내부 개발자들을 역량을 키워서 공부하고, 테스트해서 내재화된 기술을 기반으로 NoSQL을 운용하기 때문에, 단순하게 솔루션 도입 관점에서만 볼 것이 아니라, 기술 내재화 관점에서도 NoSQL 도입을 고려해야 한다.


다음글에서는 NoSQL의 데이타 모델링을 하기 위한 일반적은 데이타 모델링 패턴에 대해서 소개하기로 한다.

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


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

참고 자료



이 구성은 Cassandra나 Riak과 같은 Dynamo 계열에 공통 적용 가능하다. 다른 것들도 마찬 가지일테지만.

1. RAID 5 사용 : NoSQL 클러스터는 Quorum 사용을 통해서 노드에 (서버) 대한 FAIL을 방지 하지만 디스크 장애 자체에 대해서는 보장이 불가능하다. 고로 비용 대비 적정한 RAID 5 사용이 권장
2. IO Scheduler : NOOP 사용. NOOP은 IO Scheduling을 다른 계층이 한다는 것을 전제 한다. 즉 중간에 RAID 구성이나 iSCSI 를 사용하는 경우를 전제한다. 테스트용이나 개발용으로 사용하면서 RAID 구성등을 하지 않는다면, NOOP을 사용할 필요가 없다.
3. ext4 또는 XFS 파일 시스템 사용 : ext3는 1 volume의 max 사이즈가 2 TB를 넘지 못한다. ext4의 경우 16TB, XFS는 무제한(64bit 경우)
4. Log File과 Data File 디렉토리 분리 : Cassandra는 Transaction Log와 Data Log 파일이 분리되어 있다.물리디스크도 분리해서 Disk IO를 최적화 해야 한다.
 

=== 2012.04.12 첨언 ===

RAID 구성은 많은 수의 노드를 가지는 경우, 디스크 FAIL을 노드 FAIL로 간주하고, 전체 클러스터의 성능을 높이기 위해서 RAID5를 사용하지 않고 Stripping으로 구성하는 것이 경제성이나 (RAID 5 parity 디스크 사용 안함), 성능 (Stripping이기 때문에, 전체 IO 성능 향상) 관점에서 유리하다.


짧으나마 NoSQL 경험해보고 배운 내용을 정리해보면

1. RDB는 Entity를 정의하고 데이타 모델링을 정의한 후에, 쿼리와 APP을 개발한다. 반대로 NoSQL은 App을 먼저 디자인하고, 필요한 쿼리 결과를 먼저 정의 한후에, 그에 맞춰서 데이타 모델링을 해야 한다.

2. 절대 Normalization은 하지 말고, DeNormalization을 할것. 데이타 중복을 허용하여 성능을 높이고, 데이타안에 데이타를 넣는 (Composition) 모델등을 사용하여 Query 수를 줄여야 한다.

3. 내 애플리케이션의 서비스 특성과 이에 맞는 NoSQL을 선택한다. BigTable 계열, Cassandra 계열, Document DB 계열등 많은 계열의 NoSQL이 있고, 그 특성도 매우 다르다 (언뜻 보면 다 같아 보이지만). 서비스를 이해하고, 사용하고자 하는 NoSQL을 완전히 이해한 다음에 시작해야 실수를 막을 수 있다.

4. NoSQL 쿼리가 실제 몇개의 물리 노드에 걸쳐서 수행되는지에 대한 이해가 있어야 제대로된 쿼리 디자인이 가능하다.

5. NoSQL 디자인은 DB 와 APP 뿐만 아니라 인프라 (네트워크,디스크)에 대한 디자인을 함께 해야 한다.

6. 대부분의 NoSQL DB는 인증이나 인가 체계가 없어서 보안에 매우 취약하기 때문에 별도의 보안 체계를 마련해야 한다. (방화벽이나 Reverse Proxy 등)
MongoDB 깜빡 잊고 있었다. Read / Write 성능이 빠를 수 밖에 없다는 걸..
Mongo는 Write시에, Memory에 먼저 Write후에, 1분 단위로 Flushing하는 Write Back 방식을 쓴다. 즉 메모리에만 쓰면 되니까는 Write가 무지 빠르다. 반대로 Read시에는 파일의 Index를 메모리에 로딩해놓고 찾는다(memory mapped file). 이러니 성능이 좋을 수 밖에, 단 Flushing전에 Fail이 되면 데이타 유실에 의해서 Consistency 가 깨지는 문제가 발생하고, Configuration 구조상 메모리 사용량이 많으며, 확장성에 제약이 있다.
특히 Write 구조에서는 비동기 식으로 Write를 하기 때문에 Disk 성능에 덜 Sensitive하다. 즉 이 말은 DiskIO성능이 상대적으로 낮은 클라우드에서 더 잘돌아간다는 이야기.

이에 비해서 Cassandra(같은 Dynamo 계열인 Riak도 마찬가지) 는 Write Back이나 Memory Mapped file을 사용하지 않기 때문에 MongoDB에 비해서 성능이 낮을 수 밖에 없다. 더군다나, Write나 Read시 1개 이상의 Node에서 값을 읽거나(R Value) 쓰기 때문에(W Value) Consistency가 mongoDB에 비해서 나으며, 당연히 확장성도 더 높다.

즉 확장성+일관성 vs 성능간의 Trade Off 구조다.
 
한국 내 정도 서비스 할 수준이라면 걍 mongo가 났겠네.. 대규모 서비스라면 Cassandra 고민해봐야 할듯 하고.

분산 환경 기반의  NoSQL은 예전 포스팅에서도 설명했듯이 크게 Google의 BigTable 논문을 기반으로한 시스템과, Amazon의 Dynamo를 기반으로 한 시스템 두가지로 나뉘어 진다.
Dynamo 계열의 NoSQL의 장단점을 간단히 정리해보면

Dynamo 계열 NoSQL의 개요

1. Ring과 Consistent Hasing
먼저 Dynamo 계열 (Cassandra, Riak) 의 NoSQL의 특징은 Ring 토폴로지를 기본으로 하고 있다. Ring 구성이란, 전체 데이타를 1~N (2^160과 같이 큰 범위로) 이라는 특정 레인지로 정의한후 전체 데이타 저장 구조를 Ring 형으로 정의한 후에, 이 Ring을 피자 조각을 나누듯이 여러 Slice로 나눈다. 이를 Partition이라고 하는데, 각 Partition은 데이타를 저장하는 구간 정보를 가지고 있다. 예를 들어 전체 Ring이 1000개의 데이타를 저장한다고 하고, 각 Partition의 수를 10개로 지정하면 첫번째 파티션은 0~999, 두번째는 1000~1999 까지의 키를 가지는 데이타를 저장한다. 이르 통해서 저장하고자 하는 데이타의 키를 알면 어느 파티션에 저장할 수 있는지 쉽게 찾아갈 수 있기 때문에, 각 Partition을 저장하는 하드웨어(Node)에 부하를 분산 시킬 수 있는 구조를 갖는다. 이런 방식을 Ring 기반의 Consistent Hashing이라고 이야기 한다.

2. N-Value & Quorum
이 경우 특정 파티션을 저장하고 있는 Node가 장애가 났을때, 특성 파티션의 데이타 유실이 발생할 수 있는데, 이를 방지하기 위해서 Node간의 데이타 복제를 수행한다. 몇 개의 복제본을 갖느냐를 정해야 하는데, 이 복제본의 수를 보통 "N-Value" 또는 "Quorum" 이라고 정의하며, 이 Quorum의 수는 일반적으로 3개 정도로 지정한다.
이 N-Value를 3으로 지정하는 이유는 여러가지가 있겠지만, 장애 대응면에서 최소한 하나의 복제본을 가져야하기 때문에 2개의 복제본이 필요하고, 예측된 작업(패치,서버 교체)시에도 장애를 대응하기 위해서 최소한 두개의 복제본을 유지해야 하기 때문에 일반적으로 3개의 복제본을 생성한다. (이 N-Value는 NoSQL 설정에서 조정할 수 있다.)

3. R-Value, W-Value
앞에 설명한 것 처럼, N-Value의 복제본을 가지게 되는데, Dynamo Architecture는 R-Value와 W-Value라는 특성을 유지 한다. 이 값은 "성능과, 데이타 정합성간의 Trade-Off"를 위한 값인데, 데이타 복제는 실시간으로 이루어지지 않는다. 약간의 Delay가 발생한다 (수 밀리세컨드, 데이타 센터간에는 조금더 길 수 있다.)
N-Value를 3이라고 가정하자. 첫번째 Node에 Write를 한후에,  두번째 Node와 세번째 Node에 데이타가 복제 되어야 한다. 이 복제과정에서 데이타를 읽을때, 이 3 노드 중에서 데이타를 몇개의 노드에서 데이타를 읽어올지를 결정하는 것이 R-Value이며. 동시에 몇개의 Node에 Write할것인가를 결정하는 것이 W Value이다.
만약에 W-Value가 2이면 Write시에 동시에 두개의 Node에 Write한다. R-Value가 1보다 클 경우 R-Value 노드 에서 데이타를 읽어오고, 두 개의 데이타가 다를 경우 최근 데이타를 사용한다.

이런 이유로 R-Value + W-Value > N-Value이면 Data Consistency가 보장된다.
예를 들어 N=3일때, R=2,W=2이면, Write시 적어도 두개의 복제본에 썼기 때문에, 하나가 복제가 안되어 있다하더라도, R-Value가 2이기 때문에, 꼭 하나는 새로운 데이타가 읽어지게 되고, 새로운 데이타를 Winning하는 정책 때문에 항상 최신의 데이타를 읽을 수 있다. (여기서 새로운 데이타를 판단 가능하게 하는 방법을 Vector-Clock이라고 한다. 이는 나중에 따로 포스팅 예정)

참고 : http://wiki.apache.org/cassandra/ArchitectureOverview 

Consistency

See also the API documentation.

Consistency describes how and whether a system is left in a consistent state after an operation. In distributed data systems like Cassandra, this usually means that once a writer has written, all readers will see that write.

On the contrary to the strong consistency used in most relational databases (ACID for Atomicity Consistency Isolation Durability) Cassandra is at the other end of the spectrum (BASE for Basically Available Soft-state Eventual consistency). Cassandra weak consistency comes in the form of eventual consistency which means the database eventually reaches a consistent state. As the data is replicated, the latest version of something is sitting on some node in the cluster, but older versions are still out there on other nodes, but eventually all nodes will see the latest version.

More specifically: R=read replica count W=write replica count N=replication factor Q=QUORUM (Q = N / 2 + 1)

  • If W + R > N, you will have consistency

  • W=1, R=N
  • W=N, R=1
  • W=Q, R=Q where Q = N / 2 + 1

Cassandra provides consistency when R + W > N (read replica count + write replica count > replication factor).

You get consistency if R + W > N, where R is the number of records to read, W is the number of records to write, and N is the replication factor. A ConsistencyLevel of ONE means R or W is 1. A ConsistencyLevel of QUORUM means R or W is ceiling((N+1)/2). A ConsistencyLevel of ALL means R or W is N. So if you want to write with a ConsistencyLevel of ONE and then get the same data when you read, you need to read with ConsistencyLevel ALL.



4. Masterless Architecture
또다른 특징 중에 하나는 Masterless 아키텍쳐이다. Ring을 구성하고 있는 아무 Node에나 요청을 보내도 처리가 되고, 전체 설정 정보를 가지고 있는 마스터 노드나 Admin 노드가 없다.
10개의 노드를 가지고 있는 Ring의 아무 Node에나 Request를 하더라도, 각 Node는 해당 데이타가 다른 어느 Node에 저장되어야 하는지를 Consistent Hash를 통해서 알 수 가 있고, 해당 노드로 Request를 Routing한다. 이때 자기가 데이타를 가지고 있지 않더라도 첫번째 요청을 받은 Node가 데이타를 처리하는 이 노드를 Coordinator Node라고 정의한다.

지금까지 대략적인 Dynamo 아키텍쳐의 특성에 대해서 알아보았다. 그러면 어떤 장단점이 있을까?

장점
1. High Availibility & Partition Tolerence
위와 같은 특성 때문에, 분산 시스템의 CAP 이론에서 A와 P에 최적화 되어 있다. 특정 노드가 장애가 나더라도 서비스가 가능하며 (A-Availibility) Node간의 네트워크 통신이 끊어지더라도 서비스가 가능하다 (P-Partition Tolerance : Vector Clock을 이용하여 데이타의 정합성을 처리가 가능하고 각 노드가 독립적으로 서비스가 가능

2. No Sigle Failure Point. No Master Node
그리고 Masterless 아키텍쳐로 인해서 Single Failure Point (SFP)가 없다. 이는 대규모 분산 환경에서 아주 큰 장점 중의 하나인데, 무제한 확정된 클러스터라도, 특정 노드 장애에 대해 종속이 되어 버리면 시스템의 안정성에 많은 영향을 미친다.

단점
반대로 단점은
1. Cannot Change Ring Size
일반적인 Dynamo 기반의 아키텍쳐는 Ring Size (Partition 수)를 변경할 수 없다. 데이타가 이미 Partition 별로 분산 저장되어 있기 때문에 파티션의 개수를 변경하면 다시 데이타를 변경된 파티션 수 에 따라 재 분배해야 한다. 이는 데이타의 이동을 초래하고, 많은 IO 부하를 유발하기 때문에 운영환경에서는 거의 불가능하다고 봐야 한다.

2. Data InConsistency
앞에서 설명한 바와 같이 데이타 복제가 실시간이 아니기 때문에 데이타에 대한 불일치가 발생한다. 물론 R,W Value를 조정해서 Consistency를 보장받는 방안은 있지만, 이 값을 높일 경우 동시에 여러 노드에 Read 또는 Write를 해야 하기 때문에 성능저하가 발생할 수 있고, 또한 Node간에 네트워크가 단절되는 Partitioning이 발생했을 때도 서비스는 되기 때문에, 다시 장애가 극복되었을때는 당연히 Data InConsistency가 발생하게 된다.

3. Sibling (Data Conflict 발생)
특히 네트워크 Partitioning이 발생하거나 또는 동시에 두개의 Client가 Write를 했을때, Vector-Clock 값이 똑같아서 어느 데이타가 더 최근 데이타인지 판단할 수 없는 Data Conflict (Sibling현상)이 발생한다. (Sibling의 자세한 개념은 나중에 Vector Clock 설명에 같이 추가)

NoSQL 계보 정리

클라우드 컴퓨팅 & NoSQL/NoSQL 일반 | 2011.11.14 17:45 | Posted by 조대협

Google의 BigTable에서 시작된 것들
- HBase (Java)
- HyperTable (C++)
주로 대규모 분산처리 특히 Map&Reduce에 알맞고, 동시 대규모 클라이언트를 지원하는데 뛰어 나다

Amazon Dynamo 로 부터 시작된 것들
- Voldemork
- Riak

FaceBook에서 시작된것
- Cassandra
Write에 Optimize되었으며, Read는 Write에 비해 느림. 대규모 데이타 저장에 최적화됨

그밖에 Mongo 계열
-MongoDB 쉽다. 그리고 AutoSharding과 Balacing 제공. 10gen에서 Commercial Support
-CouchDB : MongoDB와 특성은 유사하나 내부 기술 구조는 다름

http://bigdatalowlatency.com/

대용량 분산 데이타 처리에 대한 글이 많다.

큐브리드에서도 NoSQL 벤치마크한 자료들이 많네요. 그것도 영어로..
http://blog.cubrid.org/dev-platform/nosql-benchmarking/

여기 Foursquare에서 MongoDB에 대한 장애 케이스가 있네요
http://monetary.egloos.com/3600459

결국은 메모리가 빵빵해야 하고, 용량 초과되기 전에 증설을 자알~~ 해야 한다는것.

요즘 대용량 데이타 처리 때문에, NoSQL을 머릿속에만 올려놓고, 근래에나 되서 이래서는 안되겠다 해서 직접 자료를 찾아보고 있습니다.

NoSQL은 Cassandra, HBase, Mongo, Riak등을 후보군으로 뒀는데,

Cassandra는 FaceBook에서 Donation해서 만든 분산 DB로 개인적으로는 가장 신뢰가 가기는 했지만, 국내의 많은 블로그 포스팅등을 읽어보면, 안정성이나 사용성이 떨어진다는 것이다. 즉 제품은 좋은데 야생마처럼 잘 쓰지 못하면 모쓰는 제품이라는 이야기. 일단 후보로 남겨놓고 패스.

HBase는 Hadoop File System (HDFS)를 기반으로 설계되었는데, 검색해보니 생각보다 많이 사용이 안되는 것 같아서 패스
Riak도 신생이라서 패스

결국은 Mongo와 Cassandra에서 고민하게 되었는데,
신생 MongoDB가 얼마전부터 사람들 입에 많이 입에 오르내리고 있다. 검색을 해봐도 많이 나오고
이는 즉 사용이 쉽다는 것을 의미하고 또한 10gen이라는 회사에서 제품에 대한 Ownership을 지고 서포트와 컨설팅 그리고 라이센스를 제공하고 있다. 둘다 오픈소스(?)이긴 하지만 자기네들만이 사용하기 위해 만든 Cassandra와는 태생 자체가 다르다는 사실

요즘 분산 아키텍쳐를 보면 대부분 비슷한것이 앞단에 Load Balancing을 해주는 Proxy 를 두고, 뒤에 데이타 처리를 하는 Processing Node를 두는 것이 일반적인데, SWIFT도 글코, MogileFS도 글코, 분산 처리 환경인 Gearman이나 Hadoop도 결국은 비슷하다. 아니나 다를까, MongoDB도 유사한 구조를 갖는다.

일단 기능적인 특징을 보면

Indexing이 가능하다.
이말은 즉 빠른 Search가 가능하다는 이야기인데, 문서를 찾아보니, Index는 메모리에 저장되기 때문에, 메모리 크기에 영향을 많이 받는다. 즉 Deployment설계할때, 하드웨어의 Memory 사이즈가 중요한 Factor 라는 것

GridFS 기반의 Blob 데이타 저장 지원
GridFS라는 분산 파일 시스템을 사용하여 Binary 데이타 저장이 가능하다. 일반적인 아키텍쳐에서 meta 정보를 DBMS에, binary를 File System에 나눠서 저장할때, 이로 인해서 발생되는 데이타 일관성에 불일치를 방지할 수 있다는 점에서는 혁신적인데.. 문제는...
국내의 어느 블로거가 테스트한 데이타 http://symplog.tistory.com/entry/MongoDB-MongoDB-GridFS-%EB%B6%80%ED%95%98%ED%85%8C%EC%8A%A4%ED%8A%B8 를 보면, 파일 업로드 다운로드 성능이 그리 뛰어나지 않은 듯 하다.
큰 파일을 저장할때, 파일을 Chunk 단위로 나눠서 다운로드, 업로드 하는데 이는 메모리 사용면에서 효율성을 제공한다. (한꺼번에 다 읽거나 쓸때 한꺼번에 Flush를 하면 파일을 메모리에 가지고 있는 동안, 파일 사이즈가 크면 Out Of Memory를 유발할 수 있기 때문에..) 1.7 버전 이하에서는 4M, 1.7 이상에서는 16M의 Chunk Size를 제공하는 것 같은데.
문제는 Opendedup에서도 테스트해봤지만, 이 Chunk 단위로 파일을 나누는 작업이 보통 일이 아니라는, 일단 태생 자체가 작은 Blob 데이타를 저장하기 위함이지 대용량 파일을 저장하기 위함은 아닌 것 같은데,
http://blog.wordnik.com/12-months-with-mongodb 블로그를 보면 12billion (약 120억개)의 레코드를 저장하고, 여기에 음악 파일을 저장하는 것을 보면 가능하다고도 볼 수 있다. 보통 음악 파일이 4M 안팍인것을 감안하면 괜찮은 시나리오인 듯 하나 500GB가 넘어가는 비디오 파일을 저장할때는 어느정도 성능을 감당할 수 있을지는 미지수 이다.
만약에 안정적으로 GridFS가 대용량 파일을 저장할 수 있는 구조를 제공한다면 사람들이 SWIFT,MogileFS,GlusterFS를 사용하지 않고 모두 MongoDB를 사용해야 하지 않을까?
이 부분은 나름 테스트가 필요한 부분으로 남겨놓고 넘어간다.

Querying
아울러 RDBMS 와 같은 Query를 제공한다. (물론 RDBMS보다 한참 못 미치기는 하지만)
Key/Value Store만 지원하는 다른 NoSQL에 비하면 매력 적인 기능

Replication
http://www.mongodb.org/display/DOCS/Master+Slave
Master-Slave Replication도 지원하네, Query Off Loading 구현도 가능하겠다.

Sharding
그외에 자체적으로 데이타 Sharding 아키텍쳐를 지원한다. 요즘 이게 유행인지 MySQL 최신 버전도 자체적으로 Sharding을 지원한다. Sharding을 사용하면 1000개의 Shard까지는 거뜬히 지원할 수 있는 것 처럼 나오는데, 이건 테스트 하기는 어려울테고, 성능 데이타를 레퍼런스 하는 수 밖에

일단 완성도나 기능들이 높아 보이는 것 같은데..
깔아서 테스트해보고, 10gen 에서 컨설팅 불러서 직접 들여다 봐야 몬가 나오지 않을까?
=== 첨언 ===
구조를 살펴보니, 앞에서 언급했던 것처럼 SWIFT나 MogileFS와 상당히 유사하다
앞단에 Load Balancing 역할을 해주는 mongos 라는 프로세스들이 뜨고
뒷단에 실제 데이타를 저장하는 mongod라는 프로세스들이 뜨는데, 여기서 재미있는 것은 데이타 Replication을 하는데, 각 Shard당 3개의 인스턴스를 제공하도록 구성을 권장한다. Swift등에서 흔히 이야기 하는 3 Copy다. 데이타 안정성등을 위하는 건데. (딱 봐도, 하드웨어 비용이 장난 아니겠다.)

더불어서 MogoDB는 Cassandra나 HBase에 비해서 나은 성능을 갖는데 앞에서 설명한 바와 같이 Memory를 이용한 Indexing등으로, 반대로 이야기 하면 Memory가 충분히 있어야 한다는 이야기고, 비싸다는 이야기다.

큐브리드 블로그에 보면 재미있는 내용이 있는데 http://blog.cubrid.org/dev-platform/nosql-benchmarking/

Cassandra and HBase is for processing full-scale large amounts of data, while MongoDB can be used quickly, schema-free when using a certain amount of data.

MongoDB adopts a documented-oriented format, so it is more similar to RDBMS than a key-value or column oriented format.

MongoDB operates on a memory base and places high performance above data scalability. If reading and writing is conducted within the usable memory, then high-performance is possible. However, performance is not guaranteed if operations exceed the given memory. Therefore, MongoDB should be used as a medium or small-sized storage system.

한마디로, 성능은 좋지만 빅데이타는 Cassandra나 HBase를 쓰고 중소형에만 MongoDB를 쓰라는 것이다.
RDBMS에 유사하고 강력한 Feature, 사용의 편리성의 입장에서 MongoDB가 국내외에서 많은 사용층을 가지고 있는 것이 대강 이해는 된다. 한편으로는 MongoDB의 한계를 벗어날만한 데이타를 아직까지 사용해본 적이 없다는 반증도 될것이다. 10~20억 데이타는 내가 아는한에서는 RDBMS에서도 크게 문제가 없다. 문제는 10~20억을 넘는 100억, 1000억개의 데이타 핸들링에도 MongoDB가 버텨 줄것이냐인데.. 데이타 한건당 대략 10K만 잡아도 용량이 1Peta 이다. 3TB 노드를 300개 정도 연결해야 한다는 것인데... MongoDB에서 보통 1000개의 Instance를 이야기를 하니 이론상으로는 가능할것 같기는 한데
첫번째는 어렵지 않을까? 하는 생각이고, (그만한 레퍼런스가 있냐?) 두번째는 만약에 된다고 하더라도 돈이 엄청 들어갈것 같은 느낌이다. Swift도 MogileFS도 저가라고는 말하지만 소프트웨어가 저가인거지 3Copy로 하드웨어 구성을 벤더 제품으로 하면 마찬가지라는... (Commodity 하드웨어라면 몰라도..)
  이래 저래 자료를 찾아볼 필요가 있다.



No-SQL DB Comparison

클라우드 컴퓨팅 & NoSQL/NoSQL 일반 | 2011.01.06 09:51 | Posted by 조대협
http://kkovacs.eu/cassandra-vs-mongodb-vs-couchdb-vs-redis

Mongo DB,Cassandra,HBase 등 NoSQL에 대해서 비교를 해놨음

ROA (REST 아키텍쳐)의 완성

아키텍쳐 /WEB 2.0 | 2010.03.22 17:23 | Posted by 조대협

고객사 차세대 아키텍쳐에 대한 Blue Print를 Research하다가 NoSQL (Cassandra, HBase)등을 reference했는데, 결과적으로 ROA 아키텍쳐의 완성은 NoSQL DBMS가 있어야 하는게 아닌가 싶다.

보고용 Article을 좀 쓰다가 정리가 안되서 blog에 포스팅하는데,
ROA에서 문제는 기존의 RDBMS는 ROA의 Resource구조와 맵핑이 잘 안된다.
ROA는 1 resource가 하나의 저장소에 저장되는 형태가 좋은데, (하나의 ROW라던지). RDBMS는 여러개의 Table에 걸쳐서 데이타가 나누어 저장되고, Key 구조도 FK를 이용하거나해서 복합 키가 생겨 버려서 Key 정의에도 모호성이 보인다.

반면에 NoSQL DB, 특히 Column형 DB는 Key & Value형태를 가지고 Value는 Schmeless로 아무 데이타형이나 들어갈 수 있기 때문에, (마치 HashTable에 VO를 Object 형으로 넣으면 모든 데이타 타입을 다 넣을 수 있는것 처럼) ROA 에 딱 맞아 떨어진다. 그것도 아주!! 기가막히게...

벌써 Facebook,Digg,Twitter들도 MySQL에서 Cassandra로 많이 전환하였다.
성능과 안정성 대용량 데이타 모두 지원하니 최고이기는 한데,
문제는 이런 SNS 애플리케이션들은 데이타 구조가 엔터프라이즈 애플리케이션에 비해서 많이 간단하다는 것이다. Reference관계가 없더라도 구현이 가능하다는 것이다.

반면 엔터프라이즈 애프리케이션은 각 엔터티간 관계 복잡한 관계 설정이 필요하다.

내린 결론은 ROA의 가장 이상적인 아키텍쳐는(본인 생각에)
ESB를 통한 유연성을 제공해주는 진입부분, REST 컴포넌트 그리고 NoSQL DBMS이다.
단 복잡도가 높은 엔터프라이즈 애플리케이션에는 적용하기가 어렵고 복잡도가 상대적으로 낮은 SNS성에 적합하다

결국 엔터프라이즈는 SOAP을 경량화해서 구현하는게 정답이 아닐까 싶다.

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

참고 할만한 자료

http://research.microsoft.com/en-us/people/sriram/raghuramakrishnan.pdf

오늘 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를 필두로한 엔터프라이즈 진영보다, 서비스 진영의 기술들이 더 앞서가는 느낌이 듭니ㅏㄷ.