DBMS 는 서로 다른 목적 하에 동작한다.
어떤 DBMS 는 임시적인 hot data 를 처리하는데 사용되고, 어떤 DBMS 는 영구적인 cold storage 를 처리하는데 사용된다.
어떤 DBMS 는 복잡한 쿼리를 통해 데이터에 접근할 수 있고, 어떤 DBMS 는 오직 key 값을 가지고 데이터에 접근한다.
어떤 DBMS 는 시간순으로 들어오는 데이터를 처리하는데 유리하고, 어떤 DBMS 는 매우 큰 blob 데이터를 처리하는데 유리하다.
이런 DBMS 의 차이를 이해하기 위해서는 DBMS 의 아키텍처와 다양한 관점에서의 DBMS 분류에 대해 이해할 필요가 있다.
먼저 이번 글에서는 데이터베이스 아키텍처와 스토리지 엔진에 대해 간단하게 알아본다.
데이터베이스 아키텍처
DBMS 시스템에 대한 공통적인 청사진은 없지만 대체로 Transport / Query Processor / Execution Engine / Storage Engine 4개 레이어로 구성된다.
Transport 계층은 client-server 구조로 되어있는 대부분의 DBMS 인스턴스(node라고도 함)가 서버 역할로서 클라이언트 요청을 받아들이는 과정을 담당한다. 그리고 이 요청은 Query Language 형태로 바뀌어 다음 계층으로 전달된다.
또 Transport 계층은 같은 클러스터 안에 있는 다른 DB node 와 소통하는 역할을 담당하기도 한다.
Query Processor는 SQL을 파싱하고 해석한 뒤, 데이터에 대한 접근 제어 로직을 처리한다.
파싱된 쿼리는 Query Optimizer 로 전달된다.
Query Optimizaer 는 쿼리 실행에 불필요한 부분을 제거하고, 내부 통계를 기반으로 최적의 쿼리 실행 계획(query plan 또는 execution plan)을 찾는다.
Execution Engine은 쿼리 플랜을 기반으로 실제로 쿼리를 처리하는 연산을 수행한다.
Execution Engine은 쿼리 플랜을 local 또는 remote operations 로 실행한 결과를 하나로 모은다.
remote operation은 클러스터 내의 다른 DB 노드에서 데이터를 읽어오는 것과 관련된 연산이다.
그리고 Local Query 는 최종적으로 Storage Engine에 의해 실행된다.
Storage Engine (또는 Database Engine) 은 메모리 또는 디스크에 있는 데이터를 저장하고, 가져오고, 관리하는 역할을 수행하며, 각 노드를 영구적, 장기적 메모리를 저장하도록 설계되어있다.
Storage Engine 은 보통 다음과 같은 요소로 구성되어 있다.
- Transaction Manager : 트랜잭션 관리
- Lock Manager : 실행중인 트랜잭션 내에서 Object 잠금
- Access methods : 디스크에 있는 데이터에 접근하는 것을 관리하며, heap file, B-Tree 또는 LSM Tree 를 포함한다.
- Buffer Manager : 메모리에 데이터를 캐싱한다.
- Recovery Manager : operation 실행 기록을 로그로 남기고, 문제가 발생하면 로그를 기반으로 기록을 복원한다.
Transaction Manager 와 Lock Manager 는 여러 명령어가 병행적으로 들어올 때 물리적, 논리적 데이터 무결성을 보장하는 역할을 담당한다.
스토리지 엔진은 데이터 자체에 집중하여 유저가 레코드에 대해 CRUD를 수행하는데 사용되는 간단한 API 를 제공한다.
DBMS는 Storage Engine 위에 트랜잭션, 인덱싱, 스키마, SQL 등 다양한 기능을 추가하여 만들어진다.
스토리지 엔진이 key, value 를 다룰 때는 정해진 타입 없이 임의의 바이트 시퀀스 형태로 다룬다.
그리고 값을 표현하거나 정렬할 때는 상위의 서브 시스템이 처리한다.
예를 들어 하나의 테이블에서 사용하는 키는 int32 타입일 수도, ascii 타입일 수도 있다.
하지만 스토리지 엔진 입장에서는 그 타입을 신경쓰지 않으며, 둘 다 바이트 시퀀스로 직렬화된 형태로 다룬다.
스토리지 엔진에는 BerkeleyDB, LevelDB 등의 종류가 있고, DBMS 를 개발할 때는 이런 기존의 스토리지 엔진을 활용하여 개발한다.
따라서 원하는 경우 DBMS 에 더 적합한 스토리지 엔진으로 언제든 교체할 수 있다.
예를 들어 MySQL의 경우 InnoDB, MyISAM, RocksDB 와 같은 스토리지 엔진들을 사용한다.
DBMS 의 비교와 선택
데이터베이스는 한번 결정하고 나면 보통 장기적으로 사용된다.
그리고 한번 DBMS 를 길게 사용하면 다른 DBMS로 변경하는 것이 쉽지 않다.
따라서 초기에 어떤 DBMS 를 사용할지 시간을 들여 신중하게 결정하는 것이 중요하다.
모든 DBMS들은 각각이 가진 강점과 약점이 있다.
단순히 인기순위, 사용하고 있는 스토리지 엔진, 구현 언어 등만 고려하기보다 각 DB가 어떻게 동작하고 그 내부에 무엇이 들어있는지 얕게라도 이해하고 선택하는 것이 좋다.
DBMS를 비교하려면 그 전에 명확한 비교 기준부터 세워야 한다.
내가 개발하려는 시스템의 워크로드에 대해 여러 DBMS를 시뮬레이션해보고, 중요하게 생각하는 지표를 활용해서 DBMS를 선별한다.
이때 확장성과 성능 이슈는 데이터가 충분히 쌓이고 DBMS를 오래 사용하면서 서서히 나타나는 문제이므로, DBMS를 시뮬레이션할 때는 최대한 실제 환경과 비슷하게 오랜 시간 테스트를 해야한다.
이렇게 실제 워크로드에 대해 테스트해보면 데이터베이스의 성능, 운영 및 디버깅하는 방법을 이해하는데 도움이 되고, 해당 DB 커뮤니티가 얼마나 잘 형성되어있는지 이해할 수 있다.
(그리고 사실 DB 성능은 그렇게 중요한 비교 기준이 아니다. 느리지만 안정적으로 잘 저장하는 것이 빠르지만 잘 잃어버리는 것보다 낫다.)
DBMS를 비교할 때는 다음 요소를 고려하면 좋다.
- 스키마와 레코드의 크기
- 클라이언트 수
- 쿼리 유형과 엑세스 패턴
- 읽기 / 쓰기 쿼리의 비율
- 위 요소들에 대한 예상되는 변경 사항
그리고 다음 요소를 고려하여 다음과 같은 항목을 점검해보자.
- DBMS가 어플리케이션이 요구하는 형태의 쿼리를 처리할 수 있는가
- DBMS가 어플리케이션이 다루려는 크기의 데이터를 저장하고 다룰 수 있는가
- 하나의 단일 노드가 몇 개의 읽고 쓰는 쿼리를 처리할 수 있는가
- 시스템이 몇 개의 노드를 가져야 하는가
- 어플리케이션의 예상 성장률을 고려할 때, 클러스터를 어떻게 확장하는가
- 유지관리 프로세스가 어떤가
이 요소를 고려하여 워크로드에 대해 DBMS를 시뮬레이션해보고 선택할 수 있으며,
그리고 대부분의 DBMS는 특정 상황에 사용할 수 있는 stress test tool 이 존재한다.
(만약 없다면, 그 DBMS는 주의해야 한다.)
DBMS를 선택했다면, 해당 DBMS를 구현한 코드에 익숙해지면 좋다.
전체 코드를 세세히 알 필요없이, 대략적인 개요의 형태만이라도 이해하면 좋다.
이를 통해 DBMS가 찍는 로그나 설정 값을 보다 쉽게 이해할 수 있고, DBMS를 사용하는 어플리케이션이나 DBMS 자체에서 이슈가 생겼을 때 원인을 찾아내기 쉽기 때문이다.
DBMS를 결정한 이후에도 계속해서 DBMS의 변경사항을 추적하고 이해하면서, 업데이트 전략을 세워야 한다.
새 버전의 DBMS는 기존의 버그를 수정하기도 하지만, 새로운 버그를 안고 있을 수도 있기 때문이다.
DBMS 를 결정할 때는 그 DBMS 가 사용하는 스토리지를 이해하는 것이 중요하다.
스토리지 엔진을 설계하는 것은 수많은 예외 케이스와 세부 사항들을 고려해야하기 때문에 매우 어렵다.
(물리적 데이터에 대한 레이아웃과 포인트 설계, 직렬화 형식 결정, 데이터에 대한 가비지 콜렉팅 방식, 동시성 처리 등)
특히 이런 사항들을 고려하면서도 절대로 데이터를 잃어서는 안된다.
이런 사항들을 고려하다보면 어떤 선택을 하는지에 따라 트레이드 오프가 발생한다.
예를 들어 데이터를 요청 순서대로 저장한다면 저장은 간단하지만 사용자가 정렬된 데이터를 요구했을 때 데이터를 매번 정렬해야 하는 오버헤드가 생긴다.
이렇게 각각의 스토리지는 나름의 선택의 결과를 따라 구현했기 때문에 스토리지 엔진마다도 장단점이 존재한다.
어떤 스토리지 엔진은 읽기-쓰기 시간을 줄이는데 최적화되어있고, 어떤 스토리지 엔진은 노드당 저장되는 데이터의 양을 늘리는데 집중하고, 어떤 스토리지 엔진은 단순한 운영에 최적화 되어있다.
다음 글에서는 DBMS를 다양한 관점에서 분류해보고 각 분류 별 특징에 대해 정리해본다.