Contents
see List백업 파일보다 중요한 것은 복구 가능한 백업입니다
데이터베이스 백업은 파일을 만들어 두는 작업으로 끝나지 않습니다. 실제 장애가 발생했을 때 서비스가 받아들일 수 있는 시간 안에 복원되고, 복원된 데이터가 업무 기준과 맞는지 확인되어야 백업이라고 부를 수 있습니다. PostgreSQL을 운영하다 보면 pg_dump 파일은 매일 쌓이지만, 정작 새 서버에 복구해 본 기록은 없는 경우가 많습니다. 이 상태에서는 백업 파일이 깨졌는지, 확장 기능이 누락되었는지, 권한이나 시퀀스 값이 빠졌는지 장애 순간까지 알기 어렵습니다.
이 문서는 소규모 서비스나 사내 업무 시스템에서 바로 적용할 수 있는 논리 백업과 복구 검증 절차를 기준으로 설명합니다. 물리 복제나 PITR이 필요한 대규모 운영 환경도 많지만, 관리자가 먼저 갖춰야 할 기본은 정기적인 덤프, 별도 위치 보관, 독립 환경 복구, 핵심 쿼리 검증입니다. 특히 고객 주문, 재고, 정산, 회원 데이터처럼 업무 중단 비용이 큰 테이블은 백업 성공 로그만 믿지 말고 복원 후 검증 쿼리를 함께 남겨야 합니다.
백업 정책을 먼저 숫자로 정합니다
백업 스크립트를 만들기 전에 RPO와 RTO를 정해야 합니다. RPO는 장애가 났을 때 최대 몇 시간의 데이터 손실까지 허용할지, RTO는 서비스를 몇 시간 안에 복구해야 하는지를 뜻합니다. 예를 들어 하루 한 번 새벽에 pg_dump를 실행한다면 최악의 경우 하루치 변경분을 잃을 수 있습니다. 주문이나 결제가 있는 시스템이라면 이것만으로 부족할 수 있으므로 주기적인 스냅샷, WAL 아카이빙, 외부 보관을 함께 검토해야 합니다.
- 백업 주기: 업무 데이터 변경량이 많은 시간대를 피하고, 백업 파일 생성 시간을 측정합니다.
- 보관 기간: 최근 7일, 최근 4주, 월말 6개월처럼 복구 목적별 계층을 둡니다.
- 보관 위치: 운영 서버 한 곳에만 두지 말고 다른 디스크, 다른 서버, 오브젝트 스토리지 중 하나 이상을 사용합니다.
- 검증 주기: 최소 주 1회는 별도 데이터베이스에 복원하고 검증 쿼리를 실행합니다.
pg_dump 백업 스크립트 예시
아래 예시는 custom format으로 백업을 만들고, 파일 크기와 종료 코드를 확인한 뒤 오래된 파일을 정리하는 기본 형태입니다. custom format은 pg_restore로 테이블 단위 복구나 병렬 복원에 활용하기 좋습니다. 단순 SQL 파일이 필요한 경우 plain format도 가능하지만, 운영 백업에서는 복구 유연성이 높은 custom format을 기본값으로 두는 편이 실용적입니다.
#!/usr/bin/env bash
set -euo pipefail
APP_NAME="erp"
DB_HOST="127.0.0.1"
DB_PORT="5432"
DB_NAME="erp_prod"
DB_USER="backup_user"
BACKUP_DIR="/var/backups/postgresql/$APP_NAME"
TODAY="$(date +%Y%m%d-%H%M%S)"
OUT="$BACKUP_DIR/$DB_NAME-$TODAY.dump"
mkdir -p "$BACKUP_DIR"
chmod 700 "$BACKUP_DIR"
pg_dump \
--host="$DB_HOST" \
--port="$DB_PORT" \
--username="$DB_USER" \
--format=custom \
--compress=9 \
--no-owner \
--no-privileges \
--file="$OUT" \
"$DB_NAME"
test -s "$OUT"
sha256sum "$OUT" > "$OUT.sha256"
find "$BACKUP_DIR" -type f -name "*.dump" -mtime +30 -delete
find "$BACKUP_DIR" -type f -name "*.sha256" -mtime +30 -delete
echo "backup_ok path=$OUT"
실제 운영에서는 비밀번호를 스크립트에 직접 쓰지 말고 postgres 전용 사용자 홈의 .pgpass, 시스템 비밀 관리 도구, 배포 환경의 secret 기능을 사용합니다. 백업 전용 계정에는 필요한 읽기 권한만 부여하고, 운영 애플리케이션 계정과 분리합니다. 또한 백업 디렉터리 권한은 최소화해야 합니다. 덤프 파일에는 개인정보, 주문 내역, 내부 정산 데이터가 그대로 들어 있으므로 로그나 알림에 파일 내용을 출력하지 않는 것도 중요합니다.
복원 검증은 별도 데이터베이스에서 실행합니다
백업 검증은 운영 데이터베이스에 다시 넣는 방식으로 하면 안 됩니다. 같은 서버 안이라도 별도 인스턴스나 별도 데이터베이스를 만들고, 가능하면 운영 권한과 분리된 검증 계정으로 진행합니다. 아래 예시는 최신 덤프를 검증용 데이터베이스에 복구한 뒤 핵심 테이블 개수와 시퀀스 상태를 확인하는 흐름입니다.
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/var/backups/postgresql/erp"
LATEST="$(ls -t $BACKUP_DIR/erp_prod-*.dump | head -n 1)"
VERIFY_DB="erp_restore_check"
sha256sum -c "$LATEST.sha256"
dropdb --if-exists "$VERIFY_DB"
createdb "$VERIFY_DB"
pg_restore \
--dbname="$VERIFY_DB" \
--clean \
--if-exists \
--no-owner \
--no-privileges \
--jobs=2 \
"$LATEST"
psql "$VERIFY_DB" -v ON_ERROR_STOP=1 <<'SQL'
select 'users' as table_name, count(*) from users
union all
select 'orders', count(*) from orders
union all
select 'products', count(*) from products;
select relname, n_live_tup
from pg_stat_user_tables
where relname in ('users', 'orders', 'products')
order by relname;
SQL
echo "restore_check_ok dump=$LATEST"
업무 기준 검증 쿼리를 따로 둡니다
테이블이 복원되었다고 해서 업무 데이터가 정상이라는 뜻은 아닙니다. 운영 시스템마다 반드시 지켜야 하는 데이터 규칙이 있습니다. 주문 금액은 음수가 아니어야 하고, 결제 완료 주문은 결제 시간이 있어야 하며, 재고 수량은 기준 테이블의 상품과 연결되어야 합니다. 이런 규칙을 검증 SQL로 만들어 두면 복구 연습 때마다 같은 기준으로 확인할 수 있습니다.
-- 복구 검증용 업무 규칙 예시
select count(*) as invalid_paid_orders
from orders
where status = 'PAID'
and paid_at is null;
select count(*) as negative_stock_rows
from inventory
where quantity < 0;
select count(*) as orphan_order_items
from order_items oi
left join orders o on o.id = oi.order_id
where o.id is null;
검증 결과는 성공 여부만 남기지 말고 실행 시간, 덤프 파일명, 파일 해시, 주요 테이블 row count를 함께 기록합니다. 그래야 나중에 데이터가 갑자기 줄어든 시점이나 특정 테이블 복원이 실패한 시점을 추적할 수 있습니다. 백업 로그는 운영 애플리케이션 로그와 다른 위치에 보관하고, 모니터링 시스템이 있다면 백업 실패와 복구 검증 실패를 별도 알림으로 분리하는 것이 좋습니다.
실패 시나리오를 미리 정해 둡니다
복구 절차는 평상시에 문서화되어 있어야 합니다. 장애가 난 뒤 담당자가 pg_restore 옵션을 검색하는 상황이면 복구 시간은 길어지고 실수 가능성도 커집니다. 복구 대상 서버 준비, PostgreSQL 버전 확인, 확장 기능 설치, 애플리케이션 점검 모드 전환, DNS 또는 연결 문자열 변경, 복구 후 읽기 전용 검증, 서비스 재개 순서를 체크리스트로 둡니다. 특히 운영 서버와 검증 서버의 PostgreSQL 메이저 버전이 다르면 복원 방식과 확장 호환성을 미리 확인해야 합니다.
- 백업 파일 생성 성공 여부와 파일 크기를 매일 확인합니다.
- 덤프 파일의 해시를 저장하고 복구 전 무결성을 검사합니다.
- 복원 테스트는 운영과 분리된 데이터베이스에서 반복 실행합니다.
- 핵심 테이블 row count와 업무 규칙 검증 SQL을 자동화합니다.
- 복구 절차, 담당자, 목표 복구 시간을 문서로 남깁니다.
정리하면 PostgreSQL 백업 운영의 핵심은 백업 생성, 외부 보관, 복원 검증, 업무 데이터 확인을 하나의 절차로 묶는 것입니다. 파일이 존재한다는 사실만으로는 장애 대응이 되지 않습니다. 정기적으로 실제 복원을 해 보고, 검증 SQL이 통과하며, 담당자가 같은 순서로 재현할 수 있을 때 백업은 운영 가능한 안전장치가 됩니다.