개발자 글쓰기 모임 3주차의 주제는 트랜잭션의 적용 사례와, 클린 아키텍처 적용 사례이다.
하지만 트랜잭션의 적용 사례는 2주 전에 트러블슈팅 내용으로 다루었었고, 클린아키텍처 적용 사례의 경우에는 글쓰기 모임 1주차때 작성을 했었다.
https://wn1331.tistory.com/302
Coroutine과 ReactiveMongo 다중DB 환경에서 @Transactional을 사용해 보자
업무를 하는 도중, 원자적으로 작업이 되어야만 하는 즉, 트랜잭션이 꼭 필요한 비즈니스 로직이 있었다.@Transactional 어노테이션을 사용해서 간편하게 트랜잭션 작업을 하고 싶은데.. 여러 블로
wn1331.tistory.com
https://wn1331.tistory.com/301
이제 와서 고쳐보는 2024년의 내 코드
오늘은 써야지 라는 개발자 블로그 글쓰기 모임에 참여하게 되었다. 이 모임은 매주 개발 관련 블로그를 작성하고, 서로의 글을 공유하며 피드백을 나누고 경험과 인사이트를 나누자는 취지로
wn1331.tistory.com
이처럼 최근에 트랜잭션 적용과 클린 아키텍처 적용에 대해 포스팅을 다루어버려서 내용을 겹치게 하고 싶지 않아, MongoDB의 스토리지 엔진인 WiredTiger엔진에 대해서 다루어보려고 한다.
WiredTiger Engine?
현대 어플리케이션의 중추를 이루는 데이터베이스, 그 데이터베이스들 중 유연성과 확장성으로 돋보이는 MongoDB의 기능 중심에는 WiredTiger 스토리지 엔진이 자리잡고 있다.
WiredTiger Engine은 현재 MongoDB에서 Default로 사용하고 있는 고성능 스토리지 엔진으로, Document 단위 동시성을 통한 높은 처리량과 최적화된 저장을 위한 고급 압축 기법, 그리고 빠른 데이터 접근을 위한 인메모리 아키텍처를 매끄럽게 결합한다.
또한, 견고한 내구성을 보장하기 위해 WAL(Write-Ahead Logging)을 도입하고, 스냅샷 같은 Data View를 제공하는 MVCC(다중버전 동시성 제어) 기술을 통해 내구성과 무결성을 보장한다.
초기 쓰기와 인메모리 저장
먼저 MongoDB의 wiredTiger 스토리지 엔진에서 데이터가 처음 입력되는 과정은 아래와 같다.
- 데이터 초기 수신
- insert/update 등이 MongoDB 서버에 도착하면 이 요청을 WiredTiger 엔진으로 전달한다.
- 인메모리 캐시 활용
- WiredTiger의 인메모리 캐시에 기록되고, 캐시 내에서 페이지 단위로 관리된다. (수정된 페이지는 dirty 상태로 표시됨)
- 트랜잭션 로그 기록
- 캐시에 저장된 변경사항은 즉시 디스크에 순차적으로 기록되어 시스템 충돌 시 데이터 복구를 가능하게 하는 트랜잭션 로그에 기록된다. 이는 데이터 내구성을 보장하는 핵심 매커니즘.
- 체크포인트 처리
- 로그 크기가 임계치에 도달하게 되면 체크포인트가 실행되는데, dirty 페이지들이 디스크의 데이터 파일에 기록된다.
체크포인트 이후 해당 페이지들은 clean 상태로 변경된다.
- 로그 크기가 임계치에 도달하게 되면 체크포인트가 실행되는데, dirty 페이지들이 디스크의 데이터 파일에 기록된다.
이렇게 인메모리 저장 방식은 RAM의 초고속 접근 속도를 활용해 DB연산의 지연 시간을 크게 줄여준다.
Disk I/O 병목 현상을 최소화하여 동시 처리량을 극대화하고, 특히 읽기-쓰기가 빈번한 워크로드에서 성능을 향상시킨다.
이는 사용자에게 즉각적인 응답을 제공하면서도 체크포인트와 트랜잭션 로깅을 통해 데이터 내구성을 보장할 수 있다.
데이터 안전성과 영속성 보장
Disk-Based 데이터베이스에서 가장 중요한 요소가 뭐냐고 물어본다면, 나는 영속성(영구성)이라고 대답할 것이다.
실무 환경에서는 시스템 장애나 예기치 않은 상황에서도 데이터의 무결성을 유지하고 재빠르게 복구할 수 있어야 한다.
MongoDB의 WiredTiger 스토리지 엔진은 이러한 요구사항을 충족시키기 위해 다양한 매커니즘을 구현하고 있는데, 하나씩 알아보도록 하자.
Write-Ahead Logging(WAL)
WiredTiger는 데이터 변경 사항을 안전하게 관리하기 위해 WAL기법을 사용한다.
WAL은 DB의 변경 사항이 실제 데이터 파일에 반영되기 전에 먼저 로그 파일에 기록하는 방식이다.
이는 마치 중요한 작업을 수행하기 전에 메모장에 미리 계획을 적어두는 것과 유사하다.
그러면 어떻게 작동되는지 보자.
- 데이터베이스를 변경하기 전에 시스템은 변경 사항 기록을 미리 쓰기 로그에 기록한다.
- 이러한 로그 항목에는 작업 유형, 영향을 받는 데이터, 복구에 필요한 메타데이터를 포함하여 변경 사항을 재현하는데 필요한 정보들이 포함된다.
- 메모리 내 저장소로의 실제 데이터 수정
- 변경 사항이 기록되면 실제 DB에 적용 가능하다.
- 수정 사항은 메모리 내의 데이터 사본에 적용된다.
- 트랜잭션 커밋
- 트랜잭션이 커밋되면 해당 트랜잭션에 대항 변경 사항이 영구적임을 나타내는 특수 레코드가 로그에 추가된다.
- 이 커밋 레코드는 마커 역할을 하여 시스템이 어떤 변경 사항이 커밋된 트랜잭션의 일부인지 알 수 있도록 한다.
- 체크포인팅
- 주기적으로 체크포인트 작업을 수행하는데, 수행 중 시스템은 수정된 데이터 페이지를 메모리에서 디스크로 flush하고 WAL에 체크포인트 레코드를 쓴다. 이 레코드는 해당 지점까지의 모든 변경 사항이 DB파일에 적용된 WAL의 지점을 나타낸다.
- 필요한 경우에 복구가 가능하다
- 시스템 충돌/실패 발생 시 DB는 WAL을 사용하여 데이터베이스를 일관된 상태로 복원 가능하다.
- 마지막으로 커밋된 트랜잭션의 로그를 재생하여 시스템은 아직 데이터 파일에 영구적으로 기록되지 않은 변경 사항을 다시 적용할 수 있다.
그리고, WiredTiger에서는 WAL 구현체를 저널(Journal)이라고 부른다.
저널은 데이터베이스 복구 및 내구성 보장을 위한 핵심 요소이다.
- 저널 파일 위치: 기본적으로 저널 파일은 MongoDB 데이터 디렉토리의 journal 하위 폴더에 저장된다.
- 저널 압축: MongoDB는 저널 파일을 압축하여 디스크 공간과 I/O를 줄이는 옵션을 제공한다.(storage.journal.enabled: true).
- 저널 커밋 간격: 기본적으로 MongoDB는 100ms마다 저널에 변경 사항을 커밋한다. 이 설정은 storage.journal.commitIntervalMs 매개변수로 조정 가능하다.
- 저널과 체크포인트의 관계: 저널은 체크포인트 사이의 변경 사항을 추적한다. 체크포인트가 완료되면 해당 시점까지의 저널 파일은 더 이상 필요하지 않게 되어 정리된다.
위와 같은 방식으로 작동하기 때문에, 데이터 변경 중에 시스템 장애가 발생하더라도 저널 로그 파일을 통해 어떤 작업이 진행중이었는지 확인하고 복구할 수 있다.
MVCC(다중 버전 동시성 제어)
MVCC(Multi Version Concurrency Control)는 MongoDB의 WiredTiger 스토리지 엔진에서 사용하는 중요한 기술로, 하나의 도큐먼트에 대해 여러 버전을 동시에 관리하면서 필요에 따라 적절한 버전을 사용할 수 있게 해주는 메커니즘이다.
MVCC의 기본 작동 원리
- 초기 상태
- 디스크의 데이터 페이지가 WiredTiger 스토리지 엔진의 공유 캐시에 적재된다.
- 이 시점에서는 변경 이력이 비어있는 상태인데, 이는 스킵 리스특로 구현되어 있다.
- 데이터 변경 과정
- 트랜잭션이 시작되고 UPDATE 명령이 실행되면, WiredTiger는 디스크에서 데이터 페이지를 직접 변경하지 않고, 대신 변경 이력(스킵 리스트)에 새로운 데이터를 기록한다.
- 이 때, 어떤 트랜잭션 ID에 의해 변경되었는지도 함께 기록된다.
- 변경 이력 관리
- WiredTiger는 최근의 변경을 스킵 리스트의 앞쪽으로 정렬하여 최근 데이터를 빠르게 검색할 수 있게 한다.
- 이 방식으로 각 Document에 대해 여러 버전들을 동시에 관리할 수 있다.
- 메모리 관리
- 변경 이력이 계속 늘어나 memory_page_max 설정 값보다 큰 메모리를 사용하게 되면 해당 페이지를 디스크에 기록하는 작업(Eviction)을 수핸한다.
- 디스크 기록 시 Reconciliation 과정을 통해 원래의 데이터 페이지 내용과 변경된 내용이 병합된다.
- 데이터가 너무 크면 2개 이상의 페이지로 나뉘어 디스크에 기록될 수 있다.
체크포인팅
또 다른 중요한 매커니즘은 체크포인팅이다.
체크포인팅은 인메모리에서 변경된 데이터들을 주기적으로 디스크에 기록하는 과정을 의미한다.
이를 통해 시스템은 특정 시점의 일관된 데이터 상태를 디스크 상에 저장하게 되며, 장애 발생 시 마지막 체크포인트 상태로 신속하게 복구할 수 있다.
체크포인팅은 단순히 데이터를 기록하는 작업을 넘어서, 데이터베이스가 항상 최신 상태를 유지하면서도, 장애 복구 시점의 기준점을 제공하는 역할을 한다. 이렇게 시스템은 지속적으로 안정적인 운영이 가능해진다.
스냅샷 관리와 CoW(Copy-on-Write) 기법
WiredTiger는 스냅샷 관리 기능을 통해, 특정 시점의 데이터 상태를 보존할 수 있다.
스냅샷은 백업, 롤백, 또는 장애 복구 시 매우 유용하게 사용되며, 이를 통해 데이터베이스는 과거의 안정적인 상태로 쉽게 복원할 수 있다.
또한, Copy-on-Write 기법은 데이터 변경 시 원본 데이터를 보존하면서, 변경된 데이터를 별도로 기록하는 방식이다.
이 기법은 데이터의 일관성을 유지하고, 장애 발생 시 원래의 데이터를 안전하게 복구하는 데 기여한다.
WAL도 복구가 가능하고, 체크포인팅도 복구할 수 있다고 하고, 스냅샷으로도 복구시 쓰이고, CoW도 복구하는데 기여하면 대체 트랜잭션 롤백 기능은 어떻게 동작하는 걸까?
WAL, 체크포인팅, 스냅샷, CoW는 모두 시스템 장애나 복구 상황에서 데이터베이스의 내구성과 일관성을 보장하기 위한 매커니즘이다.
반면, 트랜잭션의 롤백은 아직 커밋되지 않은 변경 사항을 그냥 취소하는, 정상적인 트랜잭션 처리 과정 내의 동작이다.
예를 들어, 트랜잭션이 진행되는 동안 변경된 데이터는 메모리와 MVCC에 의해 여러 버전으로 관리되는데, 이때 오류가 발생하거나 명시적으로 롤백 명령이 내려지면, 커밋되지 않은 최신 변경 사항은 폐기되고 이전에 커밋된(또는 트랜잭션 시작 전의) 상태로 돌아간다.
이 과정은 메모리 내에서 이루어지며, WAL이나 체크포인팅은 이미 커밋된 데이터의 복구를 위한 것이므로, 직접적으로 트랜잭션 롤백 기능과는 다르다. 헷갈리지 말도록 하자. (나만 헷갈린 걸지도..)
Document 단위 잠금
WiredTiger 스토리지 엔진은 세밀한 문서 단위 잠금(document-level locking) 을 사용하여 데이터베이스의 동시성과 성능을 최적화한다. 이 매커니즘은 이전 버전의 mongodb(MMAPv1)에서 사용하던 Collection 단위 잠금에 비해 훨씬 세밀한 제어를 제공한다.
Document 단위 잠금의 작동 방식에 대해 알아보자.
- 잠금 세분화
- 개별적인 Document 수준에서 잠금을 적용하는데, 이는 하나의 Document가 잠겨도 같은 Collection의 다른 Documtne는 자유롭게 접근할 수 있다는 뜻이다.
- 이를 통해 Collection 내 다중 Document에 대한 동시 작업이 가능해 진다.
- 의도 잠금(Intent Locking)
- 의도 잠금이라 하니깐 이해가 잘 안되는데, 이는 계층적 구조(db->collection->document)에서 하위 리소스에 특정 유형의 잠금을 설정하려는 '의도'를 표시하는 잠금 유형이다.
- 의도 잠금은 하위 계층에 특정 유형의 잠금이 있음을 나타낸다.
- 다중 버전 동시성 제어(MVCC)
- 읽기 작업이 쓰기 작업을 차단하지 않도록 하고, 각 트랜잭션은 데이터의 스냅샷을 보면서 다른 트랜잭션의 변경사항은 커밋될 때까지 보이지 않는다. 이를 통해 읽기 작업에 대한 잠금이 최소화된다.
- 낙관적 동시성 제어
- 기본적으로 낙관적 접근 방식을 사용한다. 커밋 시점에 충돌을 감지하고 필요한 경우 트랜잭션을 재시도한다.
잠금 유형(Lock Mode)으로는 아래와 같다.
- S : 읽기를 위한 Shared(공유) 잠금
- X : 쓰기 작업을 위한 Exclusive(배타) 잠금
- IS : 의도적 Shared(공유) 잠금
- IX : 의도적 Exclusive(배타) 잠금
- 쓰기를 위해서 Collection을 잠그는 경우 해당 DB 잠금과 Global 잠금은 모두 IX로 잠겨야 한다.
- 실질적으로 X락은 Collection에게 잠기지만 그 윗단에 (DB와 Global은 IX롣 됨)
- Single DB에서는 IS와 IX를 동시에 잠글 수 있지만, X잠금은 다른 모드와 공존할 수 없으며, S잠금은 IS모드랑만 공존이 가능하다.
- Shared(공유) 잠금
- 다른 공유 잠금과 호환되나 배타적 잠금과는 호환되지 않는다. 호환이라는 말은 한 리소스에 두개 이상의 잠금을 설정할 수 없다는 뜻.
- 공유 잠금을 설정한 리소스에서 다른 트랜잭션이 추가로 잠금을 설정할 수 있으나, 배타적 잠금으로는 불가능하다.
- 자신이 Select하고 있는 리소스를 다른 사용자가 동시에 Select할 수는 있어도 변경은 불가능하다.
- 다른 사용자가 Select하고 있는 리소스를 동시에 Select할 수 있어도, 변경 중인 리소스를 동시에 설정할 수는 없다.
- Exclusive(배타) 잠금
- 데이터를 변경하고자 할 때 사용되며, 트랜잭션이 완료될 때까지 유지된다.
- 잠금이 해제될 때까지 다른 트랜잭션은 해당 리소스에 접근이 불가능하다. 변경 불가, 읽기 불가
- 다른 트랜잭션에 의해 잠금 설정이 된 리소스는 어떤 잠금이든 동시에 설정할 수 없다.
WiredTiger에서 사용하는 잠금 모드간의 호환성은 아래와 같다.
요청/기존 | IS | IX | S | X |
IS | ✅ | ✅ | ✅ | ❌ |
IX | ✅ | ✅ | ❌ | ❌ |
S | ✅ | ❌ | ✅ | ❌ |
X | ❌ | ❌ | ❌ | ❌ |
이 표는 기존에 설정된 잠금과 새로 요청된 잠금 간의 호환성을 보여준다.
그렇다면 예시로 5명의 클라이언트가 아래와 같은 요청들을 수행한다고 가정해보자.
위 예시는 WiredTiger의 문서 단위 잠금이 어떻게 동시성을 향상시키고 Collection 단위 잠금에 비해 더 효율적으로 작동하는지 보여준다. 같은 컬렉션 내에서도 서로 다른 문서에 대한 작업이 병렬로 처리될 수 있으며, 같은 문서에 대한 경합은 잠금 유형의 호환성에 따라 처리된다.
기본적으로 클라이언트의 요청들은 선입선출(FIFO) 방식으로 대기열에 추가되는데, S잠금끼리는 호환되므로 동일 문서에 대한 여러 읽기 요청은 동시에 처리 가능하고, 서로 다른 문서에 대한 요청은 잠금 유형에 관계없이 동시에 처리가 가능하다.
문서 수준에서 잠금이 유지되므로 Collection 전체로 잠금이 확장되지 않고, 이는 MMAPv1엔진에서 사용하던 Collection 수준의 잠금과의 주요 차이점이다.
IS/IX 잠금의 경우에는 상위 레벨(DB 또는 Collection)에서 하위 리소스(Collection 또는 Document)에 대한 작업 의도를 표시한다. 이를 통해 서로 다른 문서에 대한 작업이 서로 방해하지 않도록 조정할 수 있다.
읽기 작업은 데이터의 특정 지점 스냅샷을 보기 때문에 쓰기 작업과 충돌을 최소화하고, 트랜잭션 커밋 전까지 변경사항이 다른 트랜잭션에 보이지 않는데, 이는 MVCC의 주된 영향이다.
인덱싱
WiredTiger는 B+Tree 자료구조를 사용하여 인덱스를 구현한다.
B+Tree 자료구조의 특징으로는 아래와 같다.
- 계층적 구조: 루트 노드, 내부 노드, 리프 노드로 구성된 다단계 트리 구조이다.
- 균형 트리: 모든 리프 노드가 동일한 깊이에 있어 검색 시간이 일정하다.
- 다중 키 노드: 각 노드는 여러 키를 저장할 수 있어 트리의 폭이 넓고 깊이가 낮아진다.
- 리프 노드에만 데이터 저장: 모든 데이터는 리프 노드에만 저장되고, 내부 노드는 인덱스 키만 포함한다.
- 연결된 리프 노드: 모든 리프 노드는 연결 리스트로 연결되어 순차적 접근이 효율적이다.
- 고밀도 저장: 각 노드는 디스크 블록 크기에 최적화되어 I/O 작업 수를 최소화한다.
- 자동 재조정: 데이터 삽입/삭제 시 트리가 자동으로 재균형을 이루어 최적 성능을 유지한다.
- 효율적인 범위 쿼리: 연결된 리프 노드 구조로 인해 범위 기반 검색이 매우 빠르다.
- 확장성 : 대용량 데이터에도 로그 시간(logarithmic time) 검색 성능을 유지한다.
WiredTiger 특징과 인덱싱의 연관성?
1. MVCC(다중 버전 동시성 제어)
- B+Tree 연관성: MVCC는 B+Tree 인덱스의 여러 버전을 관리한다. 읽기 작업은 특정 시점의 일관된 B+Tree 버전을 참조하고, 쓰기 작업은 새로운 버전을 생성한다.
- 성능 기여: 읽기 쿼리가 쓰기 작업을 차단하거나 대기할 필요 없이 B+Tree 인덱스를 자유롭게 탐색할 수 있어 동시성이 크게 향상된다. 트랜잭션 분리로 인해 고부하 환경에서도 인덱스 조회 지연 시간이 일정하게 유지된다.
2. 저널링(Journaling)
- B+Tree 연관성: B+Tree 구조 변경(노드 분할, 병합, 재분배 등)은 원자적으로 이루어져야 하며, 저널링은 이러한 복잡한 작업의 내구성을 보장한다.
- 성능 기여: 인덱스 수정 작업이 메모리에서 빠르게 실행된 후 저널에 기록되고, 실제 B+Tree 디스크 구조는 체크포인트 시에 일괄 업데이트된다. 이 접근 방식은 랜덤 I/O를 순차적 I/O로 변환하여 B+Tree 수정 성능을 크게 향상시킨다.
3. 스냅샷 격리(Snapshot Isolation)
- B+Tree 연관성: 스냅샷은 특정 시점의 B+Tree 상태를 캡쳐한다. 쿼리는 일관된 B+Tree 버전에서 실행되어 인덱스 탐색 중 변경되는 상황을 방지한다.
- 성능 기여: 복잡한 쿼리나 집계 작업 중에도 B+Tree 인덱스 구조가 변경되지 않으므로, 인덱스 탐색이 일관되고 정확하게 수행된다. 이는 특히 긴 시간 동안 실행되는 분석 쿼리의 안정성과 성능을 향상시킨다.
4. 문서 수준 잠금(Document-Level Locking)
- B+Tree 연관성: 전통적인 B+Tree 구현은 노드 수준에서 잠금이 필요하지만, 문서 수준 잠금은 B+Tree의 특정 키에 해당하는 문서만 잠근다.
- 성능 기여: 서로 다른 키 범위의 B+Tree 부분을 동시에 수정할 수 있어 인덱스 업데이트의 병렬성이 향상된다. 이는 높은 쓰기 처리량이 필요한 환경에서 B+Tree 기반 인덱스의 성능을 크게 향상시킨다.
5. 압축(Compression)
- B+Tree 연관성: WiredTiger는 B+Tree 노드 자체를 압축하여 저장한다. 접두사 압축(prefix compression)과 같은 특수 기법을 사용하여 유사한 키를 효율적으로 저장한다.
- 성능 기여: 압축된 B+Tree 노드는 메모리와 디스크 공간을 적게 차지하므로, 더 많은 인덱스가 메모리에 캐시될 수 있다. 이는 디스크 I/O를 감소시키고 인덱스 조회 성능을 향상시킨다. 압축된 B+Tree 노드는 디스크에서 메모리로 로드할 때 더 적은 I/O를 필요로 하므로 인덱스 초기 로드 시간도 단축된다.\
이러한 기술들이 함께 작동될 때, WiredTiger의 B+Tree 인덱싱은 고성능, 확장성, 신뢰성이 필요한 데이터베이스 작업에 이상적인 환경을 제공한다.
WiredTiger의 트랜잭션
WiredTiger 스토리지 엔진의 트랜잭션은 높은 동시성과 내구성, 그리고 일관된 데이터 뷰를 제공하기 위해 여러 가지 중요한 특징들을 가지고 있다.
- ACID 보장
- WiredTiger는 트랜잭션이 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 지속성(Durability)을 충실히 따르도록 설계되어 있다.
- 멀티버전 동시성 제어(MVCC)와 스냅샷 격리
- 트랜잭션이 시작될 때 데이터의 스냅샷을 생성하여, 읽기 작업이 동시에 진행되는 쓰기 작업의 영향을 받지 않고 일관된 상태를 유지할 수 있게 한다.
- 이를 통해 여러 트랜잭션이 동시에 수행되더라도 서로 간섭 없이 독립적인 작업이 가능해진다.
- 낙관적 동시성 제어 (Optimistic Concurrency Control)
- 읽기 작업은 대체로 비차단(non-blocking)으로 진행되며, 쓰기 충돌은 커밋 시점에서 감지된다.
- 이 방식은 잠금(lock) 오버헤드를 줄이고, 동시 작업의 효율성을 높이는 데 기여한다.
- Write-Ahead Logging (WAL) 및 체크포인팅
- 모든 변경 사항은 먼저 로그에 기록되어, 시스템 장애 발생 시 복구가 가능하도록 한다.
- 주기적인 체크포인트를 통해 디스크에 일관된 상태를 저장하며, 내구성을 보장한다.
- 세션 기반 트랜잭션 관리와 세밀한 잠금 메커니즘
- 트랜잭션은 세션 단위로 관리되며, 하나의 세션 내에서 여러 작업을 하나의 트랜잭션으로 묶어 처리할 수 있다.
- 또한, 세밀한(fine-grained) 잠금 전략을 사용하여 높은 동시성을 지원하면서도 데이터 무결성을 유지한다.
이와 같이 WiredTiger 스토리지 엔진의 트랜잭션은 데이터의 일관성과 내구성을 보장하면서도, 동시성이 높은 환경에서 효율적으로 동작하도록 설계되었다.
왜 레플리카셋 환경이나 샤딩된 클러스터 환경에서만 트랜잭션이 동작할까?
Standalone Mongodb는 노드가 하나이기 때문에 장애 시 복구할 수 없기 때문이다. 트랜잭션이 동작하는 중에는 Primary 노드에서 데이터를 쓰고, Secondary 노드로 Oplog를 통해 복제하는데, 이러한 방식으로 동기화해야 데이터의 스냅샷 상태를 보장할 수 있기 때문이다.
Why replica set is mandatory for transactions in MongoDB?
As per MongoDB documentation, transactions only works for replica sets and not single node. Why such requirement? Isn’t it is easier to do transaction stuff on a single node rather than a distributed system?
www.mongodb.com
마무리
이번 포스팅을 작성하면서, MongoDB의 WiredTiger 스토리지 엔진에 대해 여러 레퍼런스를 참조해 보면서 아주 많은 공부가 되었다. 저장소 구조, 트랜잭션 처리, 잠금 등 핵심 개념들에 대해 다루었지만, 이것들은 정말 WiredTiger의 일부라는 생각도 들었다.
향후에는 공유 캐시와 파일 구조에 대해서도 깊게 공부해볼 필요가 있을 것 같다.
이런 지식들이 결국 더 나은 시스템 설계와 문제 해결 능력으로 이어질 수 있으리라 믿고, 앞으로도 계속해서 실무 환경에서 사용하는 기술들에 대해 학습을 계속해나갈 예정이다..
추가적으로 여담이지만 GPT나 Claude로 생성된 정보들은 맹신하면 안된다는 것을 이번에 뼈저리게 느꼈다.
언제는 B-Tree랬다가, B+Tree랬다가 왔다갔다 하고, WiredTiger에 대해 물어봤는데 일부 틀린 내용(MMAPv1내용)을 알려주기도 해서 Real MongoDB를 읽고 내가 이해한 내용과 여러 블로그들의 내용들을 요약해서 작성하였다.
+ 틀린 점이 있다면 지적 부탁드립니다
참고 문서
https://martinfowler.com/articles/patterns-of-distributed-systems/write-ahead-log.html
Real MongoDB - https://product.kyobobook.co.kr/detail/S000001766322
Kakao Tech Blog - https://tech.kakao.com/posts/670
Wikipedia - https://en.wikipedia.org/wiki/WiredTiger
'끄적끄적' 카테고리의 다른 글
TDD의 개념과 장단점 그리고 BDD by Kotest (4) | 2025.03.16 |
---|---|
이제 와서 고쳐보는 2024년의 내 코드 (4) | 2025.03.08 |