데이터 파일을 바꾸기 전에, 그 변경 내역을 로그에 먼저 디스크에 기록한다는 규칙. 이름 그대로 Write-Ahead다.
왜 이 순서인가
데이터 파일 쓰기 디스크 곳곳의 페이지를 랜덤하게 쓴다 → 비싸다
그래서 메모리 버퍼에 모아 뒀다가 나중에 내린다
↓
그 사이 크래시가 나면 메모리 변경은 사라진다
로그 쓰기 한 파일에 순차로 덧붙인다 → 싸다
커밋 시점에 '변경의 기록' 만이라도 디스크에 박아 둔다
두 가지를 동시에 얻는다
-
지속성 — 커밋 순간 데이터 페이지는 아직 메모리에 있어도,
- 로그만 디스크에 있으면 크래시 후 다시 적용해 복원할 수 있다
-
성능 — 느린 랜덤 데이터 쓰기를 뒤로 미루고
- 빠른 순차 로그 쓰기만 커밋 경로에 둔다 → 오히려 빨라진다
"안전장치를 넣었더니 더 빨라졌다"는 드문 사례다.
두 엔진의 구성
- PostgreSQL — WAL 하나 (redo 역할)
- 롤백·MVCC 용 undo 는 힙의 옛 튜플로 처리한다
MySQL InnoDB redo 로그 (지속성·롤포워드) 와
- undo 로그 (롤백·MVCC) 를 분리한다
설정과 관측
-- PostgreSQL
SHOW wal_level; -- replica (기본). PITR·복제에 필요
SHOW synchronous_commit; -- on = 커밋 시 WAL 을 디스크에 flush
SELECT pg_current_wal_lsn(); -- 현재 WAL 위치(LSN)
-- MySQL
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit'; -- 1(기본)/2/0
SHOW VARIABLES LIKE 'innodb_redo_log_capacity';
지속성은 흥정 가능한 값이다
SET synchronous_commit = off; -- PostgreSQL
SET GLOBAL innodb_flush_log_at_trx_commit = 2; -- MySQL
둘 다 커밋 때 디스크 flush를 생략해 쓰기 처리량을 크게 올린다. 대신 크래시 시 최근 수백 밀리초~1초치를 잃을 수 있다. 로그성 테이블처럼 몇 건 잃어도 되는 데이터에는 합리적인 선택이고, 결제에는 절대 쓰면 안 된다.
면접 함정
- ❌ "WAL은 성능을 희생해 안전을 얻는 것" → 순차 쓰기라 오히려 빠르다.
- ❌ "커밋되면 데이터 파일에 저장된다" → 커밋 시점에 확실한 건 로그뿐이다. 데이터 파일 반영은 나중이다.
WAL이 쌓이기만 하면 디스크가 찬다
-- 복제 슬롯이 끊긴 복제본을 기다리며 WAL 을 붙잡고 있는지 확인한다
SELECT slot_name, active,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained
FROM pg_replication_slots;
-- 현재 WAL 디렉터리 크기
SELECT pg_size_pretty(sum(size)) FROM pg_ls_waldir();
비활성 복제 슬롯(active = false) 이 가장 흔한 원인이다. 떠난 복제본의 슬롯을 안 지우면 WAL이 무한히 쌓여 디스크가 찬다.
SELECT pg_drop_replication_slot('old_standby'); -- 더는 안 쓰는 슬롯을 정리한다
MySQL의 대응물
SHOW BINARY LOGS; -- binlog 목록과 크기
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY;
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds'; -- 자동 정리 기간