데이타베이스/PostgreSQL

데이터 손실, 이제 안녕! PostgreSQL 시점 복구(PITR) 완벽 가이드

shimdh 2025. 10. 30. 18:29
728x90

PostgreSQL을 운영하는 데이터베이스 관리자(DBA)라면 누구나 한 번쯤 데이터 손실의 공포를 느껴본 적이 있을 겁니다. 실수로 중요한 테이블을 삭제하거나, 시스템 오류로 데이터가 손상되거나, 심지어 랜섬웨어 같은 악의적인 공격까지... 이런 상황에서 PostgreSQL의 시점 복구(Point-in-Time Recovery, PITR) 가 바로 당신의 구원자입니다. PITR은 데이터베이스를 정확한 과거 시점으로 되돌려 복원할 수 있게 해주며, 데이터 손실을 최소화하고 비즈니스 연속성을 유지하는 데 필수적인 기능입니다.

이 글에서는 PITR의 작동 원리부터 실제 구현 방법, 그리고 실전 시나리오까지 단계별로 자세히 안내하겠습니다. 초보자도 쉽게 따라할 수 있도록 코드 예시와 팁을 추가로 보강했으니, 끝까지 읽어보세요. 데이터 보호를 강화하고 싶다면 지금 당장 PITR을 도입해보세요!

728x90

PITR, 왜 필수적인가?

현대 비즈니스에서 데이터는 단순한 '정보'가 아닙니다. 고객 정보, 거래 기록, 분석 데이터 등은 회사의 생명줄입니다. 데이터 손실은 재정적 피해(예: 복구 비용 수억 원), 고객 신뢰 상실(리뷰 폭락), 심지어 법적 책임(개인정보 보호법 위반) 까지 초래할 수 있습니다. 전통적인 풀 백업만으로는 오류 발생 직후의 '깨끗한 상태'로 돌아가기 어렵죠.

PITR의 강점은 정밀한 롤백입니다. 예를 들어, 오후 2시에 발생한 버그로 데이터가 손상됐다면, 오전 11시 59분으로 정확히 되돌릴 수 있습니다. 이는 다운타임을 최소화하고, 비즈니스 중단을 방지합니다. 실제로, Gartner 보고서에 따르면 데이터 손실로 인한 평균 다운타임 비용은 시간당 5,600달러(약 700만 원)에 달합니다. PITR은 이런 리스크를 '예방'하는 최고의 전략입니다.

PITR의 핵심 구성 요소

PITR은 PostgreSQL의 내장 기능으로, 여러 요소가 조합되어 작동합니다. 아래에서 각 요소를 자세히 살펴보겠습니다.

1. WAL(Write-Ahead Logging) 파일과 연속 아카이빙

PostgreSQL은 모든 변경(INSERT, UPDATE, DELETE)을 디스크에 쓰기 전에 WAL 파일에 먼저 기록합니다. 이는 '쓰기 전 로그'라는 이름처럼, 트랜잭션의 완전한 히스토리를 보관해 충돌 시 데이터 무결성을 보장합니다. PITR에서 WAL은 '시간 여행'의 열쇠입니다 – 과거 트랜잭션을 재생해 특정 시점까지 복원할 수 있게 하죠.

연속 아카이빙 설정이 핵심입니다. WAL 파일이 자동으로 아카이브 디렉토리로 복사되도록 postgresql.conf를 수정하세요. 이렇게 하면 모든 변경이 영구 보관됩니다.

# postgresql.conf 편집 (pg_ctl reload 또는 서버 재시작 후 적용)
archive_mode = on
archive_command = 'test ! -f /path/to/archive/%f && cp %p /path/to/archive/%f'  # %p: WAL 경로, %f: 파일명
archive_timeout = 60  # 60초마다 WAL 아카이빙 (기본 0은 자동)

: 아카이브 디렉토리는 충분한 공간(하루 WAL 크기 x 7일 이상)을 확보하세요. 스토리지 비용을 절감하려면 S3 같은 클라우드 스토리지와 연동하는 archive_command를 사용하세요.

2. 기본 백업 (Base Backup)

WAL이 '변화의 기록'이라면, 기본 백업은 '시작점'입니다. 이는 데이터베이스의 전체 스냅샷으로, PITR 복원의 기반이 됩니다. pg_basebackup 도구로 쉽게 생성할 수 있으며, 압축 형식(TAR, PLAIN)으로 저장 가능합니다.

# 기본 백업 생성 (스트리밍 WAL 포함 추천)
pg_basebackup -h localhost -U postgres -D /path/to/backup/dir -F tar --wal-method=stream -P -v

# TAR 형식으로 압축 백업 (이동성 좋음)
pg_basebackup -h localhost -U postgres -D - -F tar --wal-method=stream | gzip > base_backup_$(date +%Y%m%d_%H%M%S).tar.gz

: 매일 자동화 스크립트로 백업하세요. cron job 예시:

0 2 * * * /usr/bin/pg_basebackup ... >> /var/log/backup.log 2>&1

백업 후 WAL 아카이빙이 제대로 작동하는지 pg_stat_archiver 뷰로 확인하세요.

3. 복구 대상 시간 (Recovery Target Time)

PITR의 '마법'은 여기 있습니다. recovery_target_time으로 정확한 타임스탬프를 지정하면, 기본 백업부터 그 시점까지 WAL을 재생합니다. 타겟을 초과하는 트랜잭션은 무시되므로, 손상된 부분만 롤백할 수 있습니다.

추가 옵션:

  • recovery_target_xid: 트랜잭션 ID로 복원 (성능 우수).
  • recovery_target_name: 사용자 정의 이름으로 복원 지점 지정.

PITR 구현 단계: 실제 복구 과정

이론은 끝! 이제 실전으로 들어가보죠. PITR 복원은 체계적입니다. 테스트 환경에서 먼저 연습하세요.

1. PostgreSQL 서버 중지

데이터 일관성을 위해 서버를 완전히 멈추세요.

sudo systemctl stop postgresql  # systemd 사용 시
# 또는
pg_ctl -D /var/lib/postgresql/data stop

2. 기본 백업 복원

백업을 데이터 디렉토리로 복사/압축 해제합니다.

# TAR 형식 백업 복원
tar -xzf base_backup.tar.gz -C /var/lib/postgresql/data

# 또는 디렉토리 복사
rsync -av /path/to/backup/dir/ /var/lib/postgresql/data/

주의: 기존 데이터 디렉토리를 백업해두세요!

3. 복구 설정 파일 생성

PostgreSQL 12 이전: recovery.conf 파일 생성.

# /var/lib/postgresql/data/recovery.conf
standby_mode = 'off'  # 스탠바이 모드 off
primary_conninfo = ''  # 복제 필요 시 설정
restore_command = 'cp /path/to/archive/%f %p'  # WAL 복원 명령
recovery_target_action = 'promote'  # 타겟 도달 시 자동 프로모션
recovery_target_time = '2025-10-30 14:59:59'  # 목표 시점 (UTC)

PostgreSQL 12 이후: recovery.signal 파일(빈 파일) 생성 + postgresql.auto.conf 편집.

touch /var/lib/postgresql/data/recovery.signal
# postgresql.auto.conf
restore_command = 'cp /path/to/archive/%f %p'
recovery_target_time = '2025-10-30 14:59:59'

: 타겟 시간은 pg_current_logfile()이나 EXTRACT(EPOCH FROM now())로 확인하세요.

4. PostgreSQL 재시작 및 복구 모드 진입

sudo systemctl start postgresql
# 로그 확인: tail -f /var/log/postgresql/postgresql-*.log

서버가 복구 모드로 들어가 WAL을 재생합니다. 완료 시 "database system is ready to accept connections" 메시지가 나옵니다.

5. 복구 진행 상황 모니터링

로그를 실시간으로 감시하세요. 유용한 쿼리:

-- 복구 중 WAL 적용 확인 (복구 후 실행)
SELECT * FROM pg_stat_recovery_prefetch;  -- WAL 프리페치 상태

도구 추천: pgBadger로 로그 분석하거나, Prometheus + Grafana로 모니터링 대시보드 구축.

6. 복구 후 정리

  • recovery.conf 또는 recovery.signal 삭제.
  • 데이터 무결성 검사: pg_dump로 백업 후 비교, 또는 CHECKPOINT;pg_stat_user_tables로 테이블 상태 확인.
  • 애플리케이션 연결 테스트.

베스트 프랙티스: 복구 후 1시간 내에 풀 백업 생성. 정기 드릴로 연습하세요.

실제 시나리오: 전자상거래 애플리케이션의 위기 대응

전자상거래 사이트에서 고객 주문이 PostgreSQL에 저장된다고 가정해 보죠. 2025년 3월 15일 오전 12시에 안정적인 기본 백업을 했습니다. 오후 3시에 코드 배포 버그로 1,000건의 주문 데이터가 손상됐어요. 다운타임은 1시간 이내로 제한해야 합니다.

PITR 적용 과정:

  1. 즉시 중단: 모든 트랜잭션 중지 (pg_terminate_backend(pid)).
  2. 백업 복원: 오전 12시 백업을 데이터 디렉토리에 로드 (5분 소요).
  3. WAL 재생: recovery_target_time = '2025-03-15 14:59:59'로 설정. 오후 3시 버그 직전까지 유효 트랜잭션만 적용 (10분 소요).
  4. 검증: 주문 테이블 쿼리 실행 – 손상 데이터 롤백 확인.

결과? 손실된 주문은 0건, 다운타임 20분. 고객에게 "시스템 업그레이드"로 알리며 신뢰 유지. 만약 PITR이 없었다면? 수일 복구와 매출 손실 1억 원...

결론: PITR로 데이터 미래를 지켜라

PostgreSQL PITR은 백업의 '다음 단계'입니다. WAL 아카이빙과 기본 백업을 결합하면, 예측 불가능한 위기에서도 데이터를 안전하게 복원할 수 있습니다. DBA로서 PITR을 무시하면 안 됩니다 – 오늘 설정하고, 내일 후회하지 마세요!

728x90