CS
DB 장애 복구를 이해하는 WAL 기본기
Database는 매 요청마다 disk의 data page를 즉시 안전하게 고쳐 쓰지 않습니다.
대부분의 storage engine은 memory 안에서 page를 먼저 바꾸고, 변경 기록을 log에 남긴 뒤, 실제 data page flush는 나중에 처리합니다.
이때 장애가 나면 자연스럽게 질문이 생깁니다.
“COMMIT이 성공했다고 응답했는데 서버 전원이 꺼지면 데이터는 어디까지 살아남을까?”
이 질문의 핵심에 있는 개념이 WAL, 즉 Write-Ahead Log입니다.
WAL의 핵심은 data page를 영구 저장소에 반영하기 전에, 그 변경을 복구할 수 있는 log record를 먼저 durable 하게 기록하는 것입니다.

1. 들어가며
Database를 쓰다 보면 COMMIT이라는 단어를 자연스럽게 사용합니다.
하지만 COMMIT이 단순히 “메모리의 값을 바꿨다”는 뜻이라면 장애 상황에서 신뢰하기 어렵습니다.
서버 프로세스가 죽거나, OS가 panic을 내거나, 장비 전원이 꺼졌을 때도 이미 성공으로 응답한 transaction은 복구되어야 합니다.
반대로 COMMIT되지 않은 transaction의 중간 결과가 data file에 남아 있으면 안 됩니다.
WAL은 이 문제를 풀기 위한 대표적인 방식입니다.
변경 내용을 data page에 직접 반영하기 전에, 먼저 log file에 “무엇을 바꿨는지”를 순서대로 기록합니다.
장애가 난 뒤에는 이 log를 읽고 committed transaction은 다시 반영하고, 끝나지 않은 transaction은 되돌리거나 무시하는 방식으로 일관성을 회복합니다.
세부 구현은 database마다 다르지만, log를 먼저 안전하게 남긴다는 원칙은 많은 storage engine에서 공통으로 등장합니다.
| 관점 | WAL 없이 생각하면 | WAL을 사용하면 |
| 성능 | 작은 변경마다 data page를 즉시 안전하게 flush해야 함 | 순차 log append를 먼저 하고 page flush를 나중으로 미룰 수 있음 |
| 복구 | 장애 시 어떤 변경이 끝났는지 판단하기 어려움 | log record와 commit record를 기준으로 복구 지점을 판단함 |
| 일관성 | data file에 반쯤 반영된 변경이 남을 수 있음 | committed 변경과 incomplete 변경을 구분해 회복함 |
이 글에서는 WAL을 DB 내부 구현 세부사항이 아니라, 장애 복구를 이해하기 위한 CS 기본기로 정리해보겠습니다.
2. 왜 중요한가?
WAL은 backend 개발자가 직접 구현할 일이 많지는 않습니다.
하지만 database 장애, replication lag, backup, checkpoint, transaction durability를 다룰 때 계속 마주치는 개념입니다.
특히 운영 중 장애가 났을 때 “DB가 올라오면서 recovery를 수행한다”는 로그를 본다면, 내부적으로 어떤 종류의 일이 일어나는지 알아야 상황을 해석할 수 있습니다.
- COMMIT 성공 응답이 무엇을 의미하는지 이해할 수 있습니다.
- 장애 후 database가 바로 열리지 않고 recovery를 수행하는 이유를 설명할 수 있습니다.
- Checkpoint가 왜 필요한지, checkpoint가 너무 오래 밀리면 어떤 비용이 생기는지 이해할 수 있습니다.
- Replication이나 backup에서 log stream이 왜 중요한지 감을 잡을 수 있습니다.
- 면접에서 transaction, durability, storage engine을 한 흐름으로 설명하기 좋습니다.
WAL을 모르면 transaction을 단순히 SQL 문법으로만 이해하게 됩니다.
반대로 WAL을 이해하면 database가 성능과 안정성 사이에서 어떤 순서를 강제하는지 볼 수 있습니다.
3. 핵심 개념
WAL은 이름 그대로 “먼저 쓰는 log”입니다.
여기서 먼저 쓴다는 말은 data page를 먼저 고치는 것이 아니라, 복구 가능한 변경 기록을 먼저 durable 하게 저장한다는 뜻입니다.
Database는 보통 table이나 index 데이터를 page 단위로 관리합니다.
Transaction이 row를 수정하면 memory buffer 안의 page가 dirty page가 되고, 이 page는 나중에 disk로 flush될 수 있습니다.
| 개념 | 의미 | 실무에서 보는 지점 |
| Data page | table이나 index 데이터가 저장되는 page 단위 | buffer pool에 올라와 수정되고 나중에 flush됨 |
| Dirty page | memory에서는 바뀌었지만 disk data file에는 아직 반영되지 않은 page | 장애가 나면 disk file만 보고는 최신 상태를 알 수 없음 |
| Log record | 변경 내용을 복구할 수 있도록 순서대로 남긴 기록 | 장애 후 redo나 undo 판단의 근거가 됨 |
| Commit record | transaction이 완료되었음을 나타내는 log 기록 | durability 판단의 기준이 됨 |
| Checkpoint | 특정 시점까지의 page 상태와 log 적용 상태를 정리한 기준점 | recovery가 읽어야 하는 log 범위를 줄임 |
중요한 점은 data page flush와 COMMIT이 항상 같은 순간에 일어나지 않는다는 것입니다.
COMMIT 시점에는 변경된 page 전체가 disk에 내려가지 않았을 수 있습니다.
대신 WAL record가 durable 하게 기록되어 있으면, crash 이후에도 database는 그 변경을 다시 재생할 수 있습니다.
4. 그림으로 이해하기
WAL을 이해할 때 가장 중요한 순서는 log append, data page 변경, commit record, crash recovery입니다.
아래 그림은 transaction이 data page를 바꾸기 전에 WAL을 먼저 durable 하게 남기고, 장애 후 recovery가 그 log를 기준으로 page를 복구하는 흐름을 단순화한 것입니다.

그림을 볼 때 data page가 언제 disk에 실제 반영되는지보다, 복구 가능한 정보가 먼저 남았는지를 보는 것이 중요합니다.
Log가 먼저 durable 해져 있으면 page flush가 뒤로 밀려도 장애 복구가 가능합니다.
반대로 data page만 먼저 일부 반영되고 log가 없다면, database는 그 변경이 정상적으로 commit된 결과인지 판단하기 어렵습니다.
상태 변화
transaction 시작
row 변경 요청이 들어옴
WAL append
변경 내용을 log record로 먼저 기록
data page 수정
buffer pool의 page가 dirty page가 됨
COMMIT
commit record가 durable 해지면 성공 응답 가능
crash 발생
dirty page 일부는 disk에 내려갔을 수도 있고 아닐 수도 있음
recovery
WAL을 scan해서 committed transaction은 redo
incomplete transaction은 engine 정책에 따라 undo하거나 무시
이 상태 변화에서 핵심은 “log가 먼저다”입니다.
WAL이라는 이름은 바로 이 순서 제약을 말합니다.
5. 실무 예시
계좌 이체처럼 두 row를 함께 바꾸는 transaction을 생각해보겠습니다.
한 계좌에서는 금액을 빼고, 다른 계좌에는 금액을 더합니다.
둘 중 하나만 반영된 채로 장애가 나면 데이터 일관성이 깨집니다.
BEGIN;
UPDATE accounts
SET balance = balance - 100
WHERE id = 1;
UPDATE accounts
SET balance = balance + 100
WHERE id = 2;
COMMIT;
상태 변화
BEGIN 기록
transaction의 시작 정보가 남음
첫 번째 UPDATE log record 기록
id=1 balance 변경을 복구할 수 있는 정보가 WAL에 남음
두 번째 UPDATE log record 기록
id=2 balance 변경을 복구할 수 있는 정보가 WAL에 남음
COMMIT record 기록 및 flush
database가 사용자에게 commit 성공을 응답할 수 있음
장애 발생
data page 중 일부가 아직 flush되지 않았을 수 있음
recovery 수행
commit record가 있는 transaction의 update를 redo해서 두 계좌 변경을 일관되게 맞춤
여기서 WAL이 없으면 database는 장애 후에 두 UPDATE가 어디까지 안전하게 반영되었는지 확인하기 어렵습니다.
반면 WAL이 있으면 commit record를 기준으로 이 transaction이 완료되었는지 판단하고, 필요한 변경을 다시 적용할 수 있습니다.
실제 database는 isolation, lock, MVCC, undo log, page LSN 같은 더 많은 장치를 함께 사용하지만, 장애 복구의 큰 흐름은 WAL을 기준으로 이해할 수 있습니다.
| 장애 시점 | 복구 판단 | 결과 |
| UPDATE log는 있지만 COMMIT 전 | 완료되지 않은 transaction으로 봄 | engine 설계에 따라 undo하거나 최종 반영에서 제외 |
| COMMIT record가 durable 함 | committed transaction으로 봄 | data page 반영 여부와 무관하게 redo 가능 |
| Checkpoint 이후 log가 짧음 | 최근 log만 scan하면 됨 | recovery 시간이 줄어듦 |
| Checkpoint가 오래 밀림 | scan해야 하는 log 범위가 커짐 | 재시작 recovery 시간이 길어질 수 있음 |
운영 환경에서 “DB restart가 오래 걸린다”는 문제는 단순히 프로세스가 느린 것이 아닐 수 있습니다.
장애 전 dirty page와 log 상태, checkpoint 진행 상황, storage 성능에 따라 recovery 비용이 달라질 수 있습니다.
6. C++ 또는 DB와 연결해보기
WAL은 DB 내부 기능이지만, C++로 storage component를 만든다고 생각하면 더 직관적으로 이해할 수 있습니다.
예를 들어 key-value store가 memory table을 먼저 고치기 전에 append-only log에 변경을 남긴다고 해보겠습니다.
이때 log append와 flush가 성공한 뒤 memory 상태를 바꾸면, 프로세스가 죽어도 log를 다시 읽어 memory table을 복원할 수 있습니다.
| 단순 storage 구성 요소 | DB에서 대응되는 개념 | 복구 관점 |
| append-only log file | WAL segment | 장애 후 변경 이력을 순서대로 재생함 |
| in-memory map | buffer pool 또는 memtable | 빠르게 읽고 쓰지만 단독으로는 durable 하지 않음 |
| snapshot file | checkpoint 또는 flushed data file | 복구 시작 지점을 줄여줌 |
| sequence number | LSN | 어디까지 반영했는지 판단하는 기준이 됨 |
C++ 관점에서 보면 WAL은 특별한 문법이 아니라 순서와 실패 처리의 문제입니다.
파일에 썼다고 해서 항상 durable 한 것은 아니고, buffer, OS page cache, fsync, storage cache 같은 계층이 사이에 있습니다.
그래서 “log를 먼저 쓴다”는 말은 단순히 write 함수를 호출한다는 의미보다 더 엄격합니다.
사용자에게 성공을 응답하기 전에, 복구에 필요한 정보가 적절한 durability level로 남아 있어야 한다는 뜻에 가깝습니다.
예상 결과
정상 종료
snapshot 또는 data page가 최신 상태를 포함
WAL은 checkpoint 이후 필요한 범위만 유지 가능
COMMIT 직후 crash
data page가 오래된 상태여도 WAL에 commit record가 있으면 redo 가능
COMMIT 전 crash
commit record가 없으면 완료된 transaction으로 취급하지 않음
이 차이를 이해하면 database 설정도 더 현실적으로 볼 수 있습니다.
예를 들어 durability를 강하게 잡으면 commit latency가 늘 수 있고, group commit처럼 여러 transaction의 log flush를 묶어 비용을 줄이는 방식도 등장합니다.
결국 WAL은 성능을 포기한 기능이 아니라, 순차 append와 비동기 page flush를 활용하면서도 crash recovery를 가능하게 만드는 타협점입니다.
7. 자주 하는 오해
- COMMIT이 성공하면 data page가 반드시 즉시 disk에 저장된다.
일반적으로 핵심은 data page 전체가 즉시 flush되는 것이 아니라, recovery에 필요한 log가 durable 하게 남았는지입니다. 실제 page flush는 나중에 일어날 수 있습니다. - WAL은 backup과 같은 것이다.
WAL은 변경 이력 기반의 복구 재료이고, backup은 특정 시점의 데이터 사본입니다. 둘은 함께 쓰일 수 있지만 같은 개념은 아닙니다. - Checkpoint가 있으면 WAL은 필요 없다.
Checkpoint는 recovery가 시작할 기준점을 줄이는 역할입니다. checkpoint 이후 변경을 복구하려면 여전히 WAL이 필요합니다. - Log file만 있으면 언제나 즉시 복구된다.
Log 양, checkpoint 상태, storage 속도, page flush 상태에 따라 recovery 시간은 달라질 수 있습니다. - WAL은 DB 관리자만 알면 된다.
Backend 개발자도 장애 분석, transaction latency, replication, migration 계획을 이해하려면 WAL의 기본 흐름을 알고 있어야 합니다.
면접에서도 이 오해들을 풀어 설명하면 단순 암기보다 훨씬 좋은 답변이 됩니다.
특히 COMMIT과 data page flush를 같은 것으로 말하지 않는 것이 중요합니다.
8. 면접 질문 예시
WAL은 transaction의 ACID, storage engine, OS file system, 장애 복구를 함께 묻기 좋은 주제입니다.
- WAL은 무엇이고 왜 data page보다 먼저 기록해야 하나요?
WAL은 변경 내용을 복구 가능한 log record로 먼저 durable 하게 남기는 방식입니다. data page가 나중에 flush되거나 일부만 반영되더라도, crash recovery가 log를 기준으로 committed 변경을 redo할 수 있기 때문에 먼저 기록해야 합니다. - COMMIT 성공 직후 crash가 나면 database는 어떻게 복구하나요?
commit record가 durable 하게 남아 있다면 recovery 과정에서 해당 transaction을 committed로 보고 필요한 변경을 redo합니다. data page가 이미 flush되었는지 여부는 page의 반영 상태와 log sequence를 기준으로 판단합니다. - Checkpoint는 WAL과 어떤 관계가 있나요?
Checkpoint는 특정 시점까지의 반영 상태를 정리해 recovery가 읽어야 하는 log 범위를 줄입니다. WAL을 대체하는 것이 아니라, WAL scan 비용을 줄이기 위한 기준점입니다.
좋은 답변은 “log를 먼저 쓴다”에서 멈추지 않습니다.
Commit record, dirty page, redo, checkpoint, durability cost까지 연결해 말하면 실무 감각이 있는 답변이 됩니다.
9. 정리
WAL은 data page보다 변경 log를 먼저 durable 하게 기록하는 방식입니다.
Database는 memory의 dirty page를 나중에 flush할 수 있고, crash가 나면 WAL을 기준으로 committed 변경을 복구합니다.
COMMIT 성공은 보통 복구 가능한 log 기록이 안전하게 남았다는 의미로 이해해야 합니다.
Checkpoint는 WAL을 없애는 기능이 아니라 recovery가 scan해야 하는 log 범위를 줄이는 기준점입니다.
WAL을 이해하면 transaction durability, database restart recovery, replication, backup 전략을 더 현실적으로 해석할 수 있습니다.
WAL을 한 문장으로 정리하면, “먼저 복구할 수 있게 기록하고, 나중에 data page를 안전하게 따라오게 만드는 방식”입니다.
'CS' 카테고리의 다른 글
| Consistent Hashing, cache sharding에서 key 이동을 줄이는 방법 (0) | 2026.07.25 |
|---|---|
| DNS Lookup 흐름, Recursive Resolver부터 Authoritative DNS까지 (0) | 2026.07.21 |
| Cache Locality와 False Sharing 이해하기 (0) | 2026.07.14 |
| Page table과 TLB로 이해하는 OS memory 관리 (0) | 2026.07.10 |
| System call과 Context switch 차이 (1) | 2026.07.07 |
'CS'의 다른글
- 현재글DB 장애 복구를 이해하는 WAL 기본기