클라우드 서비스의 성능을 측정하기 위한 벤치마크 툴입니다. 여러개의 대안이 있을 때 어떤 것이 우리쪽에 더 적합한가 측정하기에 아주 훌륭한 도구 입니다.

  YCSB 메인 페이지


설치 방법

   
    $ wget https://github.com/downloads/brianfrankcooper/YCSB/ycsb-0.1.4.tar.gz
    $ tar xfvz ycsb-0.1.4.tar.gz
    $ cd ycsb-0.1.4


컴파일 된 바이너리를 다운 받는 방법 (자바로 추정)

    $ git clone git://github.com/brianfrankcooper/YCSB.git
    $ cd YCSB
    $ mvn clean package


실제로 다운 받아서 컴파일 하는 방법. 그러나 컴파일이 안됩니다. asm 3.1.jar 의 압축이 풀리지 않는다는 이유로 에러가 발생합니다. (여기서 중단.. 안되는 일을 되게 할려는 노력도 중요하지만 굳이 쉽게 되는 일이 있는데 할 필요는 없는 듯..)

설치가 됐으면 실제로 테스트 해보는 시간입니다. 자세한 설명은

 https://github.com/brianfrankcooper/YCSB/wiki/Running-a-Workload

위 주소에서 잘 나와 있습니다. 그러니 생략하고 제가 좋아하는 실전형 따라하기 모드로 가겠습니다. MongoDB 에서 테스트를 한다고 가정합니다.

    - MongoDB 는 Local 에 설치되어 있다고 가정합니다. Port 는 40001 에 띄워져 있습니다.
   

YCSB 는 2가지 형태의 모드가 있습니다. (정확히는 3가지지만 shell 은 당장 안 쓸거라서 설명에서는 제외하겠습니다) 즉 load 와 run 입니다.


    load

데이터를 벤치마크 대상 데이터 저장소에 삽입하는 일입니다.


    run

이미 들어간 데이터를 가지고 벤치마크 테스트를 행하는 일입니다.


그러나 load 는 간단한 건에 대해서는 잘 동작하지만 건수가 억단위로 가면 시간이 기하급수적으로 늘어납니다. 그래서 데이터를 입력하는 것은 수동으로 1-100000000 의 숫자 아이디를 가진 'x' * 1000 바이트 짜리 데이터를 입력하는 모듈을 짜서 데이터를 입력해 두었습니다. (load 가지고 테스트를 하고 싶으면 대략 10만에서 100만 정도 까지 데이터를 입력하는 형태로 운영하시면 좋습니다)

ycsb-0.1.4 디렉토리에 있다고 가정하면 결론부터 이야기 하기로 하겠습니다.

 
   $ ./bin/ycsb run mongodb -P workloads/workloada -P mongo.ini -s > result.log


지금은 이대로 따라서 하면 에러가 발생할 것입니다. (그러나 어떤 원리인지 모르지만 파라미터가 틀려도 기본적으로 동작합니다.)


ycsb 는 실행 명령입니다.

run 은 transaction mode 로 실행하라는 소리입니다.

mongodb 는 내가 테스트 하고 싶은 DB Layer 가 MongoDB 라는 소리입니다.

-P workloads/workloada 는 Property 로 workloads 디렉토리 밑에 있는 workloada 를 선택해 주라는 이야깁니다. Property 는 지정 파일을 열어보시면 ycsb 를 실행할때 필요한 설정들이 들어 있는 것을 확인하실 수 있습니다. -P 는 파일을 지정할 수 있고, -p 는 개별 설정들을 지정할 수 있습니다.

-P mongo.ini 는 내가 지정해 줄 수 있는 설정들을 포함하고 있습니다. -P 인것을 보니 파일을 지정하는 것이겠지요? workloada 와 mongo.ini 에 같은 항목에 대한 언급이 있다면 마지막에 명시된 설정값을 따릅니다. 즉 위 예제에 따르면 mongo.ini 에 있는 것을 따르게 되어 있습니다.

-s 는 10초마다 진행사항을 보여주라는 의미입니다.


그리고 mongo.ini 의 내용입니다.


    mongodb.url=mongodb://localhost:40001
    mongodb.database=mydb
    mongodb.writeConcern=normal
    table=robots
    operationcount=10000


내용중에 관심 있게 볼 것은
   

url 은 mongodb 가 떠 있는 주소와 포트입니다.
database 는 테스트할 대상이 있는 db 의 이름입니다.
table 은 테스트할 대상이 있는 collection 의 이름입니다.
operationcount 는 내가 run 을 실행할때 몇번의 수행작업을 할 것인지 정해주는  것입니다. (load 시에는 recordcount 입니다)

어려운듯 보입니다만 (실은 어려웠습니다.. ) 막상 실행을 해보니 어렵지는 않더군요.

HBase 는 가-분산 방식 까지 설치되어 있다고 가정하고 Hadoop 은 완전-분산 방식까지 설치되어 있다고 가정합니다. (지난 포스트들을 찾아보세요)

4대의 서버에 걸쳐서 HBase 클러스터링 설정을 하는 것으로 하겠습니다. 

nobody1 - HMaster
nobody2 - RegionServer
nobody3 - RegionServer
nobody4 - RegionServer

 




이제 설정파일들을 검토하겠습니다.  

    conf/hbase-env.sh
   

  # export JAVA_HOME=/usr/java/jdk1.6.0/
  export JAVA_HOME=/usr/lib/jvm/java-6-openjdk


를 추가해주고 (아마 되어 있을 것입니다)

 

  # export HBASE_CLASSPATH=
  export HADOOP_HOME=/home/hadoop/work/hadoop-1.0.1
  export HBASE_CLASSPATH=${HBASE_CLASSPATH}:$HADOOP_HOME/conf


를 추가해줍니다. 
 

  # Tell HBase whether it should manage it's own instance of Zookeeper or not.
  export HBASE_MANAGES_ZK=true


이제 주키퍼를 사용한다고 설정해야 하는 부분입니다. 

conf/hbase-site.xml

 1    <configuration>
 2    <property>
 3        <name>hbase.rootdir</name>
 4        <value>hdfs://nobody1:9000/hbase</value>
 5    </property>
 6
 7    <property>
 8        <name>hbase.cluster.distributed</name>
 9        <value>true</value>
10    </property>
11
12    <property>
13        <name>dfs.replication</name>
14        <value>3</value>
15    </property>
16
17    <property>
18        <name>hbase.zookeeper.quorum</name>
19        <value>nobody1,nobody2</value>
20    </property>
21
22    <property>
23      <name>hbase.zookeeper.property.dataDir</name>
24      <value>/home/hadoop/work/hbase-0.92.1/zookeeper</value>
25      <description>Property from ZooKeeper's config zoo.cfg.
26        The directory where the snapshot is stored.
27      </description>
28    </property>
29   </configuration>
   
hbase.rootdir 은 하둡의 네임노드뒤에 /hbase 를 적어줬습니다. 
hbase.cluster.distributed 는 클러스터링을 할 것인지에 관한 것입니다. true 로 적어줬습니다. 
dfs.replication 은 복제셋을 얼마나 가져갈 것인지에 관한 설정인데 3 으로 정해줬습니다. 

zookeeper
관련 설정은 꼭 해줘야 하는 부분입니다. 
hbase.zookeeper.quorum 은 클라이언트가 접속해야 하는 주키퍼를 설정해줄 수가 있습니다. nobody1 과 nobody2 에 주키퍼가 떠 있어서 클라이언트의 접속을 받을 것이라는 설정입니다. 

   conf/regionservers

   

   nobody1
   nobody2
   nobody3
   nobody4


   
이것은 실제적으로 데이타가 저장이 되는 리젼 서버(Region Server)들이 저장되는 곳입니다. 여기에 쓰여져 있는대로 리젼서버들이 구동됩니다. 

이제 설정이 끝나고 설정을 복사해 줄 차례입니다. 

   

   $ cd ~/work/hbase-0.92.1
   $ rsync -av . hadoop@nobody2:/home/hadoop/work/hbase-0.92.1/
   $ rsync -av . hadoop@nobody3:/home/hadoop/work/hbase-0.92.1/
   $ rsync -av . hadoop@nobody4:/home/hadoop/work/hbase-0.92.1/


   이제 다 설정 되었으니 하둡을 먼저 구동시키고 HBase 를 구동시킵니다. 
   

   $ cd ~/work/hbase-0.92.1
   $ bin/start-hbase.sh 




몽고 DB 에서 간단한 맵 리듀스 (MapReduce)를 돌려보겠습니다.

예제의 원문은

http://cookbook.mongodb.org/patterns/pivot/

에서 찾을 수 있습니다.


db.actors.insert( { actor: "Richard Gere", movies: ['Pretty Woman', 'Runaway Bride', 'Chicago'] });
db.actors.insert( { actor: "Julia Roberts", movies: ['Pretty Woman', 'Runaway Bride', 'Erin Brockovich'] });

기본이 되는 데이터를 집어 넣습니다.

map = function() {
  for(var i in this.movies){
    key = { movie: this.movies[i] };
    value = { actors: [ this.actor ] };
    emit(key, value);
  }
}


map 함수입니다. mapreduce 를 돌리는 대상이 아래에도 나오지만 actors 이기 때문에 this 는 actors 컬렉션을 지칭한다고 보면 됩니다.

  for(var i in this.movies){

map 은 대체적으로 모든 데이터 한 row 당 매핑 (mapping) 된다고 보면 되기 때문에 actors 의 한 row 는 actor 한개와 movies 여러개가 들어 있습니다. 첫 줄은 movies 갯수만큼 for 문을 돌리라는 이야기 입니다.

    key = { movie: this.movies[i] };

key 값은 영화명으로 지정해 주는 것입니다. 해쉬 값으로 설정되는 것이겠지요? {movie: **** } 형태입니다.

    value = { actors: [ this.actor ] };

value 값은 배우명으로 지정해 주는 것입니다. 역시 해쉬 값으로 설정되는 것입니다. {actors: ***}

    emit(key, value);

map 함수들이 보통 하는 것이 reduce 에게 전달하기 위한 값들을 추출하는 것이 목적이기 때문에 (key, value) 쌍으로 값을 송출합니다.


reduce = function(key, values) {
  actor_list = { actors: [] };
  for(var i in values) {
    actor_list.actors = values[i].actors.concat(actor_list.actors);
  }
  return actor_list;
}

리듀스 (reduce) 함수는 프레임워크가 맵 (map) 함수에서 송출된 데이터를 key 값으로 정렬 시킨 값을 넘겨 받습니다. 넘겨 받는 인자가 (key, values) 로 바뀐것을 주목하시면 됩니다. 즉 map 에서 송출한 데이타들을 key 값으로 정렬한 것입니다. 즉 { movie : aaa } 라는 key 값으로 { actors : [bbb , ccc]} 라는 값으로 넘어옵니다.

  actor_list = { actors: [] };

reduce 함수는 일정한 형태로 값을 넘겨 받아야 합니다. 그 형식을 만들어 주는 것이라고 보면 됩니다. (단  key, value 가 한개씩 붙어 있는 형태는 reduce 를 거치지 않고 바로 db 에 쓰여집니다)

  for(var i in values) {
    actor_list.actors = values[i].actors.concat(actor_list.actors);
  }

values 에 있는 값들을 한개씩 리턴할 값에 붙여 주는 행동입니다.


printjson(db.actors.mapReduce(map, reduce, "pivot"));


실제로 mapReduce 를 구동시키고 그 결과값을 Pivot 에 써주는 작업입니다.

db.pivot.find().forEach(printjson);


잘 쓰여졌는지 확인하는 작업입니다.

위 파일을 내려 받으시고 command line 상에서

$ mongo movie-star.js --shell


라고 입력하시면 구동하시는 모습을 확인할 수 있습니다.


먼저 하둡(Hadoop) 이 필히 설치가 되어 있어야 합니다. 이번에 HBase 를 가-분산 방식 (Pseudo Distributed )으로 설치해 볼 예정이기 때문에 하둡 (Hadoop) 또한 가-분산 방식으로 설치가 되어 있는 것이 좋을 것입니다.

하둡이 먼저 설치되어야 하는 이유는 HBase 가 하둡 기반위에서 돌아가기 때문입니다. $HBASE_HOME/lib 밑의 추가되어 있는 hadoop-core-x.x.x.jar 는 스탠드얼론(Stand Alone) 버젼에서 쓰이는 것으로 나중에 분산적용할 때는 클러스터(Cluster)에 설치되어 있는 하둡과 버젼을 일치시켜줘야 한다. 따라서 HBase 0.92.0 버젼을 설치하기 위해서는 Hadoop-1.0.0 버젼이 설치되어야 합니다.

하둡 설치하는 방법은 저의 지난 아티클 을 참조합니다.


하둡이 설치되고 구동되는 것까지 확인해 보셨다면 설정 파일들을 몇개 수정해 줘야 합니다. 일단 디렉토리를 계속 왔다리 갔다리 하는게 귀찮으니 하둡쪽의 conf/hdfs-site.xml 을 HBase 쪽의 conf/hdfs-site.xml 로 링크를 걸어주는 작업부터 하기로 합니다.

$ cd ~/work/hbase-0.92.0/conf
$ ln -s ~/work/hadoop-1.0.0/conf/hdfs-site.xml hdfs-site.xml

링크가 걸렸다면 다음 파일을 열어서

conf/hbase-site.xml, conf/hdfs-site.xml

 
<property>
    <name>dfs.support.append</name>
    <value>true</value>
 </property>

위의 내용을 추가해 줍니다.

그리고

conf/hdfs-site.xml 파일 아래쪽에 동시에 제공될 수 있는 파일들 갯수의 상한선을 지정해줘야 합니다.

      <property>
        <name>dfs.datanode.max.xcievers</name>
        <value>4096</value>
      </property>


에 추가 , 이것을 지정 안해 줄시에는 이상한 에러가 발생한다고 하니 유념하시기 바랍니다.

그리고 다음 파일을 열어서

conf/hbase-env.sh

export HADOOP_HOME = /home/crazia/work/hadoop-1.0.0
export HBASE_CLASSPATH=${HBASE_CLASSPATH}:$HADOOP_HOME/conf


이 내용을 추가해 주고

export JAVA_HOME=/usr/java/jdk1.6.0_31/


위의 내용을 추가해서 어떤 자바를 쓸 것인지 지정해줘야 합니다.

여기까지는 공통된 부분이고 이제부터 분산방식을 지정해야 합니다.  분산 방식은 보통 가-분산 (Pseudo-Distributed) 방식이랑 완전-분산(Fully-Distributed) 방식으로 나뉩니다. 컴퓨터 한대에 설치해서 테스트 해 볼것이기 때문에 가-분산 방식으로 설치해보기로 합니다.

하둡은 이미 설치되서 가-분산 방식으로 설정이 되어 있다고 했었기 때문에

hbase-site.xml 의 최종 모습입니다.

<configuration>

  <property>
    <name>hbase.rootdir</name>
    <value>hdfs://localhost:9000/hbase</value>
  </property>

  <property>
    <name>dfs.support.append</name>
    <value>true</value>
  </property>

  <property>
    <name>dfs.replication</name>
    <value>1</value>
  </property>

</configuration>


hbase.rootdir 은 $HADOOP_HOME/conf/core-site.xml 에 있는 fs.default.name 을 참조합니다. 제 것은 포트 번호가 9000으로 되어 있군요. 그래서 9000 으로 지정해주고 /hbase 라고 추가해 줬습니다.

hdfs-site.xml 의 최종모습입니다.

<configuration>
  <property>
    <name>dfs.replication</name>
    <value>1</value>
  </property>

  <property>
    <name>dfs.name.dir</name>
    <value>/home/crazia/work/hadoop-1.0.0/name</value>
  </property>

  <property>
    <name>dfs.data.dir</name>
    <value>/home/crazia/work/hadoop-1.0.0/data</value>
  </property>

  <property>
    <name>dfs.support.append</name>
    <value>true</value>
  </property>

  <property>
    <name>dfs.datanode.max.xcievers</name>
    <value>4096</value>
  </property>

</configuration>


설정이 다 되었습니다. 이제 하둡부터 구동시킵니다.

$ cd $HADOOP_HOME


  하둡이 설치된 곳으로 이동하라는 명령입니다. 참고로 저는 /home/crazia/work/hadoop-1.0.0 에 설치가 되어 있습니다.

$ ./bin/start-all.sh


하둡을 구동시킵니다. 사실 하둡 파일 시스템만 구동시키면 되지만 그냥 전부 다 구동시켜줍니다. (파일 시스템만 구동시킬 경우에는 start-dfs.sh 를 사용합니다) 하둡이 완벽하게 구동 되었으면 이제 HBase 를 구동시킬 차례입니다.

$ cd $HBASE_HOME


  HBASE 가 설치된 곳으로 이동하라는 명령입니다. 참고로 저는 /home/crazia/work/hbase-0.92.0 에 설치가 되어 있습니다.

$ ./bin/start-hbase.sh


구동이 완료 되었습니다. 저번 아티클 에서 언급됐던 shell 을 띄워서 제대로 구동이 됐는지 테스트를 해봅니다.

이상입니다.


바야흐로 폭발적인 데이터의 시대가 왔습니다. 저번 포스트 에서도 언급을 했지만 RDBMS 와 다르게 확장을 주요 특징으로 하는 것이 NoSQL 입니다. 즉 '분산' 으로 그 폭발적인 데이터들을 전부 수용이 가능합니다.

이러한 NoSQL 중에서 CouchDB 를 잠시 살펴보기로 하겠습니다.

http://couchdb.apache.org/

위 링크에서 대략적인 것을 살펴 볼 수가 있습니다. CouchDB 의 가장 큰 특징은 (절대적으로 제 관점입니다)

Subversion 같은 파일 레파지토리 시스템 (File Repository System)을 분산 DB 형태로 바꾸어 놓은 것이라고 할 수 있습니다

세세한 몇가지 특성을 살펴보기로 하겠습니다.

1. Erlang 이란 언어로 쓰여짐
 
가장 빠른 속도를 자랑한다는 소리만 많이 들었습니다만 아직 써보지는 않았습니다. 컴퓨터 언어세계에서 몇개국어 이상을 하다 보니 더 이상 언어 배우는게 힘들더군요. (게임할 시간도 부족.. 쿨럭)

2. DB 속성중 일관성 (Consistency) 가 강화 됐다.
 
저번 포스트 에서 언급 했던 CAP 이론중에서 CP 쪽 특성을 가지고 있는 것이라고 볼 수 있습니다.

3. 사용하기 쉽다
 
몽고디비 (MongoDB) 같은 계열의 특징입니다. 가장 주요하게 설치될때 웹서버도 같이 설치되고 클라이언트랑 HTTP로 통신하고 데이터를 Json 방식으로 주고 받습니다. 당연히 사용하기 쉽겠지요?

4. 양방향 복제 (Bi-Directional Replication)
 
생물학에서 나온 용어 입니다. 초기 세포분열이 시작될때 한 시점을 바탕으로 해서 양쪽으로 똑같이 복제 되가는 형태를 말합니다. 여기서는 데이타가 초기에 디비에 저장될 때, 똑같이 양쪽으로 복제가 일어나는 것을 말하나 봅니다.

5. Document - Based 방식

데이타를 문서 형태로 저장합니다. 초장에 설명 드릴 때 SVN (Subversion) 방식의 디비화 라는 설명을 드렸습니다.

6. RESTful HTTP API 를 지원한다.
 
3번하고 연결되는 내용이기도 합니다만, 성격이 조금 다르지요. 말 그대로 API 형태로 RESTful 방식을 지원합니다.

7. 읽고 쓸 때 락 (Lock)이 없다.
 
보통의 디비랑 다른 점이라고 할 수 있지만, SVN 시스템을 써보셨다면 이해하실 것입니다. 락은 없지만 Conflict 는 생길 수가 있다는 점이 특징입니다. 따라서 마치 SVN 처럼 Conflict 가 생겼다면 변경된 내용이 추가되서 변경할 수 있게 합니다.

8. Crash-Only 설계가 적용되었다.
 
데이터 파일이 항상 무결한 상태에 있음을 보장하기 위해서 캐쉬에 일부 저장했다가 커밋시 커밋된 데이터나 관련된 자료구조를 덮어 쓰지 않는다고 합니다. 개별적인 특징으로 시스템이 돌아가던 서버가 갑자기 꺼진다고 해도 데이터는 무결한 상태가 유지되는 것입니다. 즉 일반적으로 셨다운 (Shutdown)이 없다고 합니다.

9. MVCC (Multi-Version Concurrency Control) 지원
 
이것이야 말로 가장 SVN 같은 시스템과 비슷한 기능입니다. 여러 클라이언트가 동일한 문서를 보고 있다고 해도 그 동일한 문서가 같은 버젼일 수가 없습니다. 즉 어려운 말로 하자면 읽기의 시작부터 끝까지 일관된 스냅샷 (Snap Shot)을 보게 됩니다.

10. 인덱스 업데이트가 언제나 파일 끝에서만 발생하도록 설계됨

11. 컴팩트(Compact) 를 시켜줘야 한다.
 
 데이터 파일을 저장하는 단위는 일정 크기 (MongoDB 는 16메가)로 늘어나게 되어 있는데 , 이 파일의 크기가 한 없이 늘어나는게 아니라 어느 정도 데이터의 가감이 일어나면 크기를 다시 일정한 크기로 줄여줘서 유지하는 방식을 말합니다.

12. _changes 를 이용한 실시간 갱신

사용자가 보고 있는 문서(Document)가 변경 됐으면 _changes 메시지가 클라이언트측에 도착합니다. 그래서 실시간으로 갱신이 되거나, 편집중이였으면 Conflict 가 발생합니다.

13. JQuery Library 가 포함되어 있다.
 
Javascript 형식의 Map/Reduce 도 지원하는데 이러한 것이 가능한 이유가 독립적으로 JQuery Library 가 포함되어 있기 때문입니다.

14. 활용 되는 곳
 
누적 데이터나, 데이터가 전반적으로 바뀌는 변화가 별로 없는 곳, 실행될 질의가 미리 정의되어 있는 곳 , 데이터들의 버젼 관리가 중요한 곳 (마치 Subversion 을 디비화 시킨것 처럼) 보통 CRM (Customer Relationship Management) 나 CMS (Conversational Monitor System) 같은 곳에서 쓰이기 좋습니다.





화살표는 신경 쓰지 맙시다..

Consistency : 일관성
  각각의 사용자가 항상 동일한 데이터를 조회한다.

Availability : 가용성
  모든 사용자가 항상 읽고 쓸 수 있다.

Partition Tolerance : 확장 가능성
  물리적 네트워크 분산 환경에서 시스템이 잘 동작한다.


기존의 RDBMS 로 칭해지는 데이타베이스들은 CA 에 취중합니다. 따라서 확장이 용이하지가 않고, 대신 최근 트렌드가 되고 있는 NoSQL 들은 기본적으로 P 의 성능이 좋습니다. 그래서 확장성은 기본입니다. 대신 C A 의 일부분을 희생합니다.

카산드라 (Cassandra) 는 AP 를 추구 하고, HBase 는 CP 를 추구합니다.

카산드라는 페이스북이 채택하고 개발해진 것으로 알려지고 유명해 졌는데요. Consistency 모델이 페이스북의 새로운 메시지 플랫폼을 구현하기에는 어렵다고 판단이 되서 , 새로운 메시지 플랫폼은 HBase 로 구현했다고 합니다. 즉 AP 대신 CP 로 페이스북의 데이타의 중요성에 대한 잣대가 이동한 것이지요.






+ Recent posts