11.4 WAL 아카이브와 PITR
Point-In-Time Recovery(PITR)은 base 백업 + 그 이후의 WAL을 외부 저장소로 보내 두었다가, 사고 시 원하는 시점까지 재생해 복원하는 기법입니다. 분 단위 RPO·실수 SQL의 원복·테스트 환경 재현 등에 표준입니다. archive 설정·기본 복구·복구 시점 지정을 정리합니다.
큰 그림
flowchart LR
PG["PostgreSQL primary"]
WAL["pg_wal/<br/>16MB 세그먼트"]
ARCH["archive_command<br/>외부 저장소로 복사"]
STORE["S3 / NFS / etc."]
BASE["pg_basebackup<br/>(주기적 base)"]
PG --> WAL --> ARCH --> STORE
PG --> BASE --> STORE
classDef pg fill:#ede9fe,stroke:#6d28d9,color:#3b0764,stroke-width:2px
classDef step fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef store fill:#d1fae5,stroke:#047857,color:#064e3b
class PG pg
class WAL,ARCH,BASE step
class STORE store
복구는 역순:
flowchart LR
STORE["저장소"]
BASE_R["base 복구"]
WAL_R["WAL 재생"]
TARGET["recovery_target_time<br/>또는 LSN·xid"]
NEW["복구된 클러스터"]
STORE --> BASE_R --> WAL_R
WAL_R -. 까지 .-> TARGET
TARGET --> NEW
classDef step fill:#fed7aa,stroke:#c2410c,color:#7c2d12
classDef done fill:#d1fae5,stroke:#047857,color:#064e3b
class BASE_R,WAL_R,TARGET step
class NEW done
archive 설정
postgresql.conf:
wal_level = replica # 또는 logical
archive_mode = on
archive_command = '/usr/bin/test ! -f /archive/%f && cp %p /archive/%f'
archive_timeout = 60s # 빈 클러스터도 1분마다 강제 archive| 변수 | 의미 |
|---|---|
%f | WAL 세그먼트 파일명 |
%p | 절대 경로 (PGDATA/pg_wal/…) |
%r | 마지막 재시작 포인트 |
archive_command는 종료 코드 0만 성공으로 인정. 실패하면 PostgreSQL이 같은 세그먼트를 반복 재시도 — 누락 없습니다. 단, 계속 실패하면 pg_wal/이 가득 찹니다.
실전 archive 명령
# 로컬 디렉토리
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'
# rsync to remote
archive_command = 'rsync -aq %p backup_user@backup_host:/archive/%f'
# pgBackRest 표준
archive_command = 'pgbackrest --stanza=main archive-push %p'
# AWS S3 (예: barman-cloud-wal-archive)
archive_command = 'barman-cloud-wal-archive -P aws s3://my-bucket/wal main %p'restore_command
복구 시 PostgreSQL이 archive에서 WAL을 가져오는 명령합니다. postgresql.conf(PG 12+) 또는 recovery.conf(PG 11까지)에 정의합니다.
restore_command = 'cp /archive/%f %p'
# 또는
restore_command = 'pgbackrest --stanza=main archive-get %f %p'복구 모드 트리거 (PG 12+):
# 빈 PGDATA에 base 풀어 둠
tar xf base.tar -C /var/lib/pgsql/17/data
# recovery 트리거 파일
touch /var/lib/pgsql/17/data/recovery.signal
# (standby로 띄우려면 standby.signal)
# postgresql.conf에 restore_command 설정 후
pg_ctl start -D /var/lib/pgsql/17/data복구 시점 지정
postgresql.conf에 하나의 타깃을 설정:
| 옵션 | 의미 |
|---|---|
recovery_target_time = '2026-05-23 10:00:00' | 시간 |
recovery_target_lsn = '0/3A1F8E0' | LSN |
recovery_target_xid = '12345' | 트랜잭션 ID |
recovery_target_name = '<savepoint>' | named restore point |
recovery_target = 'immediate' | base 백업 직후 일관성 회복 시점 |
recovery_target_time = '2026-05-23 09:55:00'
recovery_target_action = 'promote' # 도달 후 자동 promote (read-write)
# 또는 'shutdown' / 'pause'named restore point
운영 자체적으로 체크포인트를 박을 수 있습니다.
SELECT pg_create_restore_point('before-bad-deploy');이후 복구 시:
recovery_target_name = 'before-bad-deploy'대규모 배포·마이그레이션 전 표준 패턴입니다.
복구 절차 — 표준
- 새 호스트(또는 정지된 호스트)에 빈 PGDATA 준비
- 가장 최근의 base 백업을 복원 (tar 풀기 또는
pg_basebackup결과 복사) postgresql.conf에restore_command·recovery_target_*설정recovery.signal파일 생성- 클러스터 기동
- WAL 재생 진행 (
pg_stat_activity의startup process추적) - 타깃 도달 후
pause이면 운영자 검증 →SELECT pg_wal_replay_resume(); - promote 완료 후 새 timeline 생성합니다. read-write 클러스터로 가동
timeline
복구가 끝나 promote되면 새 timeline이 만들어집니다. WAL 파일명의 첫 8자리가 timeline ID.
000000010000000000000003A # timeline 1
000000020000000000000003A # timeline 2 (PITR 후)같은 timeline 안의 WAL을 이미 다른 복구가 사용했더라도 새 timeline은 자기 흐름을 새로 만듭니다. PostgreSQL이 자동 관리하므로 운영자가 직접 timeline 다룰 일은 거의 없습니다.
pg_waldump — 디버깅
pg_waldump /archive/000000010000000000000003A | headWAL 안의 record를 사람이 읽을 수 있게 출력합니다. 언제 어떤 변경이 들어왔는지 추적할 때.
모니터링
SELECT * FROM pg_stat_archiver;
-- archived_count, last_archived_wal, last_archived_time,
-- failed_count, last_failed_wal, last_failed_timefailed_count 또는 last_failed_time 새 값 = archive 실패. 즉시 대응합니다.
-- 복구 진행 중
SELECT pg_is_in_recovery(), pg_last_wal_replay_lsn(),
pg_last_xact_replay_timestamp();복구 중에는 pg_is_in_recovery() = true.
흔한 사고
| 사고 | 원인 |
|---|---|
| archive 실패 누적 → pg_wal 꽉 참 → 클러스터 정지 | archive 모니터링 부족 |
| 복구 시 WAL 누락 | archive 보존 정책이 너무 짧음 |
restore_command가 실패 종료 안 함 | “WAL 없음"을 PostgreSQL이 못 알아 끝없이 기다림 — 종료 코드 1로 명확히 |
| timeline 혼동 | base와 WAL의 timeline 안 맞음 |
| recovery_target 잘못 지정 | 복구 후 새 timeline이라 다시 복구 어렵다 |
운영 자동화
수동 archive_command 관리는 운영 부담입니다. pgBackRest/Barman이 archive_command·restore_command·archive 보존을 통합 관리 — 다음 절(11.5, 11.6) 참고합니다.
정리
- WAL archive =
archive_command로 완료된 WAL 세그먼트를 외부 저장소로 - restore_command + recovery.signal + recovery_target_* 로 PITR
- 시점 지정은 time/LSN/xid/named restore point
- PITR 끝나면 새 timeline 생성 — 원복 시 같은 출발에서 다시
- archive 모니터링은
pg_stat_archiver— 실패는 즉시 대응 - 운영 자동화는 pgBackRest/Barman으로 감싸기
다음 절(11.5)에서는 사실상 표준이 된 백업 도구 — pgBackRest를 봅니다.