当前位置: 首页 > news >正文

MongoDB PBM 备份恢复完整验证手册

MongoDB PBM 备份恢复完整验证手册

看那么多文章自己操作一遍比啥都熟悉的快这份文档使用的是podman,也可以使用docker不影响
验证目标:3 节点副本集 → 全量备份 + PITR 切片 → 无共享存储时恢复必然失败 → copy 备份到另一台机器 → 挂共享存储后异机 PITR 恢复成功
环境:Mac Podman,MongoDB 7 + PBM 2.15.0 ARM64,2026-07-29 实测


变量区

下面所有步骤的命令都基于这些变量。改 IP、改路径、改镜像版本只需改这里,全文生效。

# ===== 集群网络 =====NETWORK="mongo-net"SUBNET="10.89.1.0/24"# ===== 3 个 MongoDB 节点(固定 IP)=====NODE1_IP="10.89.1.11"NODE2_IP="10.89.1.12"NODE3_IP="10.89.1.13"MONGO_IMAGE="mongo:7"REPLSET="rs0"# ===== PBM 二进制存放目录(从 Docker 镜像提取)=====PBM_BIN_DIR="$HOME/pbm-bin"# ===== PBM Docker 镜像(ARM64,Mac 兼容)=====PBM_IMAGE="percona/percona-backup-mongodb:2.15.0-arm64"# ===== 备份目录 =====RESTORE_DIR="$HOME/mongo-restore-test"# 从容器 copy 出来的备份SHARED_DIR="$HOME/mongo-shared-backup"# 模拟生产 NFS 的共享目录

第 1 阶段:搭建 3 节点副本集

1.1 创建网络

podmannetwork create--subnet${SUBNET}${NETWORK}2>/dev/null

1.2 启动 3 个 MongoDB 实例

podmanrun-d--namemongo1--network${NETWORK}--ip${NODE1_IP}\${MONGO_IMAGE}mongod--replSet${REPLSET}--bind_ip_allpodmanrun-d--namemongo2--network${NETWORK}--ip${NODE2_IP}\${MONGO_IMAGE}mongod--replSet${REPLSET}--bind_ip_allpodmanrun-d--namemongo3--network${NETWORK}--ip${NODE3_IP}\${MONGO_IMAGE}mongod--replSet${REPLSET}--bind_ip_all

1.3 初始化副本集

sleep5podmanexecmongo1 mongosh--eval' rs.initiate({ _id: "rs0", members: [ {_id:0, host:"10.89.1.11:27017"}, {_id:1, host:"10.89.1.12:27017"}, {_id:2, host:"10.89.1.13:27017"} ] })'sleep10podmanexecmongo1 mongosh--eval'rs.status().members.forEach(m => print(m.name + " → " + m.stateStr))'# 预期: 1 个 PRIMARY + 2 个 SECONDARY

第 2 阶段:安装 PBM(3 个节点)

2.1 从 Docker 镜像提取 ARM64 二进制

mkdir-p${PBM_BIN_DIR}podmanrun-d--namepbm-temp${PBM_IMAGE}podmancppbm-temp:/usr/bin/pbm${PBM_BIN_DIR}/pbmpodmancppbm-temp:/usr/bin/pbm-agent${PBM_BIN_DIR}/pbm-agentpodmanrm-fpbm-templs-lh${PBM_BIN_DIR}/# 预期: pbm + pbm-agent 两个二进制(各 ~60MB)

Mac 是 ARM 芯片,不能用 x86_64 RPM/tarball——之前踩过坑,rpm -ivh/lib64/ld-linux-x86-64.so.2不存在。

2.2 拷到 3 个节点 + 配 storage + 启 Agent

foriin123;dopodmancp${PBM_BIN_DIR}/pbm mongo${i}:/usr/bin/podmancp${PBM_BIN_DIR}/pbm-agent mongo${i}:/usr/bin/podmanexecmongo${i}chmod+x /usr/bin/pbm /usr/bin/pbm-agentpodmanexecmongo${i}bash-c"cat > /etc/pbm-storage.conf << EOF storage: type: filesystem filesystem: path: /tmp/backup EOF"podmanexec-dmongo${i}pbm-agent --mongodb-uri="mongodb://10.89.1.1${i}:27017/?replSetName=${REPLSET}"done

2.3 初始化 PBM 配置(只在一台跑)

podmanexecmongo1 pbm config--file/etc/pbm-storage.conf\--mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"

2.4 确认三节点就绪

podmanexecmongo1 pbm status --mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"# 预期: 三行 pbm-agent OK

第 3 阶段:全量备份

podmanexecmongo1 pbm backup --mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"# 记下备份名(后面恢复用)podmanexecmongo1 pbm list --mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"# 例如: 2026-07-29T03:03:36Z

此时全量备份里只有 MongoDB 系统库,没有 test 业务数据。后面 PITR 恢复时,全量恢复完 test 库是空的,要靠 PITR 切片追回增量数据——这样才能真正验证 PITR 是否有效。


第 4 阶段:开启 PITR + 插入测试数据

4.1 开启 PITR(切片间隔 1 分钟)

podmanexecmongo1 pbm config--setpitr.enabled=true\--mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"podmanexecmongo1 pbm config--setpitr.oplogSpanMin=1\--mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"# 确认 PITR 已开启podmanexecmongo1 pbm status --mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"# 预期: PITR Status [ON]

4.2 等切片开始生成后插入数据

# 等 PITR 切片开始生成sleep120podmanexecmongo1 pbm status --mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"# 确认 PITR chunks 行已经出现了切片# 在主库上插数据——这些数据全量备份里没有,只存在 PITR 切片里podmanexecmongo2 mongosh--eval' use test; for (let i=0; i<10000; i++) { db.pitrTest.insertOne({name:"user"+i, ts:new Date()}) }; db.users.insertMany([{name:"张三",age:30},{name:"李四",age:25},{name:"王五",age:28}]); print("pitrTest: " + db.pitrTest.countDocuments() + " 条"); print("users: " + db.users.countDocuments() + " 条"); '

4.3 获取恢复时间点

# 等 PITR 切片覆盖刚才的插入操作(约 3-5 分钟)sleep240podmanexecmongo1 pbm status --mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"

PITR chunks那行示例:

2026-07-29T03:03:41 - 2026-07-29T03:21:06

记下 2026-07-29T03:21:06 这个结束时间,后面 PITR 恢复就用它。不需要手动 date。


第 5 阶段:第一次恢复(PITR 会失败——这是关键教训)

5.1 执行 PITR 恢复

podmanexecmongo1 pbm restore--time="2026-07-29T03:21:06"-w\--mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"

5.2 实际输出——恢复失败

Starting restore ... to point-in-time 2026-07-29T03:21:06 ... Error: failed to ensure chunk {1785294220 2}.{1785294545 1} on the storage, file: pbmPitr/rs0/20260729/20260729030340-2.20260729030905-1.oplog.s2, error: no such file - Restore on replicaset "rs0" in state: error

5.3 失败原因

三个容器各自独立的/tmp/backup,PBM 不会跨节点传输切片文件。

PITR 切片是 mongo3(负责 PITR 的节点)写到它自己的 /tmp/backup 里的。 恢复时 PBM 在 mongo1 上执行,mongo1 去读自己本地的 /tmp/backup—— 根本找不到 mongo3 写的切片 → 报 no such file 🔴 PBM 的设计假设是所有节点挂同一个共享存储(生产 NFS)。 没有共享存储就没有 PITR 恢复。

这就是为什么后面需要重新搭建带共享目录的集群来验证异机恢复。


第 6 阶段:copy 备份到 Mac 本地

# 确认备份文件在 mongo3 上(PITR 切片那台)podmanexecmongo3ls-lh/tmp/backup/# 预期: 全量备份目录 + .pbm.json + pbmPitr/# copy 出来mkdir-p${RESTORE_DIR}podmancpmongo3:/tmp/backup/.${RESTORE_DIR}/# 确认ls-lh${RESTORE_DIR}/ls-lh${RESTORE_DIR}/pbmPitr/rs0/20260729/2>/dev/null# 预期: 全量备份 + PITR 切片文件

第 7 阶段:异机恢复(挂共享存储,问题解决)

7.1 清理旧集群

podmanstop mongo1 mongo2 mongo3podmanrmmongo1 mongo2 mongo3

7.2 创建共享备份目录并 copy 备份进去(模拟生产 NFS)

mkdir-p${SHARED_DIR}cp-r${RESTORE_DIR}/*${SHARED_DIR}/ls-lh${SHARED_DIR}/

这就是生产环境的等价操作——备份放在所有节点都能访问的 NFS 目录上,恢复时任意节点都能读到同一个文件。

7.3 启动新集群(共享目录挂载到每个容器)

podmanrun-d--namemongo1--network${NETWORK}--ip${NODE1_IP}\-v${SHARED_DIR}:/tmp/backup${MONGO_IMAGE}mongod--replSet${REPLSET}--bind_ip_allpodmanrun-d--namemongo2--network${NETWORK}--ip${NODE2_IP}\-v${SHARED_DIR}:/tmp/backup${MONGO_IMAGE}mongod--replSet${REPLSET}--bind_ip_allpodmanrun-d--namemongo3--network${NETWORK}--ip${NODE3_IP}\-v${SHARED_DIR}:/tmp/backup${MONGO_IMAGE}mongod--replSet${REPLSET}--bind_ip_all

7.4 初始化副本集

sleep5podmanexecmongo1 mongosh--eval' rs.initiate({ _id: "rs0", members: [ {_id:0, host:"10.89.1.11:27017"}, {_id:1, host:"10.89.1.12:27017"}, {_id:2, host:"10.89.1.13:27017"} ] })'sleep10podmanexecmongo1 mongosh--eval'rs.status().members.forEach(m => print(m.name + " → " + m.stateStr))'

7.5 安装 PBM(每个节点) + 识别备份 + 执行恢复

# 拷 PBM + 启 Agentforiin123;dopodmancp${PBM_BIN_DIR}/pbm mongo${i}:/usr/bin/podmancp${PBM_BIN_DIR}/pbm-agent mongo${i}:/usr/bin/podmanexecmongo${i}chmod+x /usr/bin/pbm /usr/bin/pbm-agentpodmanexecmongo${i}bash-c"cat > /etc/pbm-storage.conf << EOF storage: type: filesystem filesystem: path: /tmp/backup EOF"podmanexec-dmongo${i}pbm-agent --mongodb-uri="mongodb://10.89.1.1${i}:27017/?replSetName=${REPLSET}"done# 初始化 PBM 配置podmanexecmongo1 pbm config--file/etc/pbm-storage.conf\--mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"# 强制重扫描备份仓库(新集群必须做)podmanexecmongo1 pbm config --force-resync\--mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"# 确认能看到备份podmanexecmongo1 pbm list --mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"# PITR 恢复(y 确认)podmanexecmongo1 pbm restore--time="2026-07-29T03:21:06"-w\--mongodb-uri="mongodb://${NODE1_IP}:27017/?replSetName=${REPLSET}"

这次不报no such file——三个容器挂的都是同一个 Mac 目录${SHARED_DIR},mongo3 写的切片 mongo1 能读到 ✅


第 8 阶段:验证数据

podmanexecmongo3 mongosh--eval' use test; print("pitrTest 条数: " + db.pitrTest.countDocuments()); print("users 条数: " + db.users.countDocuments()); '# 预期: pitrTest=10000, users=3# 从库延迟归零podmanexecmongo3 mongosh--eval'rs.printSecondaryReplicationInfo()'# 预期: 0 secs behind the primary

全量备份里没有 test 库——恢复全量后 test 是空的。PITR 切片回放后 test 库和 1 万条数据全回来——PITR 增量恢复有效 ✅


踩坑记录

现象原因解决
🔴PITR 切片找不到(致命)restore 报no such file: pbmPitr/rs0/20260729/xxx.oplog.s2没有共享存储——三个容器各自独立的/tmp/backup。PBM 不会跨节点传输切片。所有节点挂同一共享目录:-v ~/mongo-shared-backup:/tmp/backup,生产用 NFS
架构不匹配rpm -ivh/lib64/ld-linux-x86-64.so.2不存在Mac ARM 芯片,不能用 x86_64 RPM/tarball用 Docker Hub 的 ARM64 镜像
新集群看不到备份pbm listno documents in result备份文件在共享目录里,但 PBM 元数据没同步到 MongoDB admin 库pbm config --file+pbm config --force-resync
PBM 2.15.0 不支持 MongoDB 4.2no such command: 'hello'MongoDB 4.2 用isMaster,5.0+ 用hello生产 4.2 降级到 PBM 2.0.5

练完清理

podmanstop mongo1 mongo2 mongo3 mongo4 pbm-temp2>/dev/nullpodmanrmmongo1 mongo2 mongo3 mongo4 pbm-temp2>/dev/nullpodmannetworkrm${NETWORK}2>/dev/nullrm-rf${RESTORE_DIR}${SHARED_DIR}${PBM_BIN_DIR}

验证日期:2026-07-29
环境:Mac Podman MongoDB 7 + PBM 2.15.0 ARM64

http://www.jsqmd.com/news/1292816/

相关文章:

  • 从机理到实践告别“黑箱”模拟:OpenGeoSys(OGS6)多物理场THMC 全耦合建模与Python自动化分析
  • 2026年7月耐用的避雷针型号齐全推荐,钢管塔避雷针/镀锌角钢铁塔/电力架构/杆塔避雷塔,避雷针零售厂家价格 - 品牌推荐师
  • 微信公众号注册全流程详解:从类型选择到认证避坑指南
  • AI审计手记 #07 从“真假”到“意图”:AI视频审计的下一个范式(一个猜想)
  • WebGIS开发入门到进阶 | 高德地图打卡功能实现教程
  • 2026年北京GEO服务推荐:泛海明心靠谱选择 - GrowthUME
  • 数据编码与徽章生成技术:从Base64到动态徽章系统实战
  • 2026年GEO优化实战:AI搜索获客避坑与效果提升指南 - GrowthUME
  • 2026年长春正规医美机构梳理 奥克拉医疗美容等机构特色汇总 - 浩了个浩
  • Harris角点检测算法原理详解与Matlab完整实现
  • 2026.7安徽金思捷亲测,金蝶云苍穹集团适配
  • 2026考研备考效率工具横评:5款主流AI语音转写工具实测(网课笔记/专业课复盘场景)
  • 2026年7月最新成都雷神笔记本售后网点完整指南(地址+客服电话+到店攻略) - 苹果手机电脑维修
  • 如何快速定位手机号码归属地:3分钟掌握精准位置查询技巧
  • 柏盛家具|全屋定制工厂怎么甄别,实操技巧,多工厂横向对比 - 国麟测评
  • 2026石家庄代理记账新趋势,财务公司如何助企业降本增效? - GrowthUME
  • vulnhub靶场实战-Basic Pentesting:2
  • 智能驾驶芯片选型指南:从英伟达、高通到地平线的技术路线与工程实践
  • 《城市天际线2》街区建造教程:从道路规划到细节装饰的完整指南
  • 十堰家装公司怎么选?2026主流装企特点解析与装修避坑指南 - 国麟测评
  • Visual Studio远程开发Linux C++项目:配置、调试与实战指南
  • 示波器开关机和接线
  • 2026龙泉驿家装服务商横向解读:迈尚装饰本地化综合优势分析 - 国麟测评
  • 2026焦作家装如何选择一站式整装,主流定制品牌客观对比与选购避坑指南 - 国麟测评
  • 2026年佛山桂城哪家美术机构对专注力最好:贝倍嘉美术 专业培养看得见 - GrowthUME
  • 2026年葡萄园必备:可靠的葡萄水肥一体机定做厂家联系方式优选指南 - geo交流
  • 【爱马仕】Hermes 本地智能应用安装详解,从资源获取到功能测试全过程(含安装包)
  • 决策树:原理、算法、优缺点与应用场景
  • 7月性能工具链路线图——从手动诊断到自动化感知演进路径
  • Java 集合--快速掌握涵盖三大场景实现的Set集合底层原理