백업은 있는데 복구를 못 할 때, pg_dump와 PITR 중 무엇을 써야 할까요

백업은 있는데 복구를

백업은 있는데 복구를 못 하는 상황은 대부분 백업 방식과 복구 시간(RTO)을 미리 맞춰보지 않아서 생깁니다. pg_dump로 받은 백업은 논리적 스냅숏이라 특정 시점을 골라서 복구할 수 없고, PITR(Point-In-Time Recovery)은 원하는 시점을 고를 수 있는 대신 장애가 나기 전부터 WAL 아카이빙을 켜두지 않았다면 아예 쓸 수 없습니다. 이 글은 PostgreSQL 13 이상에서 recovery.signal / standby.signal 방식을 쓰는 환경을 전제로, 두 방식의 복구 시간과 전제조건을 데이터베이스 크기와 장애 허용 범위에 맞춰 고르는 기준을 정리합니다.

pg_dump 백업은 있는데 복구가 느리거나 안 되는 이유

pg_dump는 테이블의 데이터를 SQL 명령문이나 커스텀 포맷으로 뽑아내는 논리적 백업 도구입니다. 복구할 때는 그 명령문을 처음부터 다시 실행해서 테이블을 채우고 인덱스를 재생성하는 과정을 거칩니다.

이 구조 때문에 원본 데이터베이스가 수십 GB를 넘어가면 복구 시간이 데이터 양에 거의 비례해서 늘어납니다. 백업 파일 자체는 멀쩍이 존재하는데, 막상 장애가 터진 당일에 복구를 돌려보면 인덱스 재생성과 제약조건 검증에 생각보다 오랜 시간이 걸려서 “백업은 있는데 복구를 못 한다”는 말이 나오는 경우가 여기서 많이 발생합니다.

커스텀 포맷(-Fc)으로 뜬 백업은 pg_restore --jobs 옵션으로 병렬 복구가 가능해서 단일 스레드보다는 빠릅니다.

pg_dump -Fc -d mydb -f mydb.dump
pg_restore -d mydb_restore --jobs=4 mydb.dump

다만 병렬 복구도 테이블 단위로 쪼개 돌리는 것이라, 테이블 하나가 유독 크면 그 테이블이 전체 복구 시간을 좌우합니다. 그리고 pg_dump는 덤프를 뜬 순간의 스냅숏만 남기기 때문에, 장애가 덤프 시점과 장애 시점 사이에 일어난 쓰기 내역을 복구해 줄 방법이 원천적으로 없습니다.

PITR 복구가 pg_dump와 다르게 동작하는 원리

PITR은 물리적 베이스 백업 한 장과 그 이후 쌓인 WAL(Write-Ahead Log) 파일을 이어 붙여서, 베이스 백업 시점부터 원하는 임의의 시점까지 데이터베이스를 재생시키는 방식입니다. 그래서 “오늘 새벽 3시 직전 상태로 돌려달라”는 요청에 대응할 수 있습니다.

전제조건이 분명합니다. 장애가 나기 전부터 archive_mode를 켜고 WAL을 별도 저장소에 쌓아둬야 합니다.

archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'
wal_level = replica

서버실에서 데이터베이스 백업 및 복구 작업을 진행하는 모습

베이스 백업은 pg_basebackup으로 뜹니다.

pg_basebackup -D /var/lib/postgresql/16/main_base -Fp -Xs -P

장애가 발생하면 베이스 백업을 새 데이터 디렉터리로 복원한 뒤, 복구 설정을 넣고 recovery.signal 파일을 만들어 PostgreSQL을 재생 모드로 띄웁니다.

# postgresql.auto.conf에 추가
restore_command = 'cp /var/lib/postgresql/wal_archive/%f %p'
recovery_target_time = '2026-10-10 03:00:00+09'
recovery_target_action = 'promote'
touch /var/lib/postgresql/16/main_base/recovery.signal

복구가 진행되면 로그에 대략 이런 메시지가 쌓입니다. 정확한 트랜잭션 번호나 시각은 환경마다 다르지만 메시지 형식 자체는 PostgreSQL 공식 문서에 설명된 그대로입니다.

LOG:  starting point-in-time recovery to 2026-10-10 03:00:00+09
LOG:  restored log file "000000010000000000000005" from archive
LOG:  recovery stopping before commit of transaction, time 2026-10-10 03:00:01+09
LOG:  selected new timeline ID: 2

pg_dump와 PITR, 복구 시간(RTO) 기준으로 비교해 보세요

두 방식 중 하나를 고를 때는 “얼마나 빨리 복구해야 하는가”와 “얼마나 최근 시점까지 되돌려야 하는가”를 나눠서 봐야 합니다. 전자가 RTO이고 후자가 RPO(복구 시점 목표)입니다.

구분 pg_dump (논리적 백업) pg_basebackup + WAL (PITR)
복구 가능 시점 덤프를 뜬 순간 하나뿐 베이스 백업 이후 임의 시점 선택 가능
복구 시간 경향 DB 크기에 비례, 인덱스 재생성 포함돼 길어짐 베이스 백업 복원 + WAL 재생 시간 (대체로 더 짧음)
저장공간 덤프 파일 크기만 베이스 백업 + 누적 WAL 아카이브
사전 설정 필요 없음, 바로 실행 가능 archive_mode·archive_command를 장애 전에 켜둬야 함
테이블 단위 선택 복구 가능 (-t 옵션) 불가능, 클러스터 전체 단위로만 복구

표에서 보듯 RPO를 짧게 유지하려면 PITR이 유리하지만, 사전 설정이 안 돼 있던 서버에서는 장애 당일에 쓸 수 있는 선택지가 아닙니다. 반대로 pg_dump는 설정 없이 바로 쓸 수 있지만 RPO가 “마지막 덤프 시점”으로 고정됩니다.

특정 시점으로 데이터를 복원하는 타임라인 개념 이미지

복구 시간 목표에 맞춰 백업 전략을 고르는 기준

데이터베이스 크기가 수 GB 수준이고 하루 한 번 정도 복구해도 괜찮은 서비스라면 pg_dump만으로 충분합니다. 설정이 단순하고, 테이블 단위로 부분 복구도 되기 때문에 운영 부담이 작습니다.

데이터베이스가 수백 GB를 넘거나, 장애 발생 직전 몇 분 단위까지 데이터를 살려야 하는 서비스라면 PITR 구성이 거의 필수입니다. 다만 WAL 아카이브가 계속 쌓이는 만큼 저장공간과 보관 주기 정책(오래된 WAL과 베이스 백업을 언제 지울지)을 같이 정해둬야 디스크가 차서 서비스가 멈추는 역설적인 상황을 피할 수 있습니다.

두 방식을 함께 쓰는 것도 흔한 선택입니다. 매일 새벽 pg_dump로 논리적 백업을 하나 남겨두고, 평소에는 PITR 체계를 운영하다가 WAL 체인이 꼬이는 등 PITR이 실패했을 때 pg_dump 백업으로 최소한의 시점까지는 복구할 수 있게 이중화하는 방식입니다.

WAL 아카이빙을 켜두고도 복구가 막히는 경우들

PITR을 설정해 뒀다고 안심할 수는 없습니다. 실제로 자주 걸리는 지점은 다음 세 가지입니다.

첫째, archive_command가 한 번이라도 실패하면 그 뒤 WAL 체인이 끊깁니다. PostgreSQL은 끊긴 지점 이후로는 재생을 멈추기 때문에, 복구 가능한 시점이 생각보다 훨씬 과거로 밀립니다.

둘째, 베이스 백업 자체를 한 번도 복구 테스트해보지 않은 경우입니다. pg_basebackup이 정상 종료됐다고 해서 그 백업으로 실제 복구가 되는지는 별개 문제입니다. 디스크 공간 부족이나 권한 문제로 베이스 백업 파일 일부가 손상돼 있어도 백업 당시에는 발견되지 않습니다.

셋째, 복구 대상 서버의 PostgreSQL 버전이 백업을 뜬 서버와 다른 경우입니다. 물리적 백업은 메이저 버전이 같아야 하고, 마이너 버전 차이도 디스크 포맷 변경이 있었다면 문제가 될 수 있습니다. 이런 이유로 복구 리허설을 정기적으로 해보는 것이 백업 자체를 늘리는 것보다 더 중요하다는 평가가 나옵니다.

recovery_target_time을 지정해도 그 시점에 멈추지 않는 이유는 무엇인가요

recovery_target_time을 지정했는데 그보다 훨씬 전이나 후 시점에서 복구가 끝나는 경우가 있습니다. 가장 흔한 원인은 지정한 시간대(timezone) 표기 누락입니다. 서버 로그는 서버의 log_timezone 기준으로 찍히는데, recovery_target_time에 오프셋을 빼고 적으면 세션 타임존 기준으로 해석되어 오차가 생깁니다.

두 번째 원인은 WAL 아카이브에 그 시점을 포함하는 WAL 파일이 아예 없는 경우입니다. 이때는 조용히 실패하지 않고, 있는 WAL 중 가장 마지막 지점까지만 재생한 뒤 멈춥니다. 복구를 시작하기 전에 pg_waldump나 아카이브 디렉터리의 파일 타임스탬프로 원하는 시점의 WAL이 실제로 존재하는지 먼저 확인해두는 것이 안전합니다.

기본키를 UUID로 했더니 느려질 때 — UUIDv4·UUIDv7·BIGSERIAL 비교

Leave a Comment