零停机升级在 MongoDB 副本集中实为滚动升级,需满足三硬条件:统一主版本、提前设置 featureCompatibilityVersion、升级前节点为 SECONDARY 且 oplog 落后 ≤30 秒;选举期间写入中断 1–5 秒,依赖应用重试实现“无感知”。

零停机升级在 MongoDB 副本集里不是“完全不中断”,而是通过控制节点逐个滚动升级,让主节点切换和数据同步过程对应用透明——前提是业务能容忍短暂的写入重试、读取延迟或连接抖动。
为什么不能真·零停机?
副本集升级必然涉及 rs.stepDown()、rs.remove()、rs.add() 等操作,这些会触发选举;而选举期间(通常 1–5 秒)主节点不可写,新主节点建立前的写请求会返回 NotMaster 或 InterruptedAtShutdown 错误。所谓“零停机”实际指:应用层自动重试后无感知,而非服务端毫秒级无缝。
滚动升级必须满足的三个硬条件
缺一不可,否则可能卡住选举或同步失败:
- 所有节点必须运行同一主版本(如全为 6.0.x),补丁版本可不同但建议统一
-
featureCompatibilityVersion必须提前设为待升级目标版本(例如升 7.0 前需先在 6.0 上执行db.adminCommand({setFeatureCompatibilityVersion: "7.0"})) - 每个节点升级前,必须确认其状态为
SECONDARY且optimeDate落后主节点不超过 30 秒(用rs.status()查看)
关键操作顺序与避坑点
跳过任意一步都可能导致整个副本集不可用:
- 先选一个低负载的
SECONDARY节点,执行rs.syncFrom("primary-host:27017")强制拉取最新 oplog,再rs.freeze(0)防止它被选为主 - 停该节点:
db.shutdownServer(),替换二进制文件(/usr/bin/mongod),修改配置中storageEngine和dbpath(若引擎变更),但**不要改replSetName或删replication段** - 重启后立刻连上,运行
rs.status()—— 如果卡在STARTUP2超过 60 秒,大概率是wiredTiger数据目录权限不对或journal文件损坏,此时要mongod --repair再启 - 等它变成
SECONDARY并追平主节点后,再对下一个节点重复;最后才对原主节点操作:先rs.stepDown(30)(给足 30 秒让从节点升主),等新主稳定后再停旧主升级
升级后最易忽略的验证项
很多人只测了读写,却漏掉这两件事:
- 检查
db.serverStatus().metrics.repl.buffer.count是否为 0 —— 非 0 表示 oplog 缓冲区堆积,说明同步链路有瓶颈(常见于网络抖动或磁盘 IO 不足) - 在新主上执行
db.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}),确认 version 字段确实是目标值(如"7.0"),而不是仍为"6.0"—— 这个参数不随二进制升级自动更新,必须手动设
真正影响升级成败的,从来不是命令敲得对不对,而是 featureCompatibilityVersion 是否提前就位、oplog 是否实时追平、以及新二进制启动后有没有静默卡在 STARTUP2 状态——这三个点没盯住,滚动升级就会变成全集群不可写。











