From fb0e9c8f9c99b42a746a69838f2613cba230acf1 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sun, 23 Aug 2026 15:24:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=87=E4=BB=BD=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/pgBackRest备份方案分析.md | 192 +++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 docs/pgBackRest备份方案分析.md diff --git a/docs/pgBackRest备份方案分析.md b/docs/pgBackRest备份方案分析.md new file mode 100644 index 00000000..16049f1c --- /dev/null +++ b/docs/pgBackRest备份方案分析.md @@ -0,0 +1,192 @@ +# pgBackRest 生产备份方案分析 + +> 状态:暂缓实施。当前继续使用 `pg_dump -Fc` + OSS manifest 备份方案,待安排维护窗口后再启用 WAL 归档。 +> +> 记录日期:2026-08-23 + +## 结论 + +PostgreSQL 没有 MySQL binlog 的同名机制,但有等价能力: + +```text +基础物理备份 + WAL 归档 = 按时间点恢复(PITR) +``` + +当前 Compose 是单节点 PostgreSQL。启用 `archive_mode` 和 `wal_level` 通常需要重启 PostgreSQL,因此不能承诺绝对零停机。 + +预计生产维护窗口: + +| 阶段 | 是否停机 | 预计耗时 | +| --- | --- | --- | +| 构建 pgBackRest 镜像 | 否 | 几分钟 | +| 创建 stanza、校验 OSS | 否 | 1~3 分钟 | +| 重启 PostgreSQL 启用 WAL 归档 | 是 | 5~30 秒 | +| backend/web 等待恢复 | 是 | 20~90 秒 | +| 首次全量备份 | 否 | 几分钟到几十分钟 | +| 建议预留维护窗口 | 是 | 2~5 分钟 | + +实际时间取决于数据库大小、磁盘恢复速度、容器启动时间和 OSS 网络质量。当前 `pg_dump` 文件约 161 MB,首次物理备份预计不会很大,但仍应按实际 PostgreSQL 数据目录大小估算。 + +## 当前方案 + +目前生产使用: + +- `pg_dump -Fc` 全库逻辑备份。 +- 备份文件上传 OSS。 +- manifest 保存大小、SHA-256、迁移记录和创建时间。 +- `apps/backend/data` 配置单独打包上传。 +- `restore-db.sh --verify` 在临时 PostgreSQL 容器中演练恢复。 + +该方案可以恢复到某个 dump 的时间点,但不能恢复最近一次 dump 之后的几分钟变更。 + +pgBackRest 不能替代当前逻辑备份,建议两套并存: + +```text +pgBackRest:生产灾难恢复、PITR、分钟级 RPO +pg_dump:逻辑迁移、单表恢复、跨版本恢复、第二套保险 +``` + +## 需要增加的组件 + +当前 PostgreSQL 镜像没有 pgBackRest,需要构建自定义镜像: + +```dockerfile +FROM docker.m.daocloud.io/library/postgres:16-bookworm + +RUN apt-get update \ + && apt-get install -y --no-install-recommends pgbackrest ca-certificates \ + && rm -rf /var/lib/apt/lists/* +``` + +需要增加或挂载: + +- `/etc/pgbackrest/pgbackrest.conf` +- `/var/spool/pgbackrest/` +- pgBackRest 日志目录 +- OSS 备份凭证 +- pgBackRest repository 配置 + +不能只在正在运行的容器里执行 `apt install pgbackrest`,因为容器重建后会丢失。 + +## OSS 规划 + +可以复用当前图片 OSS 桶,但必须使用独立前缀: + +```text +backups/postgres/ # 当前 pg_dump +backups/configs/ # 应用配置 +backups/pgbackrest/ # 基础备份和 WAL +``` + +生产更推荐新建独立备份桶,并创建独立 RAM 用户。原因:数据库备份包含订单、用户和后台数据,不能与图片读写权限混用。 + +建议 OSS 配置: + +- 使用 ECS 同地域内网端点,避免公网流量费用。 +- 开启版本控制。 +- 配置生命周期规则。 +- 备份桶保持私有。 +- 必要时启用 pgBackRest 仓库加密,并安全保存加密密码。 + +pgBackRest 使用 OSS S3 兼容接口,最终配置必须通过 `pgbackrest check` 和一次完整备份实测,不能只凭配置文件判断兼容性。 + +## PostgreSQL 配置 + +需要启用: + +```text +wal_level=replica +archive_mode=on +archive_command=pgbackrest --stanza=order-site archive-push %p +archive_timeout=60 +``` + +说明: + +- `wal_level=replica` 通常需要重启。 +- `archive_mode=on` 必须重启。 +- `archive_command` 可以 reload,但建议统一写入 Compose 配置。 +- `archive_timeout=60` 让低写入量时 WAL 最多约 60 秒切换归档一次。 +- OSS 不可用时 WAL 会在本地积压,不能手动删除 `pg_wal` 文件。 + +启用前先检查当前状态: + +```bash +docker compose exec postgres psql \ + -U postgres -d order_site \ + -c "SHOW wal_level; SHOW archive_mode; SHOW archive_command;" +``` + +如果 `archive_mode` 已经是 `on`,后续可能只需要配置 pgBackRest 和 reload;如果是 `off`,需要完整重启 PostgreSQL。 + +## 计划中的切换步骤 + +当前暂不执行。正式实施时按以下顺序: + +1. 继续保留并执行现有 `bash deploy/backup-db.sh`。 +2. 创建独立 OSS 备份桶或规划独立 `backups/pgbackrest/` 前缀。 +3. 创建只允许备份前缀的 RAM 用户。 +4. 构建包含 pgBackRest 的 PostgreSQL 镜像。 +5. 准备 `pgbackrest.conf`,不要把密钥提交到 Git。 +6. 在 PostgreSQL 仍在线时执行 `stanza-create`。 +7. 选择低峰期停止 backend/web。 +8. 重启 PostgreSQL,启用 `archive_mode` 和 `archive_command`。 +9. 等待 PostgreSQL 健康检查通过。 +10. 执行 `pgbackrest check`。 +11. 执行第一次 full backup。 +12. 检查 OSS 中是否出现基础备份和 WAL 文件。 +13. 在临时 PostgreSQL 或测试服务器执行一次 PITR 恢复。 +14. 恢复 backend/web,并抽查后台、订单和图片访问。 + +不要执行以下命令,避免误删当前数据库: + +```bash +docker compose down -v +docker volume rm order_site_postgres_data +``` + +增加 pgBackRest 只需要替换镜像、挂载配置并重启,不需要删除 `postgres_data` 数据卷。 + +## 备份策略建议 + +```text +每周:full 基础备份 +每天:diff 差异备份 +持续:WAL 归档到 OSS +每天:保留当前 pg_dump 逻辑备份 +``` + +WAL 归档不依赖 cron,由 PostgreSQL 的 `archive_command` 持续触发。需要监控: + +- WAL 归档失败次数。 +- `/var/lib/postgresql/data/pg_wal` 占用空间。 +- OSS 上传延迟和失败率。 +- 最近一次 full/diff 备份时间。 +- 最近一段 WAL 是否已经出现在 OSS。 + +## 恢复时间预期 + +pgBackRest PITR 恢复也不是零停机操作。当前单节点架构下,恢复生产数据库需要停止 backend/web,并替换或恢复 PostgreSQL 数据目录。 + +恢复耗时主要取决于: + +- 基础备份大小。 +- WAL 数量。 +- 磁盘读写速度。 +- WAL 回放量。 +- PostgreSQL 启动和健康检查时间。 + +如果基础备份较小、目标时间接近当前时间,预计几分钟;数据库规模扩大后需要重新压测,不能按当前 161 MB dump 固定估计。 + +## 后续验收清单 + +- `pgbackrest stanza-create` 成功。 +- `pgbackrest check` 成功。 +- 第一次 full backup 成功。 +- OSS 中能看到基础备份和 WAL。 +- PostgreSQL 重启后 `archive_mode=on`。 +- `pg_stat_archiver` 中归档成功数持续增加。 +- OSS 暂时不可用时,WAL 会积压但不会静默丢失。 +- 临时环境 PITR 到指定时间成功。 +- 恢复后的订单、后台用户、迁移记录和图片引用可用。 +