MongoDB의 ACID 완전 정복 Part 4 — Durability: 저널·체크포인트와 Write Concern
ACID의 D(Durability)는 ‘커밋 응답을 받았다면 어떤 장애 뒤에도 그 쓰기가 남는가’를 묻습니다. 이번 글에서는 메모리와 디스크 사이 간극을 메우는 WAL·WiredTiger 저널·체크포인트 흐름을 정리하고, 단일 노드 크래시 복구가 어떻게 이뤄지는지 단계로 설명합니다. Replica Set에서는 Write Concern의 w·j·wtimeout이 ‘언제 응답을 보낼지’와 ‘복제·저널 기준선’을 어떻게 바꾸는지 나누어 짚으며, 기본값이 majority로 바뀐 이유와 wtimeout이 ‘롤백 없음’과 동치가 아닌 이유도 구분합니다. 버전별 기본값·세컨더리 동작은 배포와 설정에 따라 달라질 수 있으므로, 인용 시 사용 중인 버전의 공식 매뉴얼을 함께 확인하시길 권합니다.
시리즈 구성
- Part 1 | ACID 개념 + MongoDB의 역사적 맥락
- Part 2 | Atomicity·Consistency — 단일 문서부터 멀티 문서
- Part 3 | Isolation과 Snapshot Isolation 내부 동작
- Part 4 ← 지금 여기 | Durability, WiredTiger, Write Concern
- Part 5 | 실전 코드 패턴 + 성능 최적화 + 안티패턴
목차
- 들어가며
- Durability가 어려운 이유 — 메모리와 디스크의 간극
- WAL — Write-Ahead Logging의 원리
- WiredTiger Journal — 단일 노드 Durability의 기반
- Checkpoint — 주기적으로 일어나는 스냅샷
- Journal과 Checkpoint — 크래시 복구 흐름
- Write Concern — 분산 환경에서의 Durability
- Write Concern 옵션 — w, j, wtimeout
- 버전·릴리스와 Durability 구현 (참고)
- Durability 설정 실전 가이드
- 장애 시나리오와 보호 수준 — 토폴로지 전제
- 마치며
1. 들어가며
Part 3까지는 격리(Isolation)와 Read Concern을 중심으로 “동시에 무엇이 보이는가”를 다뤘습니다. 이번 글은 ACID의 마지막 글자인 Durability(지속성) — “커밋이 성공했다고 응답받은 쓰기가, 그 뒤 전원 차단·프로세스 크래시 같은 사건 뒤에도 유지되는가” — 에 맞춥니다.
운영에서 Durability는 스토리지 엔진의 저널·체크포인트(단일 mongod)와 복제·Write Concern(Replica Set)이 동시에 등장합니다. 한 문단으로 압축하면 다음과 같습니다.
디스크에 남기기 전에는 “완료”를 애매하게 보내지 않도록, 로그를 먼저 쌓고(WAL), 배포 형태에 따라 “몇 노드까지 확인했는가”를 쓰기 옵션으로 조절한다.
아래에서는 먼저 단일 노드 관점의 WiredTiger 저널·체크포인트를 정리하고, 이어서 Replica Set에서 writeConcern이 의미하는 바를 나눕니다. 최신 메이저 버전의 세부 최적화·기본값은 릴리스 노트와 매뉴얼이 권위가 되므로, 본문의 코드·설명은 개념 정렬에 두고 운영 시에는 반드시 사용 중 버전 문서를 대조하시길 권합니다.
2. Durability가 어려운 이유 — 메모리와 디스크의 간극
CPU·메모리는 빠르지만 휘발성이고, SSD·디스크는 상대적으로 느리지만 전원이 꺼져도 데이터가 남습니다. 데이터베이스는 처리량을 위해 작업 세트를 RAM에 올려 두는데, 그 상태에서 곧바로 “영구 저장 완료”라고 응답하면 아직 디스크에 없는 변경이 생길 수 있습니다.
반대로 모든 변경을 디스크에 fsync 할 때까지 응답을 미루면 안전해지지만 지연은 커집니다. Durability 설계는 이 속도와 안전 사이를 메우는 쪽에 가깝고, MongoDB는 그중심에 순차 로그(WAL 계열) 와 주기적 체크포인트를 둡니다.
3. WAL — Write-Ahead Logging의 원리
WAL(Write-Ahead Logging) 의 핵심 원칙은 단순합니다.
데이터 파일을 갱신하기에 앞서, 변경 내용을 로그(저널)에 먼저 남긴다.
데이터 파일 갱신은 랜덤 I/O가 많을 수 있지만, 로그에 append 하는 방식은 순차 I/O에 가깝습니다. 먼저 로그에 남겨 두면, 크래시 뒤 재시작 시 로그를 재실행(replay) 해서 데이터 파일과 메모리 상태를 맞출 수 있습니다.
개략적인 쓰기 흐름은 다음과 같습니다.
- 클라이언트가 갱신을 요청한다.
- 스토리지 엔진이 메모리 캐시를 갱신한다.
- 변경이 저널에 기록된다(WAL).
- 이 시점 이후 클라이언트가 “완료”를 받을 수 있는지는
writeConcern과 저널 플러시 정책에 달린다(§7~8). - 이후 체크포인트가 진행되면 dirty 페이지가 데이터 파일에 반영된다.
즉, “3번 직후 곧바로 응답한다”가 전역 기본은 아닙니다. 응답 시점은 w, j, wtimeout과 토폴로지(standalone / Replica Set)에 따라 달라지므로, §3은 구조 이해용이고 실제 보장 수준은 §7~8과 매뉴얼을 함께 읽는 것이 안전합니다.
아래는 개념 정렬용 흐름도입니다. j:true가 붙은 경우에만 저널 durable 이후에 응답이 나간다고 단정할 수 있으며, 기본 연결·w 조합에 따라 달라집니다.
4. WiredTiger Journal — 단일 노드 Durability의 기반
MongoDB의 기본 스토리지 엔진인 WiredTiger는 저널을 사용합니다. 데이터 디렉터리 아래 journal/(또는 설정에 따른 경로)에 저널 파일이 쌓이며, 파일명·회전 규칙은 버전과 설정에 따라 문서를 확인하는 것이 좋습니다.
4.1 저널에 기록되는 것
저널 레코드에는 어떤 트랜잭션·연산이 어떤 페이지 변경을 일으켰는지 등 복구에 필요한 정보가 담깁니다. 세부 필드·압축은 구현 세부사항에 가깝고, 운영자가 자주 보는 것은 복구 시 저널이 존재하는지, 디스크가 가득 차지 않았는지, 백업·스냅샷과의 관계입니다.
4.2 플러시 조건과 writeConcern
저널은 한동안 메모리 버퍼에 쌓였다가 디스크로 플러시될 수 있습니다. 플러시 타이밍은 storage.journal.commitIntervalMs 같은 서버 파라미터와, 클라이언트가 요청한 j: true(저널까지 기다림) 여부에 영향을 받습니다.
| 요인 | 요지 |
|---|---|
j: true | 해당 쓰기에 대해 저널이 durable storage에 기록될 때까지 응답을 지연시키려는 의도 |
journalCommitIntervalMs | 저널 커밋 간격(밀리초). 낮출수록 디스크 동기화는 잦아지고 지연·부하는 늘 수 있음 |
w: "majority" | Replica Set에서 과반수 멤버까지의 확인 규칙과 결합. writeConcernMajorityJournalDefault 등 서버 기본값에 따라 저널 의미가 달라질 수 있음 |
⚠️ 버퍼에만 있을 때: 저널이 아직 디스크에 남기 전에 전원이 꺼지면, 그 구간의 쓰기는 손실될 수 있습니다. “안전한 응답”을 원하면 j·w를 설계에 포함해야 합니다.
4.3 --nojournal 제거
과거에는 개발 환경에서 저널을 끄는 옵션이 있었으나, 최신 메이저에서는 저널 비활성화가 제거·강제되는 방향입니다. 정확한 버전 컷은 공식 릴리스 노트를 확인하세요.
5. Checkpoint — 주기적으로 일어나는 스냅샷
저널이 “최근 변경의 빠른 기록”이라면, Checkpoint는 캐시의 dirty 페이지를 데이터 파일에 반영해 두는 일관된 시점입니다. MongoDB/WiredTiger는 설정에 따라 주기적으로 체크포인트를 수행하며, 대표적으로 storage.syncPeriodSecs(초 단위)로 동기화 주기를 조절합니다(기본값은 문서 확인).
체크포인트가 끝나면:
- 데이터 파일이 그 시점까지 일관된 상태로 반영될 수 있고
- 그 이전에 불필요해진 저널은 정리될 수 있습니다(정책·버전에 따름).
체크포인트 작성 중 크래시가 나도, 메타데이터 갱신이 원자적으로 이뤄지는 방식 덕분에 이전 체크포인트로 되돌아가 복구하는 그림이 일반적입니다.
6. Journal과 Checkpoint — 크래시 복구 흐름
정상 운영 시:
- 체크포인트 T₀까지는 데이터 파일이 안정적이다.
- T₀ 이후 변경은 저널에 쌓이고, 메모리 캐시와 데이터 파일 사이에 아직 반영되지 않은 부분이 있을 수 있다.
T₀와 다음 체크포인트 사이에 프로세스가 죽으면, 재시작 시:
- 마지막으로 유효한 체크포인트를 찾는다.
- 그 이후 저널 레코드를 순서대로 replay 한다.
- 복구가 끝나면 서비스를 연다.
단일 노드에서 “저널이 디스크에 남기 전” 구간은 여전히 위험 구간입니다. 이를 줄이려면 j: true 또는 w·서버 파라미터를 함께 설계합니다.
7. Write Concern — 분산 환경에서의 Durability
Replica Set에서는 Primary 한 대의 저널만으로 부족합니다. Primary가 쓰기를 처리하고 응답했는데, 아직 다른 멤버에 복제되기 전에 Primary가 사라지면, 새 Primary 기준으로 롤백될 수 있는 쓰기가 생깁니다.
Write Concern은 “클라이언트에 성공을 알리기 전에 몇 멤버까지 확인할지”를 정하는 계약에 가깝습니다. 핵심 필드는 다음 세 가지입니다.
{
w: "majority", // 또는 숫자, "majority" 등
j: true, // 저널까지 요구할지(미지정 시 서버/연결 기본 따름)
wtimeout: 5000, // ms. 0은 무제한 대기에 가까울 수 있음
}
과반수 확인이 어떻게 Primary·Secondary와 맞물리는지는 배포마다 다르지만, 아래는 이해를 돕기 위한 개략입니다.
8. Write Concern 옵션 — w, j, wtimeout
8.1 w
w: 0: 응답을 거의 기다리지 않는 비승인(unacknowledged) 에 가깝습니다. 손실을 감수할 수 있는 로그 등 극히 제한적한 용도 외에는 권장하기 어렵습니다.w: 1: 보통 Primary까지의 확인에 가깝게 읽히지만, Secondary 복제 완료를 보장하지 않습니다. Failover 시나리오에서 이미 Primary에만 존재하던 쓰기는 위험할 수 있습니다.w: "majority": Replica Set에서 과반수가 요구 조건을 만족할 때까지 기다립니다. MongoDB 5.0부터 기본 write concern이majority로 바뀐 배경은, 운영 사례상w:1만으로는 장애 시 데이터가 사라질 수 있다는 문제를 줄이기 위함입니다.
아비터(arbiter) 가 있는 PSA(Primary–Secondary–Arbiter) 같은 구성에서는 “과반수”가 의미하는 바가 데이터를 가진 노드 수와 잘 맞는지 반드시 검토해야 합니다. 표준적인 3 데이터 멤버 구성과 동일하게 읽으면 안 됩니다.
8.2 j
j: true는 해당 write concern이 적용되는 멤버에서 저널까지 durable 하게 기록되었는지를 요구하려는 옵션입니다. j를 생략하면 연결·서버 기본과 w 조합에 따릅니다.
writeConcernMajorityJournalDefault: true(기본)인 경우, w: "majority"가 저널까지 포함한 의미로 해석되는 경로가 있습니다. 클러스터 설정을 반드시 확인하세요. 이 글에서는 “majority = 항상 동일한 저널 의미”로 단정하지 않고, 조건부임을 분명히 합니다.
8.3 wtimeout
wtimeout은 과반수(또는 지정한 w) 확인을 제한 시간 안에 받지 못했을 때 클라이언트에 오류를 돌려주기 위한 값입니다.
- 타임아웃은 **“쓰기가 Primary에 적용되지 않았다”**는 뜻이 아닐 수 있습니다. 이미 Primary에는 반영되었으나 복제 확인이 늦는 경우도 있습니다.
- 반대로,
w: "majority"를 만족하지 못한 채 Primary만 살아 있는 상태에서 장애가 나면, 그 쓰기는 선출 이후 롤백될 수 있습니다. 즉 “타임아웃 = 롤백 없음”도, “응답 = 영구 다수 커밋”도 동치가 아닙니다. 확인(ack) 실패와 장애 시 생존을 분리해서 생각해야 합니다.
프로덕션에서는 wtimeout을 명시해 무한 대기를 피하는 편이 일반적입니다.
9. 버전·릴리스와 Durability 구현 (참고)
메이저 버전마다 세컨더리 처리 순서·과반수 확인 경로·성능 특성이 달라질 수 있습니다. 예를 들어 “세컨더리가 데이터 파일 적용 전에 확인을 보낸다” 같은 파이프라인 최적화는 릴리스 노트·엔지니어링 블로그에서 설명되는 경우가 있으나, 본문에서 구체 버전의 내부 순서를 단정하지는 않겠습니다.
운영 중인 버전에서:
- Write Concern 정의
- 저널·복제 상호작용
- 기본 파라미터
는 Transactions, Write Concern, Replication을 우선 참고하는 것이 안전합니다.
10. Durability 설정 실전 가이드
10.1 금융·결제에 가깝게
const wcFinancial = {
w: "majority",
j: true,
wtimeout: 10000,
};
await db.collection("ledger").insertOne(doc, { writeConcern: wcFinancial });
읽기 쪽에서는 Part 3에서 다룬 readConcern: "majority" 등과 함께, “롤백 가능성을 줄인 읽기”를 설계할 수 있습니다.
10.2 일반 웹·서비스
많은 경우 기본 연결 write concern(majority) 과 적절한 wtimeout 만으로도 요구사항에 맞습니다. 다만 PSA·지역 분산·지연 큰 Secondary 같은 요인이 있으면 majority 확인이 자주 타임아웃날 수 있으니, SLO와 모니터링을 함께 두어야 합니다.
10.3 로그·분석(손실 허용)
// 예: 측정 이벤트(재전송 가능) — 팀 정책에 따라만 사용
await db.collection("events").insertOne(
{ type: "click", t: new Date() },
{ writeConcern: { w: 1, j: false } }
);
w: 0 에 가까운 모드는 운영 관측이 어렵고 장애 시 원인 추적이 힘들 수 있습니다.
10.4 서버 파라미터 (개략)
mongod.conf 예시(값은 환경·버전 문서 확인):
storage:
journal:
commitIntervalMs: 100
wiredTiger:
engineConfig:
cacheSizeGB: 4
commitIntervalMs를 낮추면 저널 플러시는 잦아질 수 있지만 I/O 부하는 늘 수 있습니다.
11. 장애 시나리오와 보호 수준 — 토폴로지 전제
아래는 이해를 돕기 위한 요약이며, 실제 보장은 멤버 수·아비터 유무·선출 규칙·지역 배치에 따라 달라집니다.
| 시나리오 | w: 0 | w: 1, j: false | w: 1, j: true | w: "majority" (전형적 3 데이터 멤버 가정) |
|---|---|---|---|---|
| Primary 프로세스 크래시(단일 노드 관점) | 매우 취약 | 취약할 수 있음 | 저널까지 기다렸다면 상대적으로 유리 | 복제 확인 전제 시 |
| Primary 장애 후 Failover | 복제 미확인 쓰기는 위험 | 동일 이슈 가능 | Primary만 확인 시 Secondary 미복제분은 위험 | 과반수 확인 후라면 설계상 완화 |
설계 원칙: w: "majority"는 정상적인 단일 노드 장애·전형적 선출에서 많은 케이스를 커버하지만, 과반수 멤버 동시 장애·네트워크 분할 같은 극단 상황은 인프라 이중화와 RPO/RTO 목표로 따로 다룹니다.
12. 마치며
Durability를 두 축으로 정리하면 다음과 같습니다.
단일 노드(WiredTiger): 메모리 변경 → 저널(WAL 계열) → 체크포인트로 데이터 파일 반영. 크래시 뒤에는 저널 replay 로 최대한 맞춘다.
Replica Set: Write Concern으로 “몇 멤버까지 확인했는가”를 계약하고, Failover 시 복제가 따라잡지 못한 쓰기가 롤백될 수 있음을 전제로 설계한다.
다음 Part 5에서는 실전 패턴·튜닝·안티패턴으로 이어갑니다. 본 편에서 다룬 readConcern·writeConcern은 Part 2·Part 3과 한 세트로 운영 문서를 읽는 것이 가장 안전합니다.
참고·출처
- MongoDB Manual — Write Concern
- MongoDB Manual — Journaling · Manage Journaling
- MongoDB Manual — Replica Set Primary
- MongoDB Manual — writeConcernMajorityJournalDefault
- MongoDB Manual — storage.syncPeriodSecs
- MongoDB Manual — storage.journal.commitIntervalMs
작성: 2026년 4월 · 제품 버전·기본값·드라이버 동작은 시점에 따라 달라질 수 있으니, 인용 시 사용 중인 버전의 공식 매뉴얼을 확인하세요.