Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Contents

Eventual Consitency

CouchDB는 데이터의 성장과 변화에 유연하게 대응할 수 있다. 다른 데이터베이스와의 어떤 차이점이 이런 유연함을 가져다 주는지 살펴보려고 한다. 결과적으로 couchdb를 이용해서 간단하게 확장 가능한 분산 시스템을 구축하기 위한 아이디어를 얻게 될 것이다.

분산 시스템은 넓은 네트워크위에서 견고하게 운영을 하기 위한 시스템이다. 하지만 네트워크의 특성상 견고하게 운영하기가 여간 어려운게 아니다. 네트워크는 "사라질 수 있거나", "상당한 시간 지연이 생길 수 있다는" 잠재적인 문제점을 가지고 있기 때문이다. 이러한 네트워크 위에서 분산된 견고한 시스템을 구축하기 위해서는 전략적 선택과 집중이 필요하다.

CAP 이론

CAP 이론(theorem)은 네트워크를 통해서, 분산 애플리케이션 시스템을 구성하기 위한 몇 가지의 다른 전략을 설명하고 있다. CouchDB은 분산 시스템에 참여하는 여러 노드들에 변경된 내용을 전파해서, 분산된 복제본을 만드는 전략을 사용한다. CouchDB는 RDBMS와 비교하자면, consistency(동시성), availability(가용성), partition tolerance(파티션 허용차)에 대해서 서로 다른 접근 방식을 사용한다.

동시성, 가용성, 파티션 허용차는 CAP 이론은 분산 컴퓨팅 시스템이 가져야 하는 3가지 특성이다.
  • 동시성 : 모든 노드들은 동일한 데이터를 가지고 있어야 한다.
  • 가용성 : 모든 노드들은 읽기와 쓰기를 항상 가능해야 한다.
  • 파티션 허용차 : 물리적인 네트워크 파티션을 넘어서 작동해야 한다.
하나의 데이터베이스 노드가 처리할 수 없을 만큼 데이터가 늘어날 때, 이 문제를 해결하는 가장 좋은 방법은 데이터를 처리할 노드를 늘리는 것이다. 일단 새로운 노드가 추가되면, 1. 노드들 사이에 어떻게 데이터를 분할 할지(파티션 허용차), 2. 노드들이 정확히 동일한 데이터들을 서로가 공유할지, 아니면 데이터를 나눠서 서로 다른 데이터를 관리하게 할지를 결정해야 한다(동시성). 3. 그리고 모든 노드들이 읽기와 쓰기가 가능하게 할지, 아니면 읽기와 쓰기가 가능한 노드와 읽기만 가능한 노드를 분리할지 결정해야 한다(가용성).

데이터베이스 시스템들 간에 차이가 발생하는 이유는 위의 3요소를 모두 보장하는 것이 불가능 하기 때문이다. 데이터베이스는 두 개만 보장할 수 있다. 하나는 포기해야 한다. 어떤 걸 포기하고, 어떤걸 가져가느냐에 따라서 차이가 발생한다. 여기에 대해서는 Nathan Hurst가 개발한 Visual Guide to NoSQL Systems에 데이터베이스 타입별로 잘 정리돼 있다.

C(Consistent)의 보장이 중요한 데이터베이스 시스템이 있다고 가정해 보자. 이 데이터베이스는 모든 유저가 동일한 데이터를 볼 수 있다는 것을 보장해야 한다. C를 보장하는 가장 확실한 방법은 데이터베이스에 한번에 하나의 노드만 접근할 수 있도록 Lock을 거는 거다.

A(availability)가 중요한 데이터베이스 시스템은 클라이언트가 기다림 없이 즉시 데이터를 읽고/쓸수 있어야 한다. RDBMS는 C와 A를 만족한다. 기다림 없이 즉시 데이터를 읽고쓰면서, 모든 클라이언트가 동일한 데이터를 읽을 수 있게 해야 한다. 이렇게 되면 당연하게 P를 만족하기가 어려워진다. 물리적으로 멀리 떨어져 있으면, 노드들간 consistent를 유지하기 위한 기다림이 발생할 수 밖에 없기 때문이다.

CouchDB는 AP를 만족하는 데이터베이스 시스템이다. 물리적으로 분리된 네트워크 상에서도 잘 작동해야 하고, 각 네트워크에 흩어져 있는 모든 노드에서 읽기와 쓰기가 가능하게 하는 것을 목적으로 한다. 이를 위해서 consistent를 포기한다. 클라이언트 마다 서로 다른 데이터를 볼 수 있다는 의미다. 따라서 잠금 없이데이터를 읽고/쓰는 것이 가능하다. 물론 consistent를 포기함으로 써, 필연적으로 충돌(conflict)이 발생하는데, 충돌은 버전을 관리하는 것으로 애플리케이션 영역에서 해결한다.

Consistent를 보장하지 않는게, 심각한 문제일 수도 있지만 항상 문제가 되는 건 아니다. CMS와 CRM처럼 Consistent가 중요하지 않는 형태의 데이터도 있다. 실제 CouchDB는 CRM과 CMS시스템 구축에 적당한 데이터베이스다.

CAP 이론에서는 하나의 데이터베이스 시스템이 2개의 요소만을 만족한다고 나왔는데, 이는 나머지 하나를 배제하겠다는 의미가 아니다. RDBMS의 경우 CAP 이론에서는 CA를 보장하는데, P를 아예 배제하겠다는 의미가 아니다. 예컨데, Mysql도 분리된 네트워크에서의 작동을 지원하기 위해서 asynchronous한 replication을 지원한다. 단 이렇게 할 경우 CA의 특성이 깨질 수 있기 때문에 별도의 운영/관리 비용이 들어간다. 그러니까 P를 배제하는게 아닌, P가 자연스럽게 녹아들어 갈 수 있는 데이터베이스가 아니다라는 의미로 받아들어야 할 것이다.

Local Consistency

CouchDB가 cluster상에서 어떻게 작동하는 지를 이해하기 전에, 단일 CouchDB 노드에서 어떻게 작동하는지를 우선 이해할 필요가 있다. CouchDB API는 데이터베이스 core를 모르더라도 편리하게 사용할 수 있지만, CouchDB API의 작동원리를 확실히 이해하기 위해서 core 부분을 살펴볼 것이다.

데이터의 Key

CouchDB는 스토리지 엔진으로 B-tree를 이용한다. B-tree는 로그 시간에, 검색, 삽입, 삭제를 가능하도록 정렬된 데이터 구조를 만든다. 아래는 B-tree의 작동 방식을 보여주는 비디오다.

아래 그림은 CouchDB가 B-tree를 이용해서 문서에 대한 view를 어떻게 만드는지를 보여준다. 아래 그림을 이해한다면, CouchDB의 view에 대한 모든 이해를 마친거라고 장담할 수 있다.

http://docs.couchdb.org/en/latest/_images/intro-consistency-02.png

CouchDB는 MapReduce를 이용해서 view의 결과를 계산한다. MapReduce는 "map"과 "reduce" 두개의 함수로 구성되는데, 각 문서에 개별적으로 적용된다. 문서에 개별적으로 적용되기 때문에, 병렬 계산이 가능하다. CouchDB는 B-tree에 댇이터를 넣을 때, Key로 정렬을 하는데 이는 MapReduce의 key/value를 이용한 MR연산에 적합한 구성이다. 이러한 구성은 O(log N) 혹은 O(log N+K)의 연산을 가능하게 한다.

Key로 정렬이 되고, 여기에 MR을 적용할 수 있기 때문에 각 노드를 독립적으로 조회할 수 있다. 노드를 분산하고, 각 노드에서 독립적으로 조회를 함으로써 높은 확장성과 성능상의 잇점을 얻을 수 있다.

No Locking

RDBMS에서 테이블은 하나의 데이터 구조물이다. 만약 테이블을 수정하려고 한다면, 예를들어 특정 row에 대해서 update를 수행하려 하면, 데이터베이스 시스템은 row에 대한 update가 끝나기 전까지, 누구도 그 행을 읽고 업데이트 할 수 없도록 해야 한다. 일반적으로 잠금(lock)를 이용한다. 다수의 클라이언트가 접근하는 테이블에서 첫번째 클라이언트가 lock을 하면 나머지 클라이언트들은 lock가 해제될 때까지 기다려야 한다. 요청이 병렬로 도착하더라도 하나씩 밖에 처리할 수 없다는 이야기. 요청이 많은 서비스 일 수록, 데이터베이스는 실제 작업처리 보다 어떤 작업을 처리해야 할지를 확인하는데, 더 많은 시간을 보낸다.

현대적인 RDBMS는 데이터베이스 엔진에서 MVCC를 구현해서 잠금을 피할 수 있다. 이 경우 하나의 행이나 하나의 필드에 대한 동시 변경 요구를 최종 사용자로 부터 숨길 수 있다. The basics of the InnoDB undo logging and history system 참고

CouchDB는 잠금을 거는대신에 MVCC를 이용해서 데이터베이스에 대한 동시접근을 관리한다. 아래 그림은 MVCC를 이용해서 어떻게 잠금 없이 동시접근을 관리하는지를 보여준다.

CouchDB는 잠금이 필요 없는 MVCC 모델을 따르기 때문에, 고 부하(high load)상황에서도 최고의 성능을 보장한다. CouchDB는 문서의 버전을 관리하는데, 관리 방법은 Subversion 이나 GIT과 같은 일반적인 버전 관리 시스템과 매우 비슷하다. 만약 사용자가 문서에서 어떤 값을 변경하면, 이 버전의 문서로 부터 새로운 버전의 문서가 만들어진다.

잠금없이 어떻게 문서를 관리할 수 있는지 살펴보자. 유저가 문서를 읽어서, 작업을 하고 있다. 이때 두번째 유저가 문서를 변경했다고 가정하자. 두번째 유저의 문서 변경 요청은 완전히 새로운 버전의 문서를 만들기 때문에, 다른 유저의 요청이 완료될 때까지 기다릴 필요 없이 데이터베이스에 쓸 수 있다.

이제 새로운 세번째 요청이 들어오면, CouchDB는 가장 최신 버전의 문서를 돌려준다. 현재 작업중인 문서는 최신 버전의 문서이지만, 첫번째 문서의 작업자는 여전히 자신의 문서버전에서 작업을 진행할 수 있다.

Validation

애플리케이션 개발자들은 받아들여도 되는 입력과 그렇지 않은 입력의 유효성 검사하기 위한 방법에 대해서 항상 고민해야 한다. 기존의 관계형 데이터베이스는 (오랜 역사를 가진 만큼) 복잡한 데이터들에 대해서 검증할 수 있는 다양한 방법들을 가지고 있다. 다행히도 couchdb는 각 문서단위로 검사를 수행할 수 있는 강력한 수단을 가지고 있다.

CouchDB는 Javascript를 이용해서 개발하는 MapReduce와 비슷한 방법으로 문서 유효성을 검사할 수 있다. CouchDB는 문서가 수정될 때마다 "유효성 검증 함수(validation function)"를 실행해서 새 문서의 유효성을 확인할 수 있다. 유효성 검증 함수는 이전문서에서 유저인증과 같은 세부적인 정보를 추출해서 새 문서의 업데이트를 허가해도 될지를 검사한다. 이 기능은 아직 확인하지 못했다. 테스트 해봐야 겠다.

관계형 데이터베이스의 경우 애플리케이션 영역에서 이러한 작업을 수행해야 하는데, 보통 이런 작업들은 많은 코드와 CPU 작업을 필요로 한다. CouchDB를 이용하면 더 작은 코드를 이용해서 더 효율적으로 유효성을 검증할 수 있다.

Distributed Consistency

하나의 데이터베이스 노드에서 데이터의 일관성을 유지하는 것은 그리 어렵지않다. 문제는 여러 데이터베이스 서버 사이에 일관성을 유지하는 거다. 유저가 A 서버에서 작업을 할 경우 B, C, D등 다른 서버에도 작업한 내용이 동일하게 적용돼야 한다. RDBMS에 있어서 이 문제는 매우 풀기 어려운 문제다. Multi-master, master/slave, partitioning, sharding, write-through cachee 등등 다양한 종류의 복잡한 기술들을 동원해야 한다.

Incremental Replication

CouchDB는 멀티 데이터베이스간에 eventual consistency를 지원한다. 이는 데이터의 일관성을 유지하기 위해서 데이터베이스 노드들이 계속 통신을 연결할 필요가 없다는 것을 의미한다. 필요 할 때 새로 추가된(incremental) 문서만 복제(replication)하면 되기 때문이다.

CouchDB 데이터베이스 클러스터의 scale out이 필요하다면 ? 그냥 새로운 서버를 하나 만들기만 하면 된다.

클라이언트는 각자의 노드에서 데이터를 변경하면, 이후 주기적인(cron) replication 작업을 통해서 데이터를 동기화 한다. 각 노드들은 완전히 독립적으로 작동하기 때문에, 다른 노드들의 가용성을 고민할 필요가 없다. 심지어 offline에서라도 작업에 문제가 없다.

SVN이나 GIT에서 버전간 충돌이 발생하는 것과 마찬가지의 이유로 충돌(conflict)가 발생할 수 있다. CouchDB는 충돌이 발생한 데이터를 모두 보관한다. 이들 충돌은 애플리케이션 영역에서 해결할 수 있다.

응용 사례

CouchDB 기반의 Moniwiki

Moniwiki를 확장이 용이한 CMS 시스템으로 만들려고 한다. 지금의 Moniwiki는 파일 시스템 기반이라서 확장에 한계가 있어서, CouchDB 기반으로 만들기로 했다.

참고