블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-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

 


저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

Couchbase Server

#5. node.js를 이용하여 뷰를 호출하기

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


앞서 설명한 뷰를 node.js 카우치베이스 SDK를 이용해서 호출해보자, 

카우치베이스는 node.js와 몽고DB만큼이나 궁합이 잘 맞는 것 같다. 매우쉽게 뷰를 호출할 수 있다. 뷰 호출 메서드는

var viewQuery = bucket.view(“디자인도규먼트 이름”,”뷰 이름”,{옵션1:값,옵션2:값,…})

로 뷰쿼리를 생성한 후에, 

viewQuery.query(function(err,results){…} );

로 호출하면, 호출 성공시, 결과가 result 변수로 리턴된다.

그러면 간단한 예제를 보자. “mybucket”이라는 버킷이 있고, 안에 다음과 같은 데이타가 있다.

[ { id: 'user0002', key: [ 'us', '75', 'female' ], value: 1 },

  { id: 'user0004', key: [ 'us', '14', 'female' ], value: 1 },

  { id: 'user0003', key: [ 'us', '08', 'female' ], value: 1 },

  { id: 'user0001', key: [ 'korea', '75', 'male' ], value: 1 },

{ id: 'user0005', key: [ 'canada', '69', 'male' ], value: 1 } ]


뷰의 경로는 _desgin/dev_sample 디자인 도규먼트아래에, filter라는 이름으로 다음과 같이 정의되어 있다.


function (doc, meta) {

  var year = doc.ssn.substring(0,2);

  emit([doc.country,year,doc.sex],1);

}


이제, node.js와 Express 프레임웍을 이용해서, 이 뷰를 호출 하는 간단한, REST API를 만들어보자.

 

var express = require('express');

var routes = require('./routes');

var user = require('./routes/user');

var http = require('http');

var path = require('path');

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;

    }

})

var app = express();

 

// all environments

app.set('port', process.env.PORT || 3000);

app.set('views', path.join(__dirname, 'views'));

app.set('view engine', 'jade');

app.use(express.favicon());

app.use(express.logger('dev'));

app.use(express.json());

app.use(express.urlencoded());

app.use(express.methodOverride());

app.use(express.session({ secret: 'your secret here' }));

app.use(app.router);

app.use(express.static(path.join(__dirname, 'public')));

 

// development only

if ('development' == app.get('env')) {

  app.use(express.errorHandler());

}

 

app.get('/', routes.index);

app.get('/myview',function(req,res){

    console.log('myview');

    var viewQuery =  bucket.view('dev_sample','filter'

        ,{reduce:false,descending:true,startkey: [ 'us', '75', 'female' ],endkey:[ 'korea', '75', 'male' ]});

    viewQuery.query(function (err,results){

       console.log(results);

        console.log(typeof (results));

       if(err) {

            console.error(err);

       }else{

           res.send(results);

        }// else

    });

 

});

 

http.createServer(app).listen(app.get('port'), function(){

  console.log('Express server listening on port ' + app.get('port'));

});

 


앞부분에 카우치베이스를 연결하는 부분은 http://bcho.tistory.com/926 의 예제와 동일하다.

var viewQuery =  bucket.view('dev_sample','filter'

        ,{reduce:false,descending:true,startkey: [ 'us', '75', 'female' ],endkey:[ 'korea', '75', 'male' ]});

와 같이 뷰 쿼리를 만들었는데, 여기서 주목할 부분은 option 부분이다.

  • reduce:false로 하여, 리듀스함수를 실행하지 않고, 맵 함수만 수행하도록 하였으며
  • descending:true로 하여, 내림차원 정렬이 되도록 하였다.
  • startkey,endkey를 정의하여, 내림 차순으로 정리한 뷰에서 키의 값이 [‘us’,’75’,’female’]~[‘korea’,’75’,’female’]인 결과만 쿼리하도록 설정하였다.

다음으로 viewQuery.query(function (err,results){ 를 호출하여, 뷰쿼리를 호출한후에, 마지막으로 res.send(results); 를 이용하여 리턴된 결과값을 출력하였다.

※ 결과값은 JSON 도큐먼트로 리턴되기 때문에 바로 JSON 형태로 출력된다.

다음은 예제에 대한 실행 결과 화면이다.

 




저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

Couchbase Server

#4. 뷰(View) 이해하기

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


뷰는 카우치베이스의 아주 강력한 기능중의 하나이다. RDBMS의 뷰의 개념과 유사한 개념으로, 원본 데이터로부터, 필터링을 통하여 원하는 형태의 데이터로 변환하여 보여주는 일종의 읽기 전용 테이블과 유사한 개념으로 보면 된다. 이를 통해서 키-밸류 스토어 기능만 제공하는 일반 NoSQL에 비해서 filtering 뿐만 아니라, Indexing,grouping,ordering과 같은 다양한 기능을 이 뷰를 이용하여 사용할 수 있다.

카우치베이스의 뷰는 원본 데이터에서 자바스크립트로된 맵&리듀스(Map&Reduce) 함수를 통해서 데이터를 정재한 후에, 뷰로 만들어낸다. 간단하게 개념을 잡아보면 다음과 같다.

 


좌측 그림과 같이 이름을 ID로 하고, Country,Role,Age라는 필드를 가지고 있는 값을 VALUE로 저장하고 있다고 하자, 필터링해서 보고 싶은 데이터는 여기서 Country와 Role만을 필터링 하고 싶다. 그래서 맵&리듀스 함수(여기서는 맵 함수만을 사용하였음)를 이용해서 오른쪽과 같은 뷰를 만들어낼 수 있다.


맵&리듀스(Map&Reduce)함수


뷰를 이해하려면 맵&리듀스함수에 대해서 정확하게 이해해야 한다. 맵함수는 버킷에 저장된 모든 데이터에 대해서 맵함수를 실행한다. 뷰를 정의할 때 맵함수는 반드시 정의해야 한다.

function(doc,meta){

 emit(doc.role,doc.country);

}

맵함수는 두개의 인자를 전달 받는다. “doc”는 버킷내의 저장된 개별 데이타로 각 데이터별로 id와 JSON 도큐먼트의 값을 갖는다. “meta” 는 그 데이터에 대한 메타 데이터 (flag,cas 값등)을 리턴한다.

맵함수에서는 이렇게 받은 개별 데이터를 emit이라는 함수로 가공하여 리턴한다. emit 이라는 함수에 필터링등의 로직을 적용할 수 가 있다. emit(인자1,인자2)의 인자1은 뷰의 KEY값을 리턴하고, 인자2는 뷰의 밸류값을 리턴한다.


 emit 함수를 거쳐 맵함수를 끝내면 ID,KEY,VALUE 형식의 데이터 셋이 나오는데, 이를 카우치베이스에서는 “Index”라고 부른다. ID는 원래 데이터에 대한 ID이고, KEY는 뷰의 키값이다. Index는 이 KEY에 따라서 정렬(sorting)된 형태로 리스팅 된다.  그리고 마지막에는 뷰의 값(VALUE)가 저장된다. 이렇게 생성된 Index는 디스크에 저장된다.


저장된 index를 이용해서 리듀스함수(Reduce)를 실행할 수 있는데, 리듀스 함수를 이용해서는 Grouping 기능을 사용할 수 있다. RDBMS의 group by sum이나 group by count와 같은 간단한 기능에서부터 복잡한 계산을 자바스크립트를 이용해서 구현하는 것이 가능하다.



정리하자면 뷰에는 각 버킷내의 개별 데이터를 변환하는 맵함수와, 변환된 개별 데이터를 그룹별로 모아서 처리할 수 있는 리듀스 함수를 갖는다.


Design Document


하나의 버킷에는 여러 개의 뷰를 생성할 수 있다. 아래 그림과 같이 뷰는 Design document라는 단위로 묶이게 되고 각 뷰는 그에 대칭 되는 맵&리듀스 함수를 가지고 있다.

 

 

카우치베이스의 문서를 보면 http://blog.couchbase.com/10-things-developers-should-know-about-couchbase 성능상 무리가 없게 하기 위해서는 하나의 버킷당 4개의 Design Document 정도가 적절하며, 하나의 Design Document당 최대 10개 정도의 뷰를 구현하는 것이 적절하다고 권고하고 있다. (즉 버킷당 최대 40대 정도의 뷰가 적절)


콘솔에서 뷰 만들기


개념을 이해 했으면 이제 간단한 뷰를 만들어보자, 카우치베이스는 웹콘솔에서 뷰생성 및 개발 테스트를 할 수 있도록 지원한다. 카우치베이스 웹콘솔로 이동한후 상단메뉴에서 “Views” 메뉴를 선택한후 아래에 나오는 리스트박스에서 뷰를 생성하고 싶은 버킷을 선택한다. 

다음으로, 아래에 나오는 “Create Development View” 버튼을 선택하면 뷰를 생성할 수 있다.


 

생성 버튼을 누르면 아래와 같이 대화상자가 뜨는데, 첫번째는 Design Document 명이다. 그리고 다음 텍스트 상자가 뷰 이름을 넣는 상자이다.

 


이때, design document를 넣는 텍스트박스에서 Design Document 이름이 “dev_”로 시작하는 것을 볼 수 있는데, Design document는 두 가지 타입이있다. 개발을 위한 개발용 “Development view”와 실제 운영에서 사용할 수 있는 “Production view”가 있다. 이 둘의 차이점은 다음과 같다.

  • Development View : 처음에 뷰를 생성하면 Development View로 생성된다. Design document 이름은 “_design/dev_”로 시작된다. Development View의 경우 버킷의 모든데이타에 대해서 Index를 만드는 것이 아니라 개발 목적이기 때문에 일부의 데이터에 대해서만 Index를 생성한다.
  • Production View : Development View를 이용해서 개발과 테스트를 완료하면 Publish하여 Production View로 전환한다,  Production View는 버킷의 전체 데이터로 Index를 생성한다. 

※ Development View에서 개발 및 테스트가 완료되었으면 반드시 Production View로 배포를 진행해야 한다.

뷰가 생성되었으면 콘솔에서 아래와 같이 뷰의 맵&리듀스 코드를 작성하고 테스트를 해볼 수 있다.



위에 "▼cath”라는 창에 맵&리듀스 코드 작성을 돕기위해서 버킷에 저장된 데이터 중 random으로 출력해서 샘플로 보여준다. “cath”는 샘플로 출력되는 도큐먼트의 ID이다.

아래 “▼View Code” 창 부분에는 왼쪽에는 맵 함수를 오른쪽에는 리듀스 함수를 직접 코딩해볼 수 있다. 그리고 맨아래 부분에는 이 맵&리듀스 함수를 실행했을 때의 결과를 출력해준다.

그 아래 부분에는 Filter Result라는 버튼이 있는데, 이 버튼을 통해서 맵&리듀스에 의해 생성된 결과를 필터링 할 수 있다. 도큐먼트 ID나 KEY의 범위등 지정해서 pagination등에 활용할 수 있다. 자세한 필터에 대한 내용은 향후에 설명하도록 한다.

 





뷰를 이용하여 다양한 기능 구현하기

이러한 뷰를 이용해서 카우치베이스는 다양한 데이터 조작이 가능한데, 대부분의 NoSQL은 키밸류 형태로 RDBMS에서 지원하는 Indexing, Grouping, Sorting 등 강력한 기능을 지원하지 않는 경우가 많다. 카우치베이스에서는 뷰를 이용해서 이러한 기능등을 구현할 수 가 있다.


Indexing 

RDBMS의 Index와 같은 개념으로, 도큐먼트 ID이외에 다른 필드로 검색이 가능하게 해주는 기능이다. NoSQL에서는 이를 Secondary Index라고도 부르는데, Secondary Index를 지원하는 다른 NoSQL의 경우, 제대로 성능이 나도록 설계되어 있는 경우도 있지만, Secondary Index를 기반으로 검색을 할 경우, 분산된 전체 노드를 FULL SCAN해서 (전체 목록을 뒤져서) 검색 결과를 한 노드로 합쳐서 리턴하는 형태로 구현되어 있는 경우가 있다. (Riak의 예전 Secondary Index의 구조) 이 경우, 전체 노드가 O(N)으로 전체 레코드를 검색해야 하기 때문에, 전체적인 성능 저하가 매우 심하다. 앞에서도 언급했지만, 카우치베이스는 이를 Incremental view의 개념을 사용해서, Secondary Index에 해당 하는 필드를 키로 잡은 새로운 물리적인 테이블을 내부적으로 만들기 때문에, Index를 이용한 검색도 타 NoSQL에 비해서 성능이 좋은 편에 속한다.


Extracting & Filtering

필터링은 SQL문장에서 select where라고 보면 된다. 조건에 맞는 특정한 도큐먼트만 select하는 것이 가능하다.

다음과 같은 도규먼트들이 버킷에 저장되어 있다고 할때

{

   "name": "yuna",

   "country": "us",

   "ssn": "140515-1234123",

   "sex": "female"

}

여기서 country="us" 인 것만을 쿼리하고, 전체 필드중 일부 필드(컬럼)만을 가지고 리턴하는 뷰를 만들려고 하면, 다음과 같은 맵 함수를 이용하면 된다.
function (doc, meta) {
  if(doc.country=="us") emit(doc.name,doc.country,doc.ssn);
}
emit에 오는 첫번째 필드가 KEY로 사용된다. 
단 뷰 함수에 의해서 필터링이 된 경우에는 물리적인 Index가 생기기 때문에, country를 Korea,Canada등과 같이 동적으로 변경하는 것이 불가능하다.
이런 동적인 필터링은 카우치베이스의 필터를 이용해서 가능한데, 동적으로 나라에 따라서 필터링을 하고 싶다면, 조건을 적용할 필드를 키로 리턴한 후, 키에 대한 필터링을 하면 되는데, 다음과 같이 맵 함수를 작성한 후에 뷰를 생성하고
function (doc, meta) {
  emit(doc.country,doc.name,doc.ssn);
}
아래와 같이 필터 조건에 key를 "us"로 지정하면 doc.country가 "us" 인 도큐먼트만 쿼리가 된다.
※ 문자열은 반드시 "" 을 사용해서 지정해야 한다.


Sorting
카우치베이스에서 소팅은 뷰의 키값을 기반으로 한다. 소팅의 기준으로 하고자하는 필드를 KEY로 잡으면, 뷰에서는 디폴트로 오름차순으로 키에 따라 정렬을 해준다. 내림 차순으로 정렬을 하기 위해서는 위의 필터에서 descending이라는 옵션을 체크 해주면 된다.

리듀스(Reduce)함수를 이용한 Grouping 연산
Grouping은 RDBMS의 group by와 유사한 기능으로 같은 country인 도큐먼트 수를 카운트하거나, 태어난 해별 사용자 수를 하는 것과 같은 그룹 단위의 연산을 할 수 있다.
먼저 Grouping의 개념을 사용하기 위해서는 Compound Key라는 개념을 이해해야 하는데, 카우치베이스의 Grouping 연산은 이 Compound Key를 기본으로 한다. Compound Key랑 뷰의 키를 [] (배열) 형태로 정의한 경우이다. 예를 들어 키를
["Country","생년","성별"] 과 같은 형태의 배열 형태로 정의하는 것이다. Grouping은 이 Compound Key의 Level 단위 (즉 배열의 첫번째 값으로만 그룹을 만들것인가? 아니면 첫번째,두번째 값을 포함해서 그룹으로 잡을 것인가) 로 처리한다.
실제 예제를 살펴보자. 다음과 같은 JSON 도큐먼트가 있을때,
{
   "name": "yuna",
   "country": "us",
   "ssn": "140515-1234123",
   "sex": "female"
}
앞에서 언급한 형태의 Compound Key를 만드는 함수는 다음과 같다, 
function (doc, meta) {
  var year = doc.ssn.substring(0,2);
  emit([doc.country,year,doc.sex],1);
}
이 맵함수를 이용하면 뷰는 다음과 같아진다.
["canada","69","male"] 1
["korea","75","male"] 1
["us","08","female"] 1
["us","14","female"] 1
["us","75","female"] 1
그러면 국가별로 사용자 수를 통계를 내려면, 리듀스 함수에 "_count" 라고 정의하고
필터에 group 옵션을 선택한후에, group level을 1로 지정한다.

이렇게 하면, Compound Key의 첫번째 필드 (country)를 기반으로 그룹핑을 하고, 리듀스 함수에서 이 그룹단위로 _count 연산을 수행한다.

카우치베이스에는 리듀스함수에서 사용할 수 있는 기본적인 함수를 미리 정의해놨는데, 아래와 같다.

  • _sum : 밸류값을 더한다. (밸류 타입이 Integer라야 함)
  • _count : 그룹별로 묶인 값들의 수를 카운트 한다.
  • _stats : 각종 그룹값을 계산해준다, 위에서 나온 sum뿐만 아니라, sum,count,min(최소값),max(최대값),sumsqr(Sum of square : 제곱합) 값을 출력해준다.
Pagination 
뷰에서 만들어진 데이타는 쿼리시에 pagination을 지원할 수 있다. 필터를 통해서, 뷰의 start/end key값을 정의하거나, start/end 도큐먼트ID를 지정하면 그 범위내의 도큐먼트만 쿼리할 수 있다. (위의 필터 설정 그림 참고) 콘솔에서는 나와 있지 않지만 필터에 추가로 limit라는 옵션을 주면, 최대한 읽어올 수 있는 도큐먼트 수를 정의할 수 있다.
예를 들어 뷰의 키로 1~100까지 100개의 도큐먼트가 있을때, start key=11,end key=50으로 하면 11~50까지의 50개의 레코드가 리턴된다. 여기에 limit=10을 추가하면 11~20까지의 레코드만 리턴되낟. start/end와 limit를 적절하게 사용하면 페이징 기능을 구현할 수 있다. limit를 설정하는 방법은 SDK를 이용하여 뷰를 호출하는 방법에서 알아보도록 한다.

다음번에는 SDK를 이용해서 뷰를 생성하고, 뷰에 대한 쿼리를 수행하는 방법에 대해서 알아보도록 하겠다.









저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

Couchbase bulk insert

클라우드 컴퓨팅 & NoSQL/CouchBase | 2014.07.11 16:50 | Posted by 조대협
BulkInsert
C:\dev\tools\couchbase\server\bin\tools>cbdocloader -u Administrator -p asdf1234
 -n 127.0.0.1:8091 -b mybucket .\json_sample
{'username': 'Administrator', 'node': '127.0.0.1:8091', 'password': 'asdf1234',
'bucket': 'mybucket', 'ram_quota': 100} ['.\\json_sample']
[2014-07-11 10:20:09,105] - [rest_client] [4288] - INFO - existing buckets : [u'
beer-sample', u'blog', u'default', u'filtering', u'mybucket', u'sortedkey']
[2014-07-11 10:20:09,107] - [rest_client] [4288] - INFO - found bucket mybucket
done


JSON 파일은 ./json_sample/xxx.json 들로 쭈욱 저장되어 있음

{

"_id":"bulkuser001",

"name":"terry"

}



저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

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 명령어도 증가가 아니라 값을 감소 시킨다는 점에서 사용법은 동일하다.


저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

Couchbase Server

#2 기본 개념 잡기

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

개념 잡기


카우치베이스 서버 설치가 끝났으면 기본적인 개념을 잡아보도록 하자.


Document 기반의 Key-Value 스토어


카우치 베이스느 키, 밸류 스토어이다 하나의 유니크(Unique)한 키에, 값을 저장하는 방식이다. 저장 되는 값은 JSON 도큐먼트가 저장된다. 키는 최대 250 바이트, (밸류)의 경우에는 카우치베이스 버킷의 경우 20MB, Memcached 방식의 버킷의 경우 1MB 까지 저장이 가능하다.

저장할때, 키와 값뿐만 아니라 메타데이타가 같이 저장되는데, 메타 데이타에는 CAS,TTL,Flag 3가지가 저장된다.

저장할때, 키와 값뿐만 아니라 메타데이타가 같이 저장되는데, 메타 데이타에는 CAS,TTL,Flag 값 3가지가 저장된다.

CAS는 데이타에 대한 일종의 타임 스탬프와 같은 개념으로, 여러 클라이언트가 같이 데이타를 ACCESS 했을때, 일관성(Consistent) 문제가 생기는 것을 해결해줄 수 있다. (자세한 내용은 나중에 설명한다.)

TTL 은 Time To Live 로, 데이타의 유효 시간을 정의한다. TTL을 정의해놓은 데이타는 TTL 시간이 지나면 자동으로 삭제 된다.

FLAG는 카우치베이스 클라이언트에서 사용하는 메타데이타 이다. 

이러한 메타데이타는 하나의 메타데이타 (CAS,TTL,Flag)는  60바이트의 메모리를 차지하게 된다.

카우치베이스 server는 모든 Key와 메타데이타를 메모리에 유지하기 때문에 데이터 모델링 또는 용량을 설계할때, 이 부분을 고려해서 RAM의 사이즈를 결정해야 한다.


버킷(Bucket)


버킷은 일종의 RDBMS의 데이타베이스 같은 공간이다. JSON 도큐먼트들은 이 버킷에 저장된다.

각각의 버킷은 고유의 속성 값을 가지고 있다. 버킷별 사용할 수 있는 메모리양, 옵션으로 버킷별로 접근할 수 있는 TCP 포트를 지정하거나, 접근 비밀번호를 지정할 수 있으며, 버킷에 들어가는 데이타에 대한 복제본의 수등을 정의할 수 있다.

하나의 클러스터에서 버킷은 최대 128개까지 생성할 수 있으나, 보통 성능상 10개를 권장한다.

http://docs.couchbase.com/couchbase-manual-2.0/#setting-maximum-buckets-for-clusters


뷰(View)


카우치베이스의 강력한 기능중의 하나인데, 이 뷰를 이용해서 RDBMS에서 제공되는 Indexing, grouping, sorting등을 가능하게 한다. 이 뷰는 데이타베이스 뷰와 유사한 개념을 갖는데, 카우치베이스의 뷰는 인크리멘탈 뷰 (Incremental view)라는 컨셉을 가지고 있다.

예를 들어 설명해보자. 사용자 정보를 저장하는 버킷에서, 사용자 정보를 저장하는 JSON 도큐먼트 안에 SSN(Social Security Number)라는 이름으로 주민등록 번호를 저장하는 필드가 있고, 이 주민등록 번호 필드에서 80년생 이하만 저장하는 뷰를 만든다고 하자.

데이타가 버킷에 저장될 때마다, 생성된 뷰에 같이 저장되는데, 이때, 뷰코드(View Code)라는 로직을 통해서 뷰에 저장된다. 뷰코드는 자바스크립트로 작성된 코드이다. 뷰코드에서 주민등록 번호가 80년생 이하일 경우에만 뷰에 저장하도록 정의한다.

 


결과적으로 데이타를 저장하거나 업데이트할때, 이 뷰코드가 매번 수행되게 되고 (마치 RDBMS의 트리거 처럼), 뷰코드에 정의된 알고리즘에 따라서 뷰에 데이타를 업데이트하게 된다.

이렇게 데이타가 저장/업데이트될때 마다 뷰를 증분적(Incremental)하게 업데이트 하기 때문에, 인크리멘탈 뷰라고 하며, 실제로 저장된 데이타가 많다고 하더라도 뷰에는 데이타가 업데이트 될때 하나만 추가/수정 되기 때문에 실제로 카우치베이스가 받는 로드는 그리 크지 않기 때문에, Indexing, grouping, sorting등에 사용한다 하더라도 성능상에 큰 문제를 가지지 않고 사용할 수 있는 것이다.


카우치베이스 시작하기


대략적인 개념을 잡았으면, 이제 카우치베이스를 직접 사용해보도록 하자. 


버킷 생성하기


버킷을 생성하기 위해서는 카우치베이스 웹콘솔에서 상단 “Data Buckets”를 선택한후 “Create New Data Bucket”을 선택한다.

 


버킷 생성을 선택하면 아래와 같이 버킷 생성 창이 나오는데, 버킷 이름을 “mybucket”이라고  지정하고,  개발 테스트용으로만 사용할 것이기 때문에, 이 버킷에서 사용할 메모리를 최소 사이즈인 100메가로 설정한후 버킷을 생성한다.

 



데이타 핸들링


버킷이 생성되었으면, 해당 버킷에 직접 데이타를 저장,조회,수정,삭제를 해보도록 하자.

앞에서 생성한 버킷의 우측 부분을 보면 “Documents”라는 버튼이 나온다. 이 버튼을 누르면, 현재 저장되어 있는 도큐먼트들을 보거나 또는 생성,수정,삭제 등이 가능하다.

“Create Document” 버튼을 누른후, 

Document ID에 “user0001”이라고 입력한다.

그리고 아래 그림과 같이 JSON 도큐먼트를 입력하고 Save 버튼을 누른다.


 

이때 주의할점은 카우치베이스에서 JSON 도큐먼트를 정의할때, 문자열은 “로 감싸야 한다. 일반 자바스크립트처럼 ‘로 감쌀 경우 에러가 나온다.

 


조회는 위의 보이는 Documents 메뉴창에서 Lookup Id를 선택하고, 도큐먼트 ID를 넣으면 해당 도큐먼트를 조회할 수 있고, 위의 도큐먼트 좌측에 보이는 “Edit Document”와 “Delete” 버튼을 이용하면, 수정 및 삭제를 할 수 있다.



저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

Couchbase Server

#1 소개 및 설치

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


근래에 여러 NoSQL이 소개되었지만 그중에서 좋은 솔루션인데도 불구하고 그다지 국내에서는 널리 알려지지 않은 카우치베이스에 대해서 소개하고자한다. 모바일 게임중에 유명한 쿠키런의 경우 카우치베이스를 백엔드로 사용하고 있는데, 안정성이나 성능등이 매우 뛰어나고, 사용하기 또한 매우 쉽다. 오늘은 고성능 NoSQL 서버인 카우치베이스(CouchBase) 에 대해서 소개하고자 한다.


소개


예전에 메모리 캐쉬 솔루션인 memcached에 디스크 persistence 기능을 추가하여 membase라는 솔루션이 있었는데, 이 제품에 Apache의 카우치디비(CouchDB)를 기반으로 새롭게 만든 솔루션이 카우치베이스 Server 라는 NoSQL 솔루션이다.

카우치베이스는 mongoDB나, Riak과 같이 JSON document를 직접 저장할 수 있는 Document DB 형태를 가지며, NoSQL의 분산 이론인 CAP theorem에서 CP (Consistency & Partition tolerance) 의 부분에 해당하여 데이타에 대한 일관성과, 노드간의 네트워크 장애시에도 서비스를 제공할 수 있다. 근래에 들어서 600억원의 투자를 유치하는 등 가치를 인정 받고 있는데, mongoDB나 Cassandra에 가려서 그다지 주목을 받지 못하는 것 같아서, 이번 글을 통해서 소개하고자한다.


특장점


카우치 베이스는 다른 NoSQL에 비해서 다음과 같은 추가적인 특징을 더 가지고 있다.


Memcached 기반의 Level 2 캐쉬를 내장하여 빠름

카우치베이스는 앞에서도 설명하였듯이 membase를 기반으로 하였기 때문에, memcached를 자체적으로 Level 2 캐쉬로 사용하고 있다. 즉 자체적으로 메모리 캐쉬 기능을 가지고 있기 때문에 성능이 대단히 빠르다. 이번에 카우치베이스 社에서 발표한 자료에 따르면 mongoDB대비 약 6배 이상의 성능을 낸다고 한다. 


(http://info.couchbase.com/2014-Benchmark-Showdown-Results-LP.html)


모바일 디바이스와 Sync

카우치베이스 뿐만 아니라, 카우치디비 계열 DB들은 iPhone이나 Android와 같은 모바일 디바이스에 탑재 할 수 있고, 서버에 설치되 카우치디비 계열들과 Sync가 가능하다. 카우치베이스도 역시, 카우치디비 계열이기 때문에, 모바일 디바이스에 탑재할 수 있고, 서버와 Sync할 수 가 있다.


데이타 센터간 복제 가능

카우치베이스는 XACR(Cross Data Center Replication)이라는 기능을 이용하여, 물리적으로 떨어진 데이타 센터간에 데이타 복제가 가능하다.


Indexing, Grouping ,Ordering,Join 가능

아주 중요한 특징중의 하나인데, 대부분의 NoSQL은 Key/Value Store 형식으로, 개별 필드에 대한 Indexing이나, 필드별로 group by 를 해서 sum,count등을 하는 기능이나, 특정 필드별로 Sorting이 불가능하다. Indexing을 지원하는 경우도 있기는 하지만, 내부적으로 성능상 문제가 있는 경우가 많은데, 카우치베이스의 경우 이러한 성능상 문제를 해결 하면서도 RDBMS들이 지원하는 index, grouping, ordering 기능을 지원할 수 있다. 


확장이 쉬움

보통 분산 구조의 NoSQL의 경우, 노드를 확장하거나 특정 노드가 장애가 났을때의 처리가 어려운데, 카우치베이스는 장애가 손쉽게 장애 처리를 하고,새로운 노드를 추가할때 도 매우 쉽게 노드 추가가 가능하다. 이러한 장점은 운영 관점에서 큰 이점이 된다.


Built in 관리 도구 제공

마지막으로 카우치베이스는 웹 기반의 GUI 관리 도구를 기본으로 제공한다. 많은 NoSQL들이 별도의 관리, 모니터링 도구를 지원하지 않는데 반하여, 기본적으로 강력한 관리 도구를 제공하는 것은 큰 장점이 될 수 있다.


Memcached 프로토콜 지원

캐쉬 솔루션으로 유명한 Memcached 프로토콜을 그대로 지원하기 때문에, 기존의 Memcached 클라이언트를 그대로 사용할 수 있고, 기존에 사용하던 Memcached 인프라를 그대로 대체 할 수 있다.


스키마가 없는 유연한 저장 구조 (Scheme-less)

 스키마가 없는 구조는 카우치베이스뿐만 아니라 대부분의 NoSQL이 갖는 공통적인 특성이다. 스키마가 없기 때문에 하나의 테이블에 컬럼 형식이 다른 데이타를 넣을 수 있다. 즉 하나의 데이타 버켓에 데이타 구조가 다른 JSON 문서들을 넣을 수 있다는 이야기이다.

데이타 타입이 다름에도 불구하고, 공통되는 필드에 대해서, Indexing, grouping 등을 제공할 수 있다. JSON 도큐먼트에, county 라는 앨리먼트가 있는 도큐먼트들을 대상으로 grouping등을 할 수 있다는 이야기이다.

다양한 클라이언트 플랫폼 지원

자바,닷넷,PHP,루비,C,파이썬,node.js 등 다양한 클라이언트 라이브러리를 제공한다. 클라이언트 SDK는 http://www.couchbase.com/communities/all-client-libraries 에서 다운로드 받을 수 있다.


설치하기


카우치베이스를 설치하기 위해서는 www.couchbase.com에서 카우치베이스를 맞는 OS 플랫폼에 따라서 다운로드 받으면 된다. Enterprise Edition과 Community Edition이 있는데, Enterprise Edition은 별도의 상용 라이센스를 구입해야 하며 기술 지원등을 받을 수 있다. Community Edition은 무료로 개발이나 운영 환경에 사용할 수 있으나, 기술 지원등을 받을 수 없고,  Enterprise Edition에 비해서 버전이 낮다.

※ 참고로, 상용과 오픈소스 라이센스 정책을 함께 지원하는 솔루션의 경우에는 버전업이 되면서 라이센스 정책이 갑자기 바뀌는 경우가 많으니, 오픈소스의 경우 다운로드 전에 반드시 라이센스 정책을 확인하기를 바란다. 이 글을 쓰는 현재 Community Edition의 라이센스 정책 기준은 2.2.0을 기준으로 한다. 

여기서는 윈도우즈 환경을 기준으로 설명을 한다. 사이트에서 카우치베이스 server 를 다운로드 받고 실행을 하면 자동으로 설치 위자드가 실행되고, 설치가 진행된다.

 


설치가 다 끝나면, 자동으로 웹페이지가 열리면서, 카우치베이스에 대한 셋업이 시작된다.

 


설정 셋업을 시작하면 기본적인 서버 설정에 대해서 물어보는데

 


데이타 파일을 저장하는 경로와, 호스트명등을 물어본다.그리고 새로운 클러스터를 시작할지, 아니면 기존의 클러스터에 조인할지를 물어보는데, 여기서는 개인 개발 환경을 설정하는 것이기 때문에, “Start a new cluster”로 설정한다. 이때, 카우치베이스가 사용할 메모리 용량을 지정해야 한다. 개인 개발환경이기 때문에, 1G정도로 설정하자. 실제 운영환경에서는 최대한 크게 잡아줘야 한다. 카우치베이스에 저장되는 키와 데이타에 대한 메타 데이타는 모두 메모리로 로딩되기 때문에, 메모리 용량이 충분하지 않으면 제대로된 성능을 발휘할 수 없다.

인스톨이 완료된후에, 카우치베이스 웹 콘솔을 열어 보면, 다음과 같이 인스톨된 카우치베이스 서버의 상태를 볼 수 있다. 

 




저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
 

티스토리 툴바