节点卡在rollback状态必须人工干预恢复,因其曾短暂为主并执行未同步的写入,后因oplog不一致触发回滚;常见诱因包括网络分区、错误同步源配置等;此时完全不可用,唯一合法操作是清空dbpath后重启进行初始同步。

节点进入 ROLLBACK 状态时,不能读写、不能投票、不能参与选举,必须人工干预才能恢复 —— 不能等它自动“好起来”。
为什么节点会卡在 ROLLBACK 状态?
根本原因是:该节点曾短暂当过 PRIMARY,执行过写入,但这些写入没来得及同步给多数节点;之后它被降级为 SECONDARY,再尝试从新主同步时,发现自己的最新 oplog 和同步源不一致(optime 或 hash 对不上),触发回滚流程。
常见诱因包括:
- 网络分区期间旧主仍接受写入,恢复后无法与新主达成数据一致
-
chainingAllowed: false但配置了非最优同步源,导致同步延迟累积 - 人为调用
rs.syncFrom()指向了一个落后太多或已损坏的节点 -
maxSyncSourceLagSecs设置过大,让节点选到了一个实际已滞后的同步源
ROLLBACK 状态下能做什么?
什么也做不了 —— MongoDB 4.2+ 会直接终止所有用户连接和操作。你看到的 db.currentOp() 里基本是空的,db.adminCommand({ "replSetGetStatus": 1 }) 显示状态为 "stateStr" : "ROLLBACK",且 "health" : 0。
此时唯一合法动作是:
- 确认该节点是否还有未备份的写入(比如它当主期间插入的文档)—— 查看
db.getSiblingDB("local").oplog.rs.find().sort({$natural: -1}).limit(1)的ts和h字段,对比其他节点的最新oplog - 检查
local.rollback.*目录是否存在(默认在dbPath下),里面是待回滚的操作快照,但不是可直接导入的 BSON 文件 - 不要尝试
rs.reconfig()或rs.stepDown()—— 这些命令会被拒绝
如何退出 ROLLBACK 并恢复服务?
没有“跳过回滚”的安全方式。必须完成回滚,或彻底放弃该节点的数据一致性。
标准路径是:
- 停止该节点:
db.shutdownServer()或系统级kill -2 - 清空其
dbPath(保留mongod.lock可删可不删,新版会自动处理) - 重启
mongod,让它走完整初始同步(INITIALIZING → SECONDARY)
注意:
- 如果副本集只有 3 个节点,且这个节点是唯一能提供读扩展的
SECONDARY,清空dbPath后它要花数小时甚至更久才能追上 —— 别在业务高峰干这事 - 不要试图用另一个
SECONDARY的dbPath拷贝过来“加速”,除非你能确保那个节点的oplog覆盖范围 ≥ 本节点缺失的部分,否则可能触发二次ROLLBACK -
rollback目录里的文件是 BSON 格式但带特殊 header,不能用mongorestore直接导入;真要抢救数据,得用mongodump --db local --collection rollback.*提取,再手动解析
回滚后怎么验证没丢数据?
回滚本身不报错不代表数据一致。最容易被忽略的是:
- 检查应用层是否依赖了被回滚掉的那几条写入(比如订单号、幂等 key)—— 这些不会自动重放
- 比对
local.oplog.rs最新ts在所有节点是否单调递增,且无跳跃 - 运行
db.runCommand({ "validate": "your_collection", "full": true }),尤其对索引字段和唯一约束做校验 - 如果启用了
readConcern: "majority",确认回滚后writeConcern: { w: "majority" }的写入确实被多数节点持久化了
回滚不是故障终点,而是数据一致性重新协商的起点。它的存在本身就在提醒你:那个写入窗口期,你的法定人数(w:majority)并没真正成立。











