주기적으로 메모리의 더티 페이지를 디스크에 내리고 "여기까진 데이터 파일에 반영됨"이라는 표시를 남기는 작업.
없으면 무슨 일이 생기나
체크포인트가 없다면
- 복구가 로그의 맨 처음부터 다 훑어야 한다
- 오래 운영한 DB 는 복구에 몇 시간이 걸릴 수 있다
체크포인트가 있으면
- 마지막 체크포인트 이후의 로그만 보면 된다
트레이드오프
-
잦으면 — 복구는 빠르다 (볼 로그가 적다)
- 평상시 디스크 I/O 부담이 크다 (자주 내리느라)
-
드물면 — 평상시는 한가하다
- 복구가 오래 걸린다
- 한 번 돌 때 몰아서 쓰느라 I/O 스파이크가 생긴다
"드물면 평상시가 편하다"가 항상 맞지는 않다 — 몰아 쓰는 순간의 스파이크가 응답 시간을 튀게 만든다.
설정
-- PostgreSQL
SHOW checkpoint_timeout; -- 기본 5min
SHOW max_wal_size; -- 이 크기를 넘으면 시간과 무관하게 체크포인트
SHOW checkpoint_completion_target; -- 0.9 = 다음 체크포인트까지 90% 시간에 걸쳐 천천히 쓴다
-- 얼마나 자주 도는지, 스파이크가 있는지
SELECT * FROM pg_stat_checkpointer; -- PG17+ (이전은 pg_stat_bgwriter)
checkpoint_completion_target이 핵심이다 — 한꺼번에 쏟아붓지 않고 다음 체크포인트까지 나눠 쓰게 해서 I/O 스파이크를 평탄화한다.
-- MySQL InnoDB — redo 로그 용량이 사실상 체크포인트 간격을 정한다
SHOW VARIABLES LIKE 'innodb_redo_log_capacity';
SHOW ENGINE INNODB STATUS\G -- LOG 섹션의 checkpoint age 를 본다
로그가 너무 자주 도는지 보는 법
-- PostgreSQL: requested(용량 초과로 강제) 가 timed(정해진 주기) 보다 많으면
-- max_wal_size 가 작다는 신호다
SELECT num_timed, num_requested FROM pg_stat_checkpointer;
num_requested가 크면 WAL 용량이 부족해 강제로 체크포인트가 돌고 있다 — max_wal_size를 키우면 I/O가 안정된다.
면접 함정
- ❌ "체크포인트는 데이터를 안전하게 만든다" → 안전은 WAL이 이미 보장한다. 체크포인트는 복구를 빠르게 하는 최적화다.
- ❌ "자주 돌수록 좋다" → 평상시 I/O를 갉아먹는다. 복구 시간 목표(RTO)와 맞춰 정한다.
스파이크를 눈으로 확인하기
-- 체크포인트가 돌 때마다 쓰기 지연이 튀는지 본다
SELECT num_timed, num_requested,
write_time, sync_time, -- 쓰기·동기화에 쓴 밀리초
buffers_written
FROM pg_stat_checkpointer;
sync_time이 크면 디스크에 강제 동기화하느라 멈춘 시간이다. 이 값이 크면 응답 시간에 주기적 스파이크가 나타난다.
튜닝 방향
증상: 5분마다 응답 시간이 튄다
- checkpoint_completion_target 을 0.9 로 (기본값) 확인
- max_wal_size 를 키워 체크포인트 간격을 늘린다
- 그래도 튀면 디스크 I/O 대역이 부족한 것이다
증상: 크래시 복구가 너무 오래 걸린다
- 반대로 max_wal_size 를 줄인다 (평상시 I/O 를 더 쓴다)