LLM WikiAccess-protected knowledge portal
← 스터디 홈
6편 · 약 14분

백업·복구(pg_dump, PITR)

백업 없는 데이터베이스는 시한폭탄이다

장애는 언제든 발생한다. 잘못된 DELETE, DROP TABLE, 하드웨어 고장, 랜섬웨어 감염 등 원인은 다양하다. 백업이 없거나 복구 절차를 한 번도 검증하지 않은 상태에서 장애를 맞으면 데이터를 되살릴 방법이 없다. PostgreSQL은 두 가지 백업 방식을 제공한다. 논리 백업은 SQL 덤프를 생성하고, 물리 백업은 파일 시스템 수준의 스냅샷을 저장한다. 두 방식의 차이를 이해하고 상황에 맞게 선택해야 한다.

논리 백업: pg_dump / pg_dumpall

pg_dump는 지정한 데이터베이스를 SQL 스크립트 또는 아카이브 파일로 내보낸다. 운영 중인 서버에서 실행 가능하며, 별도의 서버 설정 없이 바로 사용할 수 있다.

출력 포맷

플래그포맷특징
없음 (기본)plain SQL사람이 읽을 수 있음, psql로 복원
-Fccustom압축, 선택적 복원, pg_restore 사용
-Fddirectory멀티 파일, 병렬 덤프/복원 지원
-Fttartar 아카이브

운영 환경에서는 custom 포맷(-Fc) 또는 directory 포맷(-Fd) 을 사용한다. 압축이 내장되어 있고, pg_restore -j로 병렬 복원이 가능해 대용량 데이터베이스에서 복원 시간을 크게 줄일 수 있다.

자주 쓰는 pg_dump 명령

# custom 포맷으로 단일 DB 백업
pg_dump -U postgres -Fc -f mydb.dump mydb

# 특정 테이블만 백업
pg_dump -U postgres -Fc -t orders -t order_items -f orders.dump mydb

# 데이터 없이 스키마만 백업
pg_dump -U postgres -Fc --schema-only -f schema.dump mydb

# 병렬 4 job으로 복원 (directory 포맷)
pg_restore -U postgres -d mydb -j 4 mydb_dir/

pg_dumpall

pg_dumpall은 클러스터 전체(역할, 테이블스페이스, 모든 데이터베이스)를 SQL 스크립트로 내보낸다. 역할(Role) 이나 전역 설정까지 포함해야 할 때 사용한다.

pg_dumpall -U postgres -f full_cluster.sql
psql -U postgres -f full_cluster.sql   # 복원

논리 백업의 한계

논리 백업은 특정 시점의 스냅샷만 저장한다. 덤프 직후 변경된 데이터는 포함되지 않는다. 대용량 데이터베이스는 덤프·복원 모두 시간이 오래 걸리고, Point-in-Time Recovery(PITR) 를 지원하지 않는다.

물리 백업: pg_basebackup

pg_basebackup은 운영 중인 PostgreSQL 서버에서 파일 시스템 수준의 전체 복사본(베이스 백업) 을 만든다. WAL 아카이빙 및 PITR의 시작점이 된다.

# 단순 베이스 백업 (tar, gzip 압축)
pg_basebackup -h localhost -U replicator \
  -D /backup/base \
  -Ft -z -P

# 복제 설정 자동 포함 (-R)
pg_basebackup -h localhost -U replicator \
  -D /var/lib/postgresql/17/standby \
  -Fp -Xs -P -R
옵션의미
-Fpplain (파일 그대로)
-Fttar 아카이브
-XsWAL을 스트리밍으로 포함
-zgzip 압축
-Rstandby.signal + primary_conninfo 자동 생성
-P진행률 표시

WAL 아카이빙 설정

PITR을 사용하려면 두 가지가 필요하다: 베이스 백업WAL 아카이브. WAL 아카이빙은 WAL 세그먼트가 완성될 때마다 지정한 위치로 복사하는 작업이다.

# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'cp %p /archive/%f'   # %p = 소스 경로, %f = 파일명

archive_command는 성공 시 exit code 0을 반환해야 한다. 실패하면 PostgreSQL이 해당 세그먼트를 계속 재시도하며, 아카이브가 따라잡지 못하면 pg_wal/이 증가한다.

운영 환경에서는 단순 cp 대신 S3, NFS, pgBackRest 같은 신뢰성 있는 대상을 사용한다:

# AWS S3 예시 (aws cli 필요)
archive_command = 'aws s3 cp %p s3://my-wal-bucket/wal/%f'

PITR 복구 절차

PITR은 베이스 백업에 WAL을 재생(replay)하여 특정 시점으로 복구하는 기법이다.

시간 WAL 아카이브 (연속 기록) 베이스 백업 복구 목표 시각 장애 발생 ① 베이스 백업 복원 pg_basebackup 결과물 ② WAL 재생 restore_command ③ 목표 도달 → promote recovery_target_action=promote
PITR 복구 흐름 — 베이스 백업 + WAL 재생으로 목표 시점 복원

복구 절차 단계별

1단계: 베이스 백업을 새 디렉터리에 복원

# 기존 데이터 디렉터리 백업 이동
mv /var/lib/postgresql/17/main /var/lib/postgresql/17/main.bak

# 베이스 백업 복원
tar -xzf /backup/base.tar.gz -C /var/lib/postgresql/17/main

2단계: 복구 파라미터 설정

PostgreSQL 12 이후에는 recovery.conf가 없다. postgresql.conf에 직접 복구 파라미터를 추가한다.

# postgresql.conf
restore_command = 'cp /archive/%f %p'
recovery_target_time = '2024-01-03 14:00:00'
recovery_target_action = 'promote'   # 완료 후 읽기/쓰기 모드로 전환

3단계: recovery signal 파일 생성

touch /var/lib/postgresql/17/main/recovery.signal

recovery.signal 파일이 존재하면 PostgreSQL은 복구 모드로 시작한다.

4단계: PostgreSQL 시작 및 완료 확인

pg_ctlcluster 17 main start

# 로그에서 복구 완료 메시지 확인
tail -f /var/log/postgresql/postgresql-17-main.log
# LOG:  database system is ready to accept connections

복구 목표 옵션

recovery_target_time 외에도 다양한 방식으로 복구 목표를 지정할 수 있다.

파라미터의미예시
recovery_target_time특정 시각까지 재생'2024-01-03 14:00:00+09'
recovery_target_lsn특정 LSN까지 재생'0/5000000'
recovery_target_xid특정 트랜잭션 ID까지 재생'12345'
recovery_target_namepg_create_restore_point()로 만든 명명 복원점'before_migration'
recovery_target'immediate' = 베이스 백업 직후 일관된 상태'immediate'
-- 운영 중 복원 지점 생성 (마이그레이션 전 스냅샷 역할)
SELECT pg_create_restore_point('before_v2_migration');

recovery_target_inclusive는 목표 지점 직전까지만 재생할지(false) 목표 지점 트랜잭션까지 포함할지(true, 기본값)를 결정한다.

pgBackRest: 프로덕션 백업 도구

단순 cppg_basebackup 직접 사용은 소규모에서는 충분하지만, 대용량 운영 환경에서는 한계가 있다. pgBackRest는 PostgreSQL 전용 오픈소스 백업 도구로 다음 기능을 제공한다.

  • 증분·차등 백업: 변경된 블록만 백업해 저장 공간 절약
  • 병렬 압축: 멀티 코어를 활용해 pg_dump보다 10배 이상 빠른 백업
  • WAL 아카이빙 통합: archive_command로 바로 연결
  • 원격 저장소: S3, Azure Blob, GCS 지원
  • 보존 정책: 자동 오래된 백업 삭제
# pgBackRest PITR 복구 예시 (특정 시각으로 복원)
pgbackrest --stanza=mydb \
  --type=time \
  --target="2024-01-03 14:00:00+09" \
  --target-action=promote \
  restore

백업 방식 비교

항목pg_dumppg_basebackup + WALpgBackRest
백업 범위단일 DB (논리)클러스터 전체 (물리)클러스터 전체 (물리)
PITR 지원
증분 백업
복원 속도느림 (대형 DB)빠름매우 빠름 (병렬)
설정 복잡도낮음중간높음
적합한 규모소규모 / 개발중소규모프로덕션

DBA 체크리스트

  • 백업 직후 반드시 복원 테스트를 수행한다. 복원이 성공해야 백업이다.
  • archive_command 실패는 로그에서 확인하고 즉시 해결한다. 아카이브가 끊기면 PITR 범위에 구멍이 생긴다.
  • recovery_target_time에는 타임존을 명시한다('2024-01-03 14:00:00+09'). 서버 타임존과 혼동하면 엉뚱한 시점으로 복구된다.
  • 논리 백업(pg_dump)은 매일 1회 이상, WAL 아카이빙은 연속적으로 수행한다.
  • pgBackRest를 사용할 경우 보존 정책(repo1-retention-full, repo1-retention-archive)을 명시해 디스크가 가득 차지 않도록 한다.
  • recovery.signal 파일을 삭제하지 않으면 PostgreSQL이 항상 복구 모드로 시작한다. promote 완료 후 파일이 자동 삭제되는지 확인한다.

References

  • https://www.postgresql.org/docs/current/backup-dump.html
  • https://www.postgresql.org/docs/current/app-pgdump.html
  • https://www.postgresql.org/docs/current/app-pgbasebackup.html
  • https://www.postgresql.org/docs/current/continuous-archiving.html
  • https://www.postgresql.org/docs/current/recovery-config.html
  • https://pgbackrest.org/user-guide.html
  • https://dzone.com/articles/point-in-time-recovery-pitr-in-postgresql
  • https://stormatics.tech/blogs/postgresql-backup-best-practices
  • https://dev.to/mohhddhassan/postgresql-backups-and-point-in-time-recovery-with-pgbackrest-13gp