[MongoDB in Action] 최신 웹을 위한 도큐먼트 데이터베이스
이 내용은 몽고디비 인 액션 2nd Edition 책을 읽고 개인적으로 정리한 내용입니다.
MongoDB의 역사, 설계 목표, 핵심 기능
MongoDB는 웹 애플리케이션과 인터넷 기반을 위해 설계된 데이터베이스 관리 시스템이다.
직관적인 데이터 모델
MongoDB의 도큐먼트 형식은 JSON에 기반한다. key-value로 이루어져 있고, 중첩에 제한이 없다. 내부적으로 Binary Json
혹은 Bson
의 형태로 도큐먼트를 저장한다. document는 collection
에 저장된다. collection에 있는 데이터는 디스크로 저장된다.
{
_id : 10,
username: 'peter',
email: 'sunmin@gmail.com'
}
관계형 데이터베이스라면, user 정보를 담고있는 테이블 하나와, email 정보를 담고있는 테이블을 생성해서 조인해서 사용해야 했겠지만, document 식의 데이터는 아래와 같이 구성할 수 있다.
{
_id : 10,
username: 'peter',
email: ['sunmin@gmail.com', 'sunmin@naver.com']
}
개발자로서 데이터의 변경이 발생했을 때, 테이블을 추가하거나 스키마를 맞춰야 하는 걱정 없이 document 구조를 마음대로 변경할 수 있다는 것이 장점이다.
이러한 도큐먼트 지향적인 모델에서는 객체를 자연스럽게 모아 놓은 형태로 표현함으로써 객체를 전체적으로 작업할 수 있다. (정규화된 테이블로 나눠서 조인하지 않아도 된다)
- Application 이 데이터 구조를 정하므로 데이터 구조가 빈번히 변경되는 개발 초기 단계에서 개발 속도를 단축시켜 준다.
- 가변적인 속성을 갖는 데이터를 표현할 수 있다. (특정 컬럼에 varchar, integer 아무 형태나 들어올 수 있다)
단순한 key-value의 쿼리가 아닌, SQL
쿼리 처럼 애드혹 쿼리
를 지원한다.
// $gt 와 같이 특별한 조건을 넣을 수 있다.
db.posts.find({'tags': 'politics', 'vote_count': {'$gt': 10}});
인덱스
MongoDB에서 인덱스는 B-tree
로 구현되어 있다. 고유 식별자로 primary key
가 있고, 다른 필드들을 secondary index
로 구성해서 사용자가 넓은 범위의 쿼리를 최적화하도록 허용한다.
MongoDB에서는 한 컬렉션에 64개까지 세컨더리 인덱스를 만들 수 있다. 오름차순, 내림차순, unique, compound-key, 해시, 텍스트, 심지어 지리공간적 인덱스와 같이 다양한 인덱스가 가능하다.
복제
Replica set 이라고 부르는 구성을 통해 failover 기능을 제공한다. 또한 Replica는 데이터베이스 읽기에 대한 확장을 위해서도 사용된다.
각각 분리된 물리장비에 Mongo DB 서버가 띄워져 있고 이를 노드라고 부른다. 이 노드들을 모아둔 것이 Replica-set이다. 마스터-슬레이브
형태를 생각하면 된다.
프라이머리 노드에 대해서는 읽기와 쓰기가 모두 가능하지만 세컨더리 노드는 읽기만 가능하다. 만약 프라이머리 노드에 장애가 발생하면 클러스터는 자동으로 세컨더리 가운데 하나를 선택해서 프라이머리로 설정한다. 여기서 프라이머리가 다시 복구된다 해도 다시 프라이머리로 설정되지는 않는다. 그냥 세컨더리로 작동한다.
속도와 내구성
데이터베이스 시스템에서는 쓰기 속도와 내구성 사이에 역관계가 존재한다.
쓰기 속도는 미리 정해진 시간 내에 데이터베이스가 얼마나 많은 수의 삽입, 수정, 삭제 명령을 처리할 수 있는가를 뜻한다.
내구성은 쓰기 연산이 디스크에 제대로 이루어졌다는 것을 확신할 수 있는 정도를 뜻한다.
예를 들어 Memcached 와 같은 데이터베이스에서는 쓰기가 RAM에서만 이루어져 속도가 빠르지만, 전원이 꺼지면 사라져 버린다. 반면에 디스크에만 쓰기를 하는 데이터베이스는 속도가 너무 느리다. (그래서 쓰기 속도와 내구성은 역관계다)
MongoDB는 쓰기 시맨틱스 (write semantics)와 저널링(journaling)을 통해 속도와 내구성 사이에서 타협을 했다.
fire-and-forget
모드로 몽고DB를 실행하면 확인(ack)을 기다릴 필요 없이 서버에 쓰기 작업을 전송할 수 있다. safe
모드로, commit이 되었는지 확인하기 전에 다수의 복제 노드들에 대한 쓰기를 보장하도록 설정할 수도 있다.
기본적으로 fire-and-forget
모드가 기본적으로 설정되어 있다. 따라서 database 의 종류에 따라서 mode를 설정하는게 중요하겠다.
저널링은 모든 쓰기에 대한 로그를 100ms마다 한 번씩 저널 파일에 기록한다. 서버가 셧다운되면 저널은 MongoDB 파일을 복구해서 서버를 재시작할 때 원래의 상태를 유지하는데 이용된다.
INFO : MySQL의 InnoDB에도 트랜잭션 로그를 디스크에 동기화해서, 서버 재시작 시 트랜잭션 로그로 주 데이터 파일을 업데이트하게 한다.
쓰기 부하가 있다면 성능 향상을 위해 저널링을 하지 않은 채 서버를 실행할 수 있다.
확장
일반적으로 애플리케이션이 하나의 데이터베이스 노드만을 가질 때, 일반적인 경우는 디스크나 메모리 혹은 CPU를 추가해서 데이터베이스 병목 현상을 완화시킬 수 있다. (수직적 확장)
반대로 수평적 확장은 하나의 노드를 업그레이드 하는 것이 아닌, 데이터베이스를 여러 대의 서버에 분산시키는 것을 뜻한다.
몽고DB는 수평적 확장이 용이하도록 설계되었다. 샤딩(sharding)
으로 알려진 range-based
파티션 메커니즘을 통해 데이터를 여러 노드에 걸쳐 분산하는 것을 자동으로 관리해준다.
샤딩 시스템은 샤드 노드를 추가해서 용량을 필요한 만큼 늘리고 자동 장애조치 기능도 제공한다. 각각의 샤드는 최소한 두 개의 노드로 구성된 복제 세트로 이루어져 있어서 어느 한 노드에서도 장애가 발생하지 않은 채 자동으로 복구되도록 보장한다.
댓글남기기