数据库备份
本页给出可直接运行的备份脚本:pg_dump/pg_basebackup 完整命令、cron 自动备份 + S3 上传脚本、备份验证与恢复演练脚本,以及 RPO/RTO 具体计算示例(RPO=1h 意味着什么配置);帮助 Agent 设计有完整监控告警的可验证备份策略。
SKILL 须明确备份介质(对象存储、异地机房)、加密与密钥托管、访问审计,以及谁有权发起恢复与在生产外做还原测试。
对关系型与 NoSQL 分别说明一致性语义:逻辑备份与物理备份的窗口、复制延迟对 RPO 的影响,以及大表分片备份的注意点。
强调「备份不等于可恢复」:定期抽样恢复到隔离环境,校验校验和、行数与关键业务查询,并记录失败时的告警与工单流程。
- 备份任务失败必须在 SLA 内有人处理,避免静默堆积。
- 合规数据需符合驻留地与脱敏导出规则。
- 与灾难恢复演练技能衔接:同一套联系人、Runbook 与决策树。
RPO 与备份粒度
RPO(Recovery Point Objective)
灾难或误操作后可接受的最大数据丢失时间窗口。仅全量定期快照时,最坏情况常接近「两次全量之间」;有连续 WAL/日志归档且恢复流程验证通过时,可把声明 RPO 收紧到「日志应用滞后 + 批处理延迟」量级。
RTO 与备份的关系
RTO 关注恢复要多快;备份形态影响恢复路径(全量还原、增量链接、PITR 重放)。大库冷备 + 长重放会拉长 RTO,需在 SKILL 里同时写清 RPO/RTO 假设与验证方式。
- 异步副本、跨区域复制与备份窗口不要混为一谈:各自贡献不同的保护面,RPO 取链路短板。
- 逻辑导出与物理快照的一致性语义不同,Agent 输出策略时要写清「崩溃一致 / 应用一致」前提。
# PostgreSQL 备份命令
# 1. pg_dump — 逻辑备份(应用一致,适合单库导出与跨版本迁移)
pg_dump \
--host=db.acme.internal \
--port=5432 \
--username=backup_user \
--dbname=payments \
--format=custom \ # custom 格式支持并行恢复
--compress=6 \ # 压缩级别 0-9
--jobs=4 \ # 并行 dump 表(format=directory 时)
--file=/backup/payments-$(date +%Y%m%d-%H%M%S).dump \
--verbose 2>>/var/log/pg_dump.log
# 恢复:
# pg_restore --dbname=payments_restore --jobs=4 /backup/payments-20240315.dump
# 2. pg_basebackup — 物理备份(崩溃一致,作为 PITR 基准)
pg_basebackup \
--host=db.acme.internal \
--port=5432 \
--username=replication_user \
--pgdata=/backup/base/$(date +%Y%m%d) \
--format=tar \ # tar 格式便于压缩传输
--gzip \
--compress=6 \
--wal-method=stream \ # 同时流式接收 WAL,确保备份完整性
--checkpoint=fast \ # 快速创建检查点
--progress \
--verbose 2>>/var/log/pg_basebackup.log
echo "Backup size: $(du -sh /backup/base/$(date +%Y%m%d))"
PITR(时间点恢复)
PITR 需要:基线(全量或等价一致点)+ 连续日志链(WAL、binlog、oplog 等)在保留期内可获取,且恢复工具与权限在演练环境验证过。
- 日志保留须覆盖「法务/运维可能提出的最远回溯点」,并与全量保留策略一起算存储成本与合规驻留。
- 恢复到「任意时刻」前确认:时区、时钟跳变、DDL 与逻辑复制冲突对重放的影响。
- 云托管实例:弄清托管方提供的 PITR 窗口、是否额外导出到自有桶,以及跨区域副本是否参与 PITR。
# PostgreSQL WAL 归档配置(postgresql.conf)
# RPO=1h 意味着:WAL 归档延迟 < 1h + 全量备份间隔每日一次
# 具体配置:
# 开启 WAL 归档
wal_level = replica # 或 logical(如需逻辑复制)
archive_mode = on
archive_command = 's3cmd put %p s3://acme-backups/wal/%f'
# %p = WAL 文件路径, %f = 文件名
# archive_command 必须在成功后返回 0,失败时 PG 会重试
# WAL 归档到 S3(pgBackRest 更完善,适合生产)
# archive_command = 'pgbackrest --stanza=payments archive-push %p'
# 连续归档验证(确保 WAL 归档无间断)
# SELECT pg_walfile_name(pg_current_wal_lsn()); -- 当前 WAL 位置
# 检查 archive_status 目录中是否有 .ready 文件堆积(归档落后信号)
# PITR 恢复配置(recovery.conf / postgresql.conf PG12+)
# 恢复到特定时间点(UTC):
# restore_command = 's3cmd get s3://acme-backups/wal/%f %p'
# recovery_target_time = '2024-03-15 10:30:00 UTC'
# recovery_target_action = 'promote' # 恢复完成后自动升主
介质、加密与权限
- 对象存储与跨地域:版本控制、生命周期、非法删除防护(MFA delete、WORM 或组织策略)。
- 密钥:CMK/KMS、轮换、恢复时解密路径与 break-glass;备份文件与元数据同样加密。
- 谁可发起 restore、是否在独立 VPC/账号演练,与审计日志保留周期。
#!/usr/bin/env bash
# backup-and-upload.sh — 自动备份 + S3 上传 + 失败告警
set -euo pipefail
DB_HOST="${DB_HOST:-db.acme.internal}"
DB_NAME="${DB_NAME:-payments}"
S3_BUCKET="${S3_BUCKET:-s3://acme-backups}"
BACKUP_DIR="/tmp/backups"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}-${TIMESTAMP}.dump"
ALERT_WEBHOOK="${SLACK_WEBHOOK_URL:-}"
mkdir -p "$BACKUP_DIR"
cleanup() {
rm -f "$BACKUP_FILE" "$BACKUP_FILE.gpg"
}
trap cleanup EXIT
# 1. 备份
echo "[$(date)] Starting backup: $DB_NAME"
pg_dump \
--host="$DB_HOST" --port=5432 \
--username=backup_user \
--dbname="$DB_NAME" \
--format=custom --compress=6 \
--file="$BACKUP_FILE"
# 2. 加密(GPG 对称加密,密钥由 KMS 管理)
gpg --batch --yes --symmetric \
--passphrase-file /run/secrets/backup_passphrase \
--output "${BACKUP_FILE}.gpg" \
"$BACKUP_FILE"
rm -f "$BACKUP_FILE"
# 3. 上传到 S3(服务端加密 + 版本控制)
aws s3 cp "${BACKUP_FILE}.gpg" \
"${S3_BUCKET}/daily/${DB_NAME}/${TIMESTAMP}.dump.gpg" \
--sse aws:kms \
--storage-class STANDARD_IA \
--metadata "db=${DB_NAME},timestamp=${TIMESTAMP}"
# 4. 记录备份元数据(用于监控告警)
echo "${TIMESTAMP} SUCCESS ${DB_NAME}" >> /var/log/backup_history.log
echo "[$(date)] Backup completed: ${TIMESTAMP}.dump.gpg"
# crontab -e 配置(每日凌晨 2 点执行):
# 0 2 * * * /opt/scripts/backup-and-upload.sh >> /var/log/backup-cron.log 2>&1
#!/usr/bin/env bash
# backup-verify.sh — 备份验证恢复演练(隔离环境)
# 建议每月运行一次(或 CI 中按计划触发)
set -euo pipefail
S3_BUCKET="s3://acme-backups"
RESTORE_HOST="${RESTORE_HOST:-restore-test.internal}"
RESTORE_DB="payments_restore_$(date +%Y%m%d)"
BACKUP_FILE="/tmp/verify-restore.dump.gpg"
echo "=== Step 1: Download latest backup ==="
LATEST=$(aws s3 ls "${S3_BUCKET}/daily/payments/" \
| sort | tail -1 | awk '{print $4}')
aws s3 cp "${S3_BUCKET}/daily/payments/${LATEST}" "$BACKUP_FILE"
echo "=== Step 2: Decrypt ==="
gpg --batch --yes --decrypt \
--passphrase-file /run/secrets/backup_passphrase \
--output "${BACKUP_FILE%.gpg}" \
"$BACKUP_FILE"
echo "=== Step 3: Restore to isolated DB ==="
createdb --host="$RESTORE_HOST" "$RESTORE_DB"
pg_restore --host="$RESTORE_HOST" \
--dbname="$RESTORE_DB" \
--jobs=4 \
"${BACKUP_FILE%.gpg}"
echo "=== Step 4: Verify row counts ==="
ROW_COUNT=$(psql --host="$RESTORE_HOST" --dbname="$RESTORE_DB" \
-tAc "SELECT COUNT(*) FROM orders")
EXPECTED=100 # 最少应有的行数(从监控基线取)
[ "$ROW_COUNT" -ge "$EXPECTED" ] \
&& echo "✅ Verify passed: orders=$ROW_COUNT" \
|| { echo "❌ Verify FAILED: orders=$ROW_COUNT < expected=$EXPECTED"; exit 1; }
echo "=== Step 5: Smoke query ==="
psql --host="$RESTORE_HOST" --dbname="$RESTORE_DB" \
-c "SELECT status, COUNT(*) FROM orders GROUP BY status LIMIT 5;"
# Cleanup
dropdb --host="$RESTORE_HOST" "$RESTORE_DB" || true
echo "=== Restore drill completed at $(date) ==="
备份监控告警与 RPO/RTO 计算
# 备份失败告警(Prometheus AlertManager 规则)
# prometheus/alerts/backup.yml
groups:
- name: database_backup
rules:
# 超过 26 小时无成功备份(全量备份每 24h,容忍 2h 延迟)
- alert: BackupMissing
expr: |
time() - max(backup_last_success_timestamp_seconds{job="pg-backup"}) > 93600
for: 5m
labels: { severity: critical }
annotations:
summary: "数据库备份超时未完成"
description: "payments 库超过 26h 无成功备份,当前 RPO 风险"
# 备份文件大小异常(突然变小可能是空备份)
- alert: BackupSizeAnomaly
expr: |
backup_size_bytes{job="pg-backup"} < 1e8 # 小于 100MB 告警
for: 1m
labels: { severity: warning }
# RPO/RTO 计算示例(RPO=1h 意味着什么配置)
# ──────────────────────────────────────────────────
# 目标: RPO = 1h(最多丢失 1 小时数据)
# 方案: 全量备份每日 + WAL 连续归档
#
# 配置要求:
# archive_command 每 60s 内触发一次 WAL 切换(或 WAL 填满 16MB 自动切换)
# archive_status: 无 .ready 文件堆积(归档滞后 = 实际 RPO)
# 监控: max(WAL 归档时间戳) - now() < 60min
#
# RTO 计算示例(百 GB 库):
# pg_basebackup 还原: ~20min(100GB / 100MB/s 网络)
# WAL 重放(最多 1h 的 WAL): ~5min
# 总 RTO ≈ 25min
#
# 提高 RTO:使用流式副本 + 快速 failover(<30s)
# → RTO = failover 切换时间,不需还原整个备份
# ──────────────────────────────────────────────────
# 备份监控指标推送(bash + curl)
push_backup_metric() {
local status=$1 # 0=success, 1=fail
curl -s --data-binary @- \
"http://pushgateway:9091/metrics/job/pg-backup/instance/payments" <<EOF
backup_last_success_timestamp_seconds $([ "$status" -eq 0 ] && date +%s || echo 0)
backup_size_bytes $(stat -f%z "$BACKUP_FILE" 2>/dev/null || echo 0)
EOF
}
[ 业务 RPO/RTO 与合规约束 ]
│
▼
┌─────────────┐ 全量 / 增量 / 日志链 / 副本 的组合
│ 选型与保留 │──── 保留:全量、增量、日志、跨区域副本对齐
└─────────────┘
│
▼
┌─────────────┐ 调度、并发、对线上负载影响、失败告警
│ 执行备份 │──── 校验和、清单、元数据(库名、位点、时间)
└─────────────┘
│
▼
┌─────────────┐ 加密、最小权限、审计;定期恢复演练抽样
│ 存储与治理 │──── 与密钥轮换、成本与生命周期策略一致
└─────────────┘
│
▼
┌─────────────┐ 隔离环境还原 + PITR 试跑(若承诺)
│ 恢复验证 │──── 行数/抽样查询/应用冒烟;记录差距与工单
└─────────────┘
│
▼
┌─────────────┐ 与灾备 Runbook、RTO 时间盒、联系人一致
│ 衔接演练 │
└─────────────┘
粗算器仅帮助对齐「口头 RPO」与备份设计的数量级;正式承诺需以监控、演练与合同条款为准。
RPO 粗算小工具
用简化模型估算「设计意图下的分钟级 RPO 下限」:无连续日志时取全量周期间最坏丢失(按间隔整段计);有连续日志并可成功 PITR时取下限为日志应用最大滞后;再与异步副本最大滞后取较大值。结果供评审草稿使用。
模型:无日志时 RPO基线 = 全量间隔(小时)× 60;有日志时 RPO基线 = 日志最大滞后;再与副本滞后取 max。未计入人为误删备份、密钥不可用、重放失败等风险,这些须在 Runbook 与演练中单独列出。
---
name: database-backup
description: 备份命令、自动化脚本、恢复演练与监控告警
---
# 备份命令
pg_dump --format=custom --compress=6 --jobs=4(逻辑备份)
pg_basebackup --wal-method=stream --gzip(物理备份,PITR 基准)
# 自动备份脚本
cron: 0 2 * * *(每日凌晨 2 点)
步骤: pg_dump → gpg 加密 → aws s3 cp --sse aws:kms
元数据: 备份时间戳 + 大小写入监控 → Prometheus pushgateway
# WAL 归档(RPO=1h 的配置)
archive_mode=on; archive_command 每段 WAL 上传 S3
监控: max(归档时间戳) - now() < 60min(否则触发 BackupMissing 告警)
RTO 估算: 还原 100GB ≈ 20min + WAL 重放 1h ≈ 5min → RTO≈25min
# 恢复演练脚本
每月: 下载最新备份 → 解密 → pg_restore → 行数验证 → smoke query
隔离环境: 独立 VPC/账号,不影响生产
演练记录: 记录实际 RTO + 差距 + 工单号
# 告警规则
BackupMissing: time()-last_success > 93600s(26h)→ critical
BackupSizeAnomaly: size < 100MB → warning
复制延迟: pg_last_xact_replay_timestamp() lag > RPO/2 → warning