WiredTiger란?
WiredTiger란 MongoDB에서 사용하는 기본 스토리지 엔진이다. MongoDB는 3.2 버전부터 WiredTiger를 기본 스토리지 엔진으로 사용하기 시작했으며, 그 전까지는 MMAPv1 이라고 하는 스토리지 엔진을 사용하고 있었다. MMAPv1 스토리지 엔진을 탑재한 MongoDB는 많은 단점이 있었는데, 대표적으로 MMAPv1 스토리지 엔진은 도큐먼트 단위의 동시성 제어를 지원하지 못하고 컬렉션 단위의 동시성 제어를 제공했다. 이로 인해서 동시에 같은 컬렉션에 데이터의 쓰기가 발생하는 경우 처리량이 좋지 않고 병목현상이 발생했다. MongoDB에서는 이러한 단점들 때문에 WiredTiger라는 스토리지 엔진을 인수하고 기본 스토리지 엔진으로 사용하기 시작했다.
WiredTiger에서는 스토리지 엔진 단에서 많은 기능들을 제공하고 있다. 우선 앞서 설명한 도큐먼트 레벨의 동시성 제어를 제공하기 때문에 같은 컬렉션에 데이터를 쓰더라도 잠금 없이 데이터를 쓸 수 있다. 이 외에도 Skip List 알고리즘을 기반으로 한 MVCC ( Multi Version Concurrency Control ) 과 다양한 압축 알고리즘을 사용한 데이터 파일 압축을 지원, Journaling을 통한 데이터의 내구성 향상 등을 지원하고 있다.
WiredTiger는 별개의 소프트웨어이기 때문에 MongoDB가 빌드될 때 포함되어 빌드될 뿐, WiredTiger에 대한 소스코드는 MongoDB와 별도의 프로젝트로 존재하고 있다. WiredTiger 역시 오픈소스이기 때문에 Github에 소스코드가 공개되어 있다. WiredTiger의 동작원리가 궁금하다면, 직접 코드를 보고 확인할 수 있다.
Github : https://github.com/wiredtiger/wiredtiger
Document : https://source.wiredtiger.com/
MongoDB의 Data file
MongoDB는 Storage Engine으로 WiredTiger를 사용하고 있다. 즉, MongoDB에서 데이터를 스토리지에 저장하는 경우 WiredTiger에게 데이터의 쓰기를 요청한다.
기동중인 MongoDB의 데이터 디렉토리를 살펴보면, WiredTiger에 관련된 여러 파일들이 존재하는 것을 확인할 수 있다.
[data]$ ls -al
drwxr-xr-x 18 mongodb mongodb 4096 Nov 9 17:49 .
drwxr-xr-x 8 mongodb mongodb 90 Nov 5 14:32 ..
drwxr-xr-x 2 mongodb mongodb 4096 Nov 5 14:32 admin
drwxr-xr-x 2 mongodb mongodb 4096 Nov 5 14:32 config
drwxr-xr-x 2 mongodb mongodb 4096 Nov 9 17:49 diagnostic.data
drwxr-xr-x 2 mongodb mongodb 110 Nov 9 17:49 journal
drwxr-xr-x 2 mongodb mongodb 4096 Nov 5 15:03 local
-rw-r--r-- 1 mongodb mongodb 156790 Nov 5 14:35 log
-rw-r--r-- 1 mongodb mongodb 4882 Nov 5 14:35 log_restore
-rw-r--r-- 1 mongodb mongodb 45056 Nov 5 15:03 _mdb_catalog.wt
-rw-r--r-- 1 mongodb mongodb 6 Nov 5 14:46 mongod.lock
-rw-r--r-- 1 mongodb mongodb 114 Nov 5 14:38 storage.bson
drwxr-xr-x 2 mongodb mongodb 6 Nov 5 14:49 _tmp
drwxr-xr-x 2 mongodb mongodb 4096 Nov 5 14:38 unique
-rw-r--r-- 1 mongodb mongodb 50 Nov 5 14:38 WiredTiger
-rw-r--r-- 1 mongodb mongodb 45056 Nov 9 17:48 WiredTigerHS.wt
-rw-r--r-- 1 mongodb mongodb 21 Nov 5 14:38 WiredTiger.lock
-rw-r--r-- 1 mongodb mongodb 1507 Nov 9 17:48 WiredTiger.turtle
-rw-r--r-- 1 mongodb mongodb 421888 Nov 9 17:48 WiredTiger.wt
MongoDB에서 Database 별로 디렉토리를 나누는 옵션을 사용하고 있다.
따라서 실제 데이터 파일과 인덱스 파일들은 데이터베이스 내에 존재하고 있다.
[data/unique]$ ls
collection-0-25142271970417739.wt index-1--75987962394999326.wt
collection-0--75987962394999326.wt index-2-25142271970417739.wt
collection-3--75987962394999326.wt index-4--75987962394999326.wt
index-1-25142271970417739.wt index-5--75987962394999326.wt
이때 데이터 파일이나 인덱스 파일을 보려고 해도, 일반적인 방법으로는 볼 수가 없다.
cat index-1--75987962394999326.wt
A�#��z�XP9df�
J�`��+�(�f�
������
,�(�f�
������*`J�`��-�(�f�_����Ə���E}�8*�f�
����Ə�T��߾����P8�2
V�F���������.bE�`������|��/��'
meta data...meta data...meta data...meta data...meta data...meta data...meta data...
)����|�ӂ��F�����������
WiredTiger 빌드하기
아래 내용들은 Rocky 8.10, MongoDB 6.0 을 사용하고 있는 MongoDB에서 실행한 결과들이다.
MongoDB와 WiredTiger는 별도로 존재하기 때문에 WiredTiger를 빌드하면 MongoDB가 쓴 데이터 파일들의 내용을 직접 확인할 수 있다.
cat WiredTiger
WiredTiger
WiredTiger 10.0.2: (December 21, 2021)
6.0 버전의 MongoDB는 현재 WiredTiger 10.0.2 버전을 사용하고 있다.
그렇다면 WiredTiger의 10.0.2 버전에 대한 문서를 참고할 수 있다.
WiredTiger 10.0.0 : https://source.wiredtiger.com/10.0.0/index.html
다음 명령어들을 통해서 WiredTiger를 빌드하자.
- 빌드 전 필요한 패키지 다운로드
dnf upgrade --refresh
dnf install cmake
dnf install snappy
dnf install snappy-devel
dnf group install "Development Tools"
- 소스코드 다운로드
git clone https://github.com/wiredtiger/wiredtiger.git
- 6.0 버전으로 checkout
cd wiredtiger/
git branch --all | grep mongodb
git checkout mongodb-6.0
- snappy library가 있는지 확인
MongoDB에서는 snappy 압축을 사용하여 데이터파일을 저장하기 때문에, WT 빌드 시 snappy를 사용할 수 있도록 빌드해주어야한다.
ls /usr/include | grep snappy
ls /usr/lib64 | grep snappy
- 빌드 & cmake 시 snappy 활성화
mkdir build
cd build
cmake -DHAVE_BUILTIN_EXTENSION_SNAPPY=1 -DCMAKE_INCLUDE_PATH=/usr/include -DCMAKE_LIBRARY_PATH=/usr/lib ../.
make
이 명령어들을 수행해주면, wt라고 하는 바이너리를 볼 수 있다.
[~/wiredtiger/build]$ ls
bench CMakeFiles config examples include libwiredtiger.so.10.0.2 src wiredtiger.pc
CMakeCache.txt cmake_install.cmake CTestTestfile.cmake ext libwiredtiger.so Makefile test wt
[~/wiredtiger/build]$ ./wt
WiredTiger Data Engine (version 10.0)
MongoDB wiredtiger_open configuration: "log=(enabled=true,path=journal,compressor=snappy)"
....
그럼 MongoDB의 데이터파일들을 볼 수 있는 준비가 끝났다.
WT를 사용하여 데이터 확인하기
WT를 사용하면 MongoDB가 생성한 데이터 파일들을 전부 볼 수 있는 것과 마찬가지가 된다.
WT를 통해 사용할 수 있는 명령어들에 대한 자세한 내용은 다음 문서를 보면 확인할 수 있다.
https://source.wiredtiger.com/10.0.0/command_line.html
인덱스 파일 까보기
이번 기회에 인덱스 파일이 어떤 방식으로 저장되고 있는지 확인해보자. 내가 궁금했었던 것은 인덱스 파일은 데이터를 정렬하여 저장하는데, 서로 다른 자료형의 경우 데이터를 어떻게 정렬하여 저장하는지가 궁금했다. 서로 다른 데이터 타입의 데이터들이 어떻게 저장되어있는지 확인해보자.
우선 MongoDB에 데이터를 넣는다. 다음과 같이 서로 다른 타입의 데이터들이 index-order
라는 데이터베이스의 test
컬렉션에 들어가있다.
[direct: primary] index-order> db.test.find();
[
{ _id: ObjectId("67260c1c11b50e7e160ece2"), hello: 1 },
{ _id: ObjectId("67260c1811b50e7e160ece1"), hello: 'world!' },
{ _id: ObjectId("672613fda095eb480485e6c"), hello: 2 },
{ _id: ObjectId("672afc71df8592013041860"), hello: '1' }
]
그리고 hello
필드를 기준으로 인덱스를 생성해주었다.
[direct: primary] index-order> db.test.getIndexes();
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{ v: 2, key: { hello: 1 }, name: 'hello_1' }
]
그 이후 MonogDB를 멈춰주자.
MongoDB가 기동중인 상황에서는 데이터 파일들에 접근할 수 없기 때문에, MongoDB를 멈춘 뒤 WT를 통해서 데이터 파일들을 볼 수 있다.
데이터 디렉토리로 이동하고, wt list 명령어를 통해서 wt에서 관리하고 있는 파일들을 확인할 수 있다.
[data]$ wt list
...
table:index.45order/collection-2--6907916227660837382
table:index.45order/index-3--6907916227660837382
table:index.45order/index-4--6907916227660837382
이 중에서 index-order
데이터베이스의 파일들 중 인덱스 파일을 살펴보자.wt dump
명령어를 통해서 데이터 파일의 내용을 확인할 수 있다.
index-3--6907916227660837382 파일은 test 컬렉션의 _id
파일인데, 데이터를 확인해보면 _id
가 정렬된 순서대로 데이터가 들어가 있는 것을 볼 수 있다.
- 데이터의
_id
정렬 순서
db.test.find().sort({_id: 1});
[
{ _id: ObjectId("67260c18111b50e7e160ece1"), hello: 'world!' },
{ _id: ObjectId("67260c1c111b50e7e160ece2"), hello: 1 },
{ _id: ObjectId("672613fdfa095eb480485e6c"), hello: 2 },
{ _id: ObjectId("672afc71cdf8592013041860"), hello: '1' }
]
- 실제 인덱스 파일
[data]$ wt dump -x table:index.45order/index-3--6907916227660837382
WiredTiger Dump (WiredTiger Version 10.0.2)
Format=hex
Header
metadata...metadata...metadata...metadata...metadata...metadata...metadata...metadata...metadata...metadata...
Data
6467260c18111b50e7e160ece104 # -> 67260c18111b50e7e160ece1
0010
6467260c1c111b50e7e160ece204 # -> 67260c1c111b50e7e160ece2
0008
64672613fdfa095eb480485e6c04 # -> 672613fdfa095eb480485e6c
0018
64672afc71cdf859201304186004 # -> 672afc71cdf8592013041860
0020
그렇다면, hello
필드를 기준으로는 어떻게 정렬이 되어있을까?
- 데이터 정렬 순서
mongod_replset_1 [direct: primary] index-order> db.test.find().sort({hello: 1});
[
{ _id: ObjectId("67260c1c111b50e7e160ece2"), hello: 1 },
{ _id: ObjectId("672613fdfa095eb480485e6c"), hello: 2 },
{ _id: ObjectId("672afc71cdf8592013041860"), hello: '1' },
{ _id: ObjectId("67260c18111b50e7e160ece1"), hello: 'world!' }
]
- 인덱스 파일
[data]$ wt dump -x table:index.45order/index-4--6907916227660837382
WiredTiger
Dump (WiredTiger Version 10.0.2)
Format=hex
Header
table:index.45order/index-4--6907916227660837382
meta data....meta data....meta data....meta data....meta data....meta data....
Data
2b02040008 # -> 1
2b04040018 # -> 2
3c3100040020 # -> '1'
3c776f726c642100040010 # -> 'world!'
데이터가 정수형인 경우 -> 2b
, 문자열인 경우 3c
로 데이터 앞에 플래그가 있는 것을 볼 수 있다.
즉, 인덱스의 데이터는 자료형 별로 데이터가 정렬되어있다는 것을 확인할 수 있었다.
결론
MongoDB의 스토리지 엔진은 WiredTiger이며, 별도의 WiredTiger를 빌드하여 바이너리를 사용하면, MongoDB에서 사용하고 있는 데이터파일들의 내용을 직접 확인할 수 있다. 이를 통해서, MongoDB는 데이터 파일을 어떻게 저장하는지, 어떤 내용들로 저장하고 있는지 조금 더 쉽게 확인할 수 있다.
참고한 Percona 블로그를 보면, WT를 유용하게 사용할 수 있는 다양한 케이스들에 대해서도 살펴볼 수 있다.
MongoDB는 생성한 컬렉션이나 인덱스의 이름과, 실제 데이터 파일을 매칭하기 어려운데, wt를 사용하면 쉽게 컬렉션과 인덱스의 실제 데이터 파일을 확인하기 쉽다.
뿐만 아니라, printlog를 통해 Journal에 대한 내용도 확인할 수 있다.
WT의 더 많은 사용사례들에 대해 알고싶다면, Reference에 기재되어있는 percona 블로그를 읽어보길 바란다.
Reference
'Database > MongoDB' 카테고리의 다른 글
MongoDB - Collect slow query using Fluentbit and Opensearch (0) | 2025.01.10 |
---|---|
MongoDB Debug Mode로 빌드하기 (1) | 2024.12.22 |
MongoDB Journaling (1) | 2024.10.09 |
MongoDB Replication (1) | 2024.09.15 |
mongodb 인스턴스 만들기 (1) | 2023.12.07 |