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


Archive»


 
 

Couchbase Server

#6. Couchbase server 구조

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




이번에는 마지막으로 카우치베이스의 아키텍쳐에 대해서 알아보도록 하자

노드와 클러스터 (Node & Cluster)

노드는 물리적인 서버에서 기동하는 하나의 카우치베이스 인스턴스로, 카우치 베이스는 여러 개의 노드로 이루어진 클러스터로 구성된다


클라이언트 SDK (Client SDK)

프로그래밍 언어별로 카우치베이스에 접근하기 위한 API(SDK)를 제공한다.


vBucket 개념

카우치베이스는 실제데이타와 물리서버간의 맵핑을 vBucket이라는 것을 이용해서 관리한다. 카우치베이스는 키-밸류 스토어이다. 그래서, 각 키가 어디에 저장되어 있는지를 vBucket이라는 단위로 관리 하는데. 키에 대한 해쉬값을 계산한 후에, 각 해쉬값에 따라서 저장되는 vBucket을 맵핑한다음 각 vBucket을 노드에 맵핑한다.

아래는 서버 3대가 있었을 때, vBucket을 맵핑하는 구조에 대한 예제이다.



※ 출처 : http://docs.couchbase.com/couchbase-manual-2.5/cb-admin/#vbuckets

클라이언트 SDK는 이 vBucket와 노드에 대한 맵핑 정보를 클러스터로부터 받아서 관리한다. 즉 키에 대한 물리적인 서버 맵핑 정보를 클라이언트가 SDK를 통해 직접알 수 있기 때문에, 클라이언트가 PROXY등을 거치지 않고 직접 데이터가 저장된 노드로 접근이 가능하다.

CF. mongoDB의 경우 중간에 Proxy를 거쳐서 데이터가 저장된 물리 노드로 접근하게 된다.

만약에 노드가 추가되거나 삭제되었을 때, 물리적으로 데이터가 다른 노드로 다시 분산 배치되고, 새롭게 배치된 데이터에 따라서 vBucket to 노드간의 데이터 맵핑 정보도 업데이트 되는데, 이를 Rebalancing이라고 한다. (Rebalancing에 대한 내용은 뒤에 다시 설명)



http://docs.couchbase.com/couchbase-manual-2.5/images/vbuckets-after.png 


노드의 상세구조

그러면 각 노드는 어떤 형태로 구성이 될까? 아래는 노드의 대략적인 아키텍쳐이다.

카우치베이스의 노드는 아래 그림과 같이 크게 좌측의 Data Manager와 우측의 Cluster Manager로 나뉘어 진다.




Cluster Manager

Cluster Manager는 노드에 대한 상태와 클러스터에 대한 상태, 설정등을 관리하는 부분으로 Erlang/OTP 기반으로 구현되어 있다. 그 상위단에는 Admin Portal을 위한 Web UI가 8091 포트로 제공되고 있고, 같은 포트로 REST API가 함께 제공된다.

카우치베이스는 클라이언트 SDK는 이 8091 포트의 REST API를 통해서, 설정 정보와 앞서 설명한 vBucket 정보를 읽어온다. 여기에는 실제로 데이터에 대한 set/get이나 뷰 쿼리 수행용 포트정보도 포함이 되는데,  아래 Data Manager에서 제공되는 11211 포트나, 8092 포트가 사용된다..

그 외에도 클러스터 노드간의 통신을 위한 4389, 21100 포트등 다수의 포트가 사용되는데, 카우치베이스는 서버-클라이언트, 서버-서버간에 사용하는 포트들이 많기 때문에, 배포 전에 반드시 포트들을 확인하고 방화벽이나 네트워크 설정에 반영해야 한다.

※ http://docs.couchbase.com/couchbase-manual-2.5/cb-admin/#faqs 문서를 보면 배포시 오픈해야 하는 포트들이 설명되어 있다.


Data Manager

Data Manager 부분은 직접 데이터에 접근하는 부분으로 set/get 메서드를 이용하여 데이터를 저장하거나, 뷰에 대한 쿼리를 수행할 때 접근되는 인터페이스이다.

맨 아래단에는 멀티쓰레드 기반의 Persistence 엔진이 있으며, 디스크에 데이터를 저장하거나 읽어드릴때 사용되는 컴포넌트이다. 그 윗단에는 memcached가 있으며, 데이터를 캐슁하는데 사용된다. 또한 이 계층에서 뷰에 대한 쿼리 엔진이 제공된다.

Memcached 위에는 moxi 가 Proxy로 사용된다.


데이터 쓰기와 복제

클라이언트에서 데이터 쓰기가 발생했을 때, 카우치베이스는 어떻게 데이터를 저장할까?

먼저 클라이언트에서 Client SDK를 통해서 쓰기 요청을 하면, Client SDK는 해쉬 알고리즘에 따라데이터의 키 값에 맵핑 되는 vBucket을 찾아내고, 그 vBucket에 맵핑 되는 노드를 찾아서 쓰기 요청을 전달한다.

쓰기 요청은 해당 노드의 Listener로 전달되고, 이 Listener는 들어온 데이터를 로컬의 캐쉬에 쓰고 클러스터의 다른 노드로 복제 요청을 보낸다. 그리고 데이터는 노드의 디스크에 저장된다.




쓰기 과정중에 노드간의 복제가 발생한다.


노드별 메모리 레이아웃

그러면 각 노드별로 메모리 레이아웃은 어떻게 되어 있을까? 카우치베이스의 경우, memcached를 이용하는 만큼 서버의 메모리 공간 계산이 매우 중요하다. 앞서 글들에서도 설명하였지만, 메모리에 대해서 고려할 때, 카우치 베이스는 버킷의 키를 모두 메모리에 로딩해놓고 있다. 최소 메모리 공간은 전체키의 합보다는 최소한 커야 한다.그리고 각 도큐먼트당 60바이트의 메타 정보 저장공간이 필요하다. (키크기 + 60 바이트)*전체레코드수 / 노드수 * 3 (복제본수) 가 노드당 최소 메모리양이다. 최소 메모리란 말 그대로 최소한 돌릴 수 있는 수준을 이야기하는 것인데, 이 경우에는 캐쉬를 전혀 사용하지 못하기 때문에, 이 메모리 용량으로 서버를 운영하면 절대 안된다. (말그대로 아주 최~~소한이다.)


전체 하드웨어 공간에서 OS가 기본적으로 사용하는 용량을 제외 하면, 카우치베이스의 노드가 그 메모리 공간을 활용하는데, 카우치베이스에서는 노드에 할당된 메모리 공간을 버킷별로 다시 할당한다. (버킷을 생성할 때 설정할 수 있음)


리밸런스(Rebalance)

리밸런스 노드가 클러스터에 추가되거나, 장애등의 이유로 삭제되었을 때 데이터를 다시 노드에 분산 배치를 하는 작업이다. 노드간에 데이터 복제가 심하게 일어나기 때문에, 리밸런스는 부하가 적은 시간대에 하도록 권장하고 있다. (관리 콘솔을 보면 리밸런스를 멈추거나 시작할 수 있는 기능이 있다.) 향후에는 리밸런스를 Throttling 하는 기능이 나온다고 하니 기대해볼만하다.

NoSQL의 경우 특정 노드가 장애가 나서 시스템이 장애 나는 케이스보다 보통 노드를 추가/삭제할때 발생하는 이런 리밸런싱에 의해서 부하가 올라가거나 해서 장애가 나오는 케이스가 많기 때문에 특별히 주의를 기울일 필요가 있다.

 

XDCR

XDCR은 데이타 센터간에 카우치베이스 클러스터 데이타 복제를 지원하는 기능이다.

현재 최신 버전은 2.5 버전인데, 2.5 버전에서는 XDCR을 TLS/SSL을 이용해서 복제하기 때문에 자체적으로 보안을 지원한다. 그렇지만 무료 버전인 2.2 (Community Edition)의 경우 TLS/SSL 기반의 복제가 지원되지 않기 때문에, VPN 기반의 네트워크를 터널을 설정하고, VPN 터널을 통해서 XDCR 복제를 하도록 가이드 하고 있다.


Couchbase Gateway & CouchBase Mobile

카우치베이스의 흥미로운 점중의 하나는 모바일 디바이스에 탑재될 수 있는 Couchbase Lite버전을 제공한다는 것이다. iOS,안드로이드 버전을 제공하며, 또는 일반적인 애플리케이션에 사용할 수 있도록 자바버전과 .NET  버전도 제공된다. (모두 Community edition이 제공된다)

이 Couchbase Lite는 Couchbase 서버와 동기화가 가능하다.


다 못한 이야기

개발 관점에서는 GET/SET그리고 뷰 정도로 간편하지만, 운영과 설정에 대해서는 많아도 너무 많다. 대략적인 사용방법 아키텍쳐에 대해서 알아봤는데, 언급하지 못한 부분이 있어서 몇 가지만 언급하고자 한다.

카우치베이스는 다양한 커넥터를 이용하여 다른 솔루션과의 연동을 지원한다.

Elastic Search와 연동을 통하여 데이터에 대한 FTS (Full Text Search : 검색)을 지원할 수 있으며, Hadoop 연동을 통해서 Map & Reduce 기반의 데이터 처리가 가능하다. 또 오픈소스 ETL인 Talend 연동을 통해서 데이터를 다른 시스템으로 연동(복제)가 가능하며, 마지막으로, 데이터 암호화 솔루션인 Gazzang과 연동을 통해서 데이터를 암호화하여 저장할 수 있다.

http://www.couchbase.com/couchbase-server/connectors

 


Couchbase Server

#3. node.js를 이용하여 카우치베이스에 CRUD 구현하기

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


SDK를 이용한 프로그래밍


이제, 프로그래밍 언어를 이용해서 실제로 카우치베이스에 데이타를 저장해보자. 


카우치베이스에서 지원하는 데이터 타입


앞서 예제에서 카우치베이스 웹콘솔을 통해서 JSON 도큐먼트를 저장해봤다. 카우치베이스는 JSON 도큐먼트뿐만 아니라, 키-밸류 스토어 형식으로 일반 string(문자열), integer(숫자)도 저장할 수 있다. JSON 도큐먼트 이외의 데이터 형은, 콘솔에서는 테스트가 불가능하고, SDK를 이용해서 프로그램을 작성해서 테스트를 해야 한다.


SDK를 이용한 데이터 접근


카우치베이스의 데이타를 접근하기 위한 메서드들은 다음과 같다. 이해를 돕기 위해서 SQL 문장과 비교해놓은 테이블을 보면

(출처 : http://docs.couchbase.com/couchbase-devguide-2.5/index.html#couchbase-sdks-and-sql-commands)

SQL Command

Couchbase SDK Method

INSERT, to create.

set and add

SELECT, to retrieve/read data.

get, multiple-retrieves, and get-and-touch (get and update expiration).

UPDATE, to modify data.

set with a given key, or add with a new key, or replace with a key, or cas, also known as Check-and-Set. Used to update a value by providing the matching CAS value for the document. There are also methods for incrementing and decrementing numeric values, changing the expiration for a value, as well as pre-pending or appending to stored objects.

DELETE, to remove data.

delete, deletes information associated with a given key.

프로그래밍 언어에 따라 제공되는 SDK에 따라서 다소 차이는 있지만 대부분의 흐름은 다음과 같다.

1) 카우치베이스로 connection 연결

2) 카우치베이스 버킷을 명시하여 client를 생성

다음으로, SDK에서 제공되는 메서드를 이용해서, CRUD 연산을 아래와 같이 수행할 수 있다.


INSERT

  • Upsert : set (key,value) , key 에 해당하는 값을 value로 저장한다. 만약에 key에 이미 값이 저장되어 있으면, value로 업데이트 한다. (upsert)

  • Insert : add (key,value) , key에 해당하는 값을 value로 저장한다. 단, 이미 key에 대한 값이 존재하면 에러를 리턴한다. (insert)

SELECT

데이타를 읽어오는 SELECT는 매우 단순하다. get(key) 명령어를 사용한다.

  • Get : value:=get(key), 키에 해당하는 값을 리턴한다.

  • Multiple get : values[] = get(keys[]), 키들에 해당하는 값들을 리턴한다. 키 리스트를 배열 형태의 인자로 넘긴다.

  • Get & touch : 키에 해당하는 값을 리턴하고, 해당 키에 대한 값의 TTL을 초기 값으로 복구한다. 예를 들어 TTL이 30분인 값이 10분전에 저장되었을때, (현재의 TTL은 20이 남는다.) touch를 하게 되면 TTL 값이 다시 30으로 복귀된다. SDK에 따라 다소 메서드 정의가 다르지만, 일반적으로 get/multiple get시 옵션으로 새로운 TTL expiry time을 주는 방식으로, TTL 값을 복구시킬 수 있다.

UPDATE

  • Replace (key,value) : key에 해당하는 값을 value로 업데이트 한다. 만약에 key에 대한 값이 존재하지 않으면 에러를 리턴한다 (update).

  • Touch(key) : 해당 key 에 대한 TTL 값을 재 설정한다.

  • Check and Set (CAS) : Replace와 같은 업데이트 기능을 한다. 단, CAS 값을 같이 인자로 넘겨서 CAS값이 같을 경우에만 Replace를 하고 다를 경우에는 에러를 리턴한다.
    ※ CAS에 대해서는 뒤에서 다시 자세하게 설명한다.

  • Incr/Decr : 앞서도 잠깐 언급했지만, 카우치베이스에는 밸류를 저장할 때, JSON 도큐먼트뿐만 아니라 integer와 같은 숫자값도 저장이 가능하다. 숫자값을 저장했을 경우에는 incr,decr 명령을 이용하여 값을 더하거나 뺄 수 있다.

  • Append/prepend : 밸류가 JSON 도큐먼트나 integer 타입이 아닌, string 문자열로 저장되었을 경우에, append 명령어를 이용하여 문자열 뒤에 새로운 문자열을 붙이거나, prepend 명령어를 이용하여, 저장된 문자열 앞에 새로운 문자열을 붙일 수 있다.

DELETE

  • Remove(key) : 키에 해당하는 데이터를 삭제한다.

Lock 제어

  • Lock/UnLock : 명시적으로 해당 키에 해당하는 데이터에 Lock을 걸거나 풀 수 있다. Lock이 걸려 있을 경우에는 다른 클라이언트에 의해서 해당 데이터에 대해서 접근이 불가능하며, Lock을 풀때에는 Lock을 걸 때 리턴 받은 CAS 값을 가지고 Lock을 풀어야 한다.


db.lock('test-key', function(err, result) {

  if (err) throw err;


  // Do some work


  db.unlock('test-key', {cas: result.cas}, function(err, result) {

    if (err) throw err;


    console.log('Success!');

  });

});



참고 CAS(Check & Set)

CAS는 Check and Set의 약자로, 하나의 도큐먼트에는 CAS의 값이 설정이되어 있고, 도큐먼트의 값(VALUE)가 변경될 때 마다 이 CAS의 값도 변경된다. 이는 일관성을 유지하기 위함인데, 값이 {TOTAL:10}이라는 도큐먼트가 있다고 하자. 애플리케이션에서 이 값을 GET한후에 +1을 해서 다시 저장하는 시나리오가 있을때,


①     클라이언트 A가 GET을 하고+1을 한후에, 다시 SET으로 {TOTAL:11}을 저장하기 전에,

②     클라이언트 B가 GET으로 {TOTAL:10}의 값을 가지고 갔다고 하자.

③     클라이언트 A가 {TOTAL:11}을 저장한후에

④     클라이언트 B도 TOTAL+1을 해서 {TOTAL:11}을 저장하게 되면


위의 시나리오에서는 두개의 클라이언트 A,B가 +1씩 더해서 저장하는 시나리오이기 때문에 값이 12가 되어야 하지만 위와 같이 11이 되는 현상이 발생한다. 일관성이 깨지는 문제인데, 이러한 일관성 문제를 예방 위해서 보통 RDBMS의 경우 lock을 거는 방법을 사용하지만 카우치베이스와 같은 분산 DB의 경우에는 전체 분산 노드 간에 lock을 거는 것이 성능상 문제를 야기할 수 있기 때문에, CAS라는 필드를 사용한다.

위와 같은 경우에 {TOTAL:10}일 때 CAS값이 1이라고 가정하면, GET을 할 때 클라이언트는 {TOTAL:10} value 뿐만 아니라 CAS값 1을 같이 가져온다. 그리고 값을 다시 SET하려하 할 때, 서버에 저장된 도큐먼트의 CAS값과 SET을 하고자 하는 클라이언트가 가지고 있는 CAS 값이 일치해야 SET이 성공한다. 위의 경우 클라이언트 A,B 모두 GET시에는 CAS값을 1을 가지고 갔다고 했으면, 3에 의해서 해당 도큐먼트의 CAS값은 2(다른값)으로 변경이 되었을 것이고, 4에서 클라이언트 B가 이전 CAS값 1을 가지고 SET을 시도하면, 도큐먼트의 CAS값과 다르기 때문에 에러가 발생하게 된다.




Node.JS를 이용한 카우치 베이스 프로그래밍


그러면 Node.JS를 이용해서 카우치베이스의 데이터를 억세스 해보자.

Connection 연결 및 간단한 get/set

아래 코드는 간단하게 카우치베이스에서 Connection을 연결하고, 데이터를 set한 후에, get으로 읽어오는 부분이다.


 

var couchbase = require('couchbase');

 

var bucket = new couchbase.Connection({

    'bucket':'mybucket',

    'host':'127.0.0.1:8091'

},function(err){

    if(err){

        console.error('couchbase server connection error');

        throw err;

    }

})

 

json_document = {

    'name':'terry',

    'country':'korea',

    'role':'architect'

}

// set

bucket.set('mykey',json_document,function(err,result){

    if(err){

        console.error(err);

    }

    // get

    bucket.get('mykey',function(err,result){

        if(err){

            console.error(err);

        }else {

            console.log(result);

        }

        process.exit(0);

    });

});

 


var couchbase = require('couchbase');

 

var bucket = new couchbase.Connection({

    'bucket':'mybucket',

    'host':'127.0.0.1:8091'

},function(err){


카우치베이스 모듈을 Import한다. 만약에 카우치베이스 모듈이 설치되어 있지 않다면, “npm install couchbase” npm 명령을 이용해서 모듈을 먼저 설치하도록 하자. 카우치베이스 모듈은 C 라이브러리를 포함하고 있기 때문에, GCC나 비주얼 스튜디오와 같은 C 컴파일러가 환경에 설치되어 있어야 한다.

모듈을 import했으면, bucket으로의 연결을 만들어야 한다. Connection에서 bucket 필드에 연결하고자 하는 버킷명과, host 필드에는 연결하고자 하는 호스트명/포트를 명시한다. 이때 호스트명/포트는 array 형태로 정의할 수 있다. 만약에 연결하려는 호스트가 장애가 나서 연결이 되지 않을 경우 자동으로 array 내의 다른 호스트로 연결을 시도한다.

그리고 하나의 Connection을 연결하더라도 내부적으로 한 개가 아니라 여러 개의 Connection이 생기는 것을 확인할 수 있는데, Node.JS의 카우치베이스 SDK는 내부적으로 Connection Pooling 기능을 제공해서 여러 개의 Connection을 연후에, 매번 Connection을 새롭게 만들지 않고, 재사용하도록 하기 때문에 별도의 Connection에 대한 관리를 할필요가 없다.

json_document = {

    'name':'terry',

    'country':'korea',

    'role':'architect'

}

// set

bucket.set('mykey',json_document,function(err,result){

 


카우치베이스에 연결이 되었으면, 버킷에 set 메서드를 이용하여 데이터를 저장한다.메서드의 순서는 bucket.set(키,저장할 데이터,옵션,콜백함수(err,result){..}); 로 정의된다.

옵션 부분은 생략할 수 있다. 

옵션 부분에는 

  • cas : 위에서 설명된 Check and Set 값. 이 값이 이전의 CAS 값과 일치하지 않으면 set 이 실패한다.

  • expiry : TTL값으로, 이 시간이 지나면 자동으로 데이터가 삭제 된다.

  • persist_to integer : integer에 정의된 노드의 숫자만큼 데이터가 복제된후에 쓰기 작업을 끝낸다. 예를 들어 10개의 노드가 있는 카우치베이스 클러스터에서 이 값이 2면, 마스터 노드를 포함하여, 2개의 노드에 쓰기가 완료되면 set 작업이 완료된 것으로 리턴한다.

  • replicate_to integer  : integer에 정의된 원격 노드 (다른 클러스터) 숫자 만큼 복제가 완료되면 set 작업이 완료된것으로 리턴한다.

bucket.get('mykey',function(err,result){

다음으로 set으로 입력한 값을 get을 이용하여 조회 한다. 메서드의 순서는 

bucket.get(키,옵션,콜백함수(err,result){…});

순서로 정의 된다. 키에 대한 밸류값을 콜백함수의 “result”변수를 통해서 리턴한다.

옵션으로는

  • expiry integer : 값을 정할 수 있는데, 이 값을 지정하면 TTL 값이 이 값으로 다시 세팅된다. 앞에서 설명한 Get & Touch를 구현할 때 사용할 수 있다.

간단하게 set/get에 대한 예제를 살펴보았다. Node.JS의 카우치베이스 SDK는 단일 키에 대해서 set/get 뿐만 아니라 여러키에 대한 다중 set/get을 함께 지원한다.

setMulti(kv, options, callback), getMulti(kv, options, callback)

를 이용하면, 동시에 여러 키에 대한 업데이트나, 여러키에 대한 데이터 SELECT를 수행할 수 있다.

작성한 예제를 수행해보면 다음과 같은 결과를 얻을 수 있다.



 

도큐먼트 삭제


도큐먼트에 대한 삭제는 remove(키,옵션,콜백함수(err,result){..}); 를 사용해서 삭제하면된다.

적용할 수 있는 옵션은 set에서 사용한 cas,persist_to,replicate_to를 동일하게 사용할 수 있다.


Integer값과, String 값에 대한 처리


앞에도 설명하였지만 카우치베이스에 값은 JSON 도큐먼트뿐만 아니라, integer, string값도 저장할 수 있고, 이 값에 대해서는 incr/decr과 같은 숫자 전용 메서드와 append/prepend라는 문자열 전용 메서드를 지원한다.

다음은 String 값을 ‘ hello ‘라는 문자열로 세팅한후 append 를 이용해서 문자열 뒤에 ‘ node.js ‘ 라는 문자열을 추가하고 prepend 명령을 이용해 문자열 앞에 ‘ im couchbase ‘ 라는 문자열을 추가한 후에, get 명령을 이용하여 문자열을 가져와서 출력하는 예제이다


 

var couchbase = require('couchbase');

 

var bucket = new couchbase.Connection({

    'bucket':'mybucket',

    'host':'127.0.0.1:8091'

},function(err){

    if(err){

        console.error('couchbase server connection error');

        throw err;

    }

})

 

// set

bucket.set('string',' hello ',function(err,result){

    if(err){

        console.error(err);

    }

    // get

    bucket.get('string',function(err,result){

        if(err){

            console.error(err);

        }else {

            console.log(result);

        }

        bucket.append('string',' node.js',function(err,result){

            if(err){

                console.error(err);

            }else{

                console.log(result);

            }

            bucket.prepend('string',' im couchbase' ,function(err,result) {

                if (err) {

                    console.error(err);

                } else {

                    console.log(result);

                }

                bucket.get('string', function (err, result) {

                    if (err) {

                        console.error(err);

                    } else {

                        console.log(result);

                    }

                });

            });

        });

    });

});

 


위의 예제를 수행하면 결과는 다음과 같다.


 

prepend와 append도 set과 마찬가지로 옵션을 줄 수 있는데, 적용할 수 있는 옵션은 expiry,cas,persist_to,replicate_to 등을 적용할 수 있다.

다음은 integer 값을 저장하고, incr/decr을 이용하여 저장된 값을 증가/삭제하는 예제이다.

/**

 * Created by bw.cho on 2014-07-07.

 */

var couchbase = require('couchbase');

 

var bucket = new couchbase.Connection({

    'bucket':'mybucket',

    'host':'127.0.0.1:8091'

},function(err){

    if(err){

        console.error('couchbase server connection error');

        throw err;

    }

})

 

// set

bucket.set('number',100,function(err,result){

//bucket.incr('number',{initial:100},function(err,result){

    if(err){

        console.error(err);

    }

    // get

    bucket.get('number',function(err,result){

        if(err){

            console.error(err);

        }else {

            console.log(result);

        }

        bucket.incr('number',{offset:10},function(err,result){

            if(err){

                console.error(err);

            }else{

                console.log(result);

            }

            bucket.incr('number',{offset:-1},function(err,result) {

                if (err) {

                    console.error(err);

                } else {

                    console.log(result);

                }

                bucket.get('number', function (err, result) {

                    if (err) {

                        console.error(err);

                    } else {

                        console.log(result);

                    }

                });

            });

        });

    });

});

위의 코드는 먼저 set 명령어를 사용하여 ‘number’라는 키에 대한 값을 숫자 100으로 세팅한후에, 

bucket.set('number',100,function(err,result){

다음으로, incr 명령을 이용해서 이 값을 증가 시킨다. 이때 아래와 같이 옵션에 offset이라는 값을 지정할 수 있는데, off set은 증분값이다. off set 값 만큼 더해지는데, 아래의 경우 10을 설정했기 때문에, +10을 해서 값이 110이된다.

bucket.incr('number',{offset:10},function(err,result){

옵션에서 offset을 설정하지 않으면, 디폴트로 +1이 더해진다.

또는 아래 처럼 offset을 -1과 같이 마이너스 값을 사용하게 되면 그 값을 빼진다.

bucket.incr('number',{offset:-1},function(err,result) {

다음은 위의 소스코드에 대한 실행 결과이다.

 

하나 주의 깊게 봐야 할 것은

bucket.incr('number',{initial:100},function(err,result){

과 같이 incr에서 initial 값을 설정할 수 있는데, 이는 마치 upsert와 같이 동작한다. 만약에 해당 키값으로 정의된 값이 있다면, 기존의 값을 그대로 사용하고 만약에 해당 키로 설정된 값이 없다면 이 initial 값으로 set를 하게 된다.

decr 명령어도 증가가 아니라 값을 감소 시킨다는 점에서 사용법은 동일하다.


CouchDB Overview


어제 SSAG 에서 정명훈 이사가 강의한 CouchDB에 대한 내용 정리


CouchDB 일반 특징

CouchDB Apache 프로젝트로 MongoDB와 같은 Document DB의 형태를 띄며, NOSQL CAP이론중 AP 에 해당 한다. (장애에 매우 강하다.) 단 Consistency는 Eventual Consistency를 제공한다. (버전으로 하는 방식), Eventual Consistency 모델이기 때문에 Locking을 사용하지 않는다. (Optimistic Lock)


유사 프로젝트

유사 프로젝트로 CouchBase와 BigCouch, Cloudant등이 있다.

CouchBase는 memcached와 CouchDB를 합쳐놓은 제품으로, 앞단에 캐쉬가 있어서 성능이 매우 빠르다. BigCouch는 CouchDB가 single instance만 지원하는데 반해서, 클러스터링 기능을 가지고 있다. Cloudant는 이 BigCouch를 기반한 제품으로 DBaaS 형식의 서비스로, DB 서비스를 제공하고, 운영을 대행해준다. 향후 BigCouch와 CouchDB가 합쳐져서 클러스터링 기능을 제공할 예정이다.

그 외에도 mobile에 탑재 가능한 버전의 CouchDB들이 있다.


Secondary Index

재미있는 특징중의 하나가 Sencondary Index를 지원하는 데 이는 내부적인 Map & Reduce를 통해서 구현되는데, 2nd index search시마다 MR이 도는 것이 아니라, 2nd index를 만들어 놓은 다음에 이를 View와 같은 형태로 저장해놓고, 이 index 내에서 검색을 한다. 또한 새로운 데이타가 추가되거나 변경이 되더라도 전체 index를 rebuild하는 것이 아니라, incremental 방식으로 변경된 부분만 재 생성한다.

물론 이 index를 rebuild하는 과정에서 서버가 부하를 받아서 성능이 다소 떨어질 수 있으나, 초당 수천건 정도의 index 변경은 수용할 수 있는 수준이라고 한다.


Replication

CouchDB의 강력한 기능중의 하나가 복제 기능인데, 단방향, 양방향 복제, 1:N, M:N 그리고 필터나 룰 기반의 복제(서브셋만 복제하는 기능)도 가능하다. 1회성으로 복제하는 시나리오와 지속적으로 복제하는 시나리오도 가능하면, 네트워크에서 끊어졌다가 나중에 붙어도 복제 및 Sync만 하는 것도 가능하다.

무엇보다 CouchDB는 모바일 버전이 있기 때문에, 이를 이용하면 쉽게 단말과 서버간의 Sync 시나리오를 구현할 수 있다. 오픈 소스로 파일이나 이미지를 서버와 디바이스간에 복제하는 프로젝트가 있다.


Interface

인터페이스는 HTTP REST만 지원한다. 아쉬운 부분인데, 성능이 높은 Protocol Buffer등을 향후 지원했으면 한다.


보안

HTTPS와 OAuth 인증을 제공하며, HTTP Basic Auth도 지원한다. User Identity source (LDAP)등의 연동에 대해서는 자세하게 설명되지 않았는데, 앞단에 reverse proxy를 둬서 인증하는 방식으로 구현이 가능하리라 본다.


대략적인 아키텍쳐

기본적인 메카니즘이 append only 구조로, 일정 이상의 데이타가 쌓이면 내부적으로 자동 Compaction을 한다.

Erlang으로 구현되어 있으며, 그 위에 javascript를 제공하여, MR등은 javascript를 사용하여 구현한다.



Riak Performance

클라우드 컴퓨팅 & NoSQL/Riak | 2012.03.12 23:21 | Posted by 조대협
http://blogs.digitar.com/jjww/2011/03/riak-vs-couchdb-for-storing-100000-coupons/

CouchDB와 비교한 Performance Report가 있는데
Riak 0.14 버전 기준 작년 3월(1년전)이니 많은 변화는 있었겠지만 얻을만한 데이타가 많다.
  • Indexed insertion is 91% slower than storing just the key data.
  • MapReduce with indexes is 20% faster than MR on the data keys alone.
  • MapReduce with indexes and key filters is 32% faster than MR on the data keys alone.
  • Adding Riak nodes substantially reduces query time. Adding 3 more nodes speeds up queries by 40%.

    1. 2'nd index를 사용할시 2배 정도 느리다. (아마 W VALUE를 2정도로 해놓고 테스트 한게 아닌가 싶고)
    2. MR 사용시 2'nd index를 사용하면 더 빨라진다.
    3. Riak Node가 늘어날 수 록  Query Time이 빨라진다. (이건 좀 이상하네..)
    4. 결정적으로 MR (Map & Reduce)의 경우 2'nd index를 적절히 사용하면 CouchDB 이상의 성능을 낼 수 있다.
  • Mongo에서도 더 높은 성능을 낼 수 있을까?

    ==
    첨부

    내일 조금 더 찾아봐야 겠지만, 위의 테스트 결과도 그렇고, Riak MR은 "Filtered set of key"를 이용해서 Mongo 보다 높은 Performance를 내는거 같은데... 이 filtered set of keys가 몬가..... Mongo는 무조건 coverage query 사용하는 것 같고..

    http://nosql.mypopescu.com/post/7011323761/brief-mongodb-and-riak-comparison
    The advantage of Riak over Mongo is that Riak automatically replicates and rebalances.

    The advantage of MongoDB over Riak is that Mongo supports secondary indexes and a more robust query language.

    Both Riak and MongoDB support MapReduce via JavaScript, and both use the SpiderMonkey JavaScript engine. However, Riak’s MapReduce framework is more powerful than MongoDB’s framework because Riak allows you to run MapReduce jobs on a filtered set of keys. By contrast, in Mongo, you have to run MapReduce jobs across an entire database.

    결과적으로, Insert 성능은 Mongo에 비해서 떨어질 수 있지만, Read intensive하고, complexity가 좀 있는 복합 쿼리의 경우 Mongo,Couch 대비 Riak이 filtered set of keys를 써서 Query 성능을 더 올릴 수 있다는 것 같은데...
    내일 라슨씨한테 좀 물어봐야 겄다.

    '클라우드 컴퓨팅 & NoSQL > Riak' 카테고리의 다른 글

    Riak이 좋은 이유 7가지  (0) 2012.03.20
    Riak 장점 다시 정리  (2) 2012.03.12
    Riak Performance  (0) 2012.03.12
    Riak vs CouchDB  (0) 2012.03.12
    NoSQL Riak Overview #1/2  (0) 2012.02.21
    Riak관련 스터디 메모  (0) 2012.02.21

    Riak vs CouchDB

    클라우드 컴퓨팅 & NoSQL/Riak | 2012.03.12 22:58 | Posted by 조대협


    CouchDB의 Kick-ass replication만 기억에 남네 그랴.

    '클라우드 컴퓨팅 & NoSQL > Riak' 카테고리의 다른 글

    Riak 장점 다시 정리  (2) 2012.03.12
    Riak Performance  (0) 2012.03.12
    Riak vs CouchDB  (0) 2012.03.12
    NoSQL Riak Overview #1/2  (0) 2012.02.21
    Riak관련 스터디 메모  (0) 2012.02.21
    Riak Quick Review  (0) 2011.12.19

    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와 특성은 유사하나 내부 기술 구조는 다름