零中断不可行,但可将中断压至30秒内且不丢写入;关键在于客户端自动扛过闪断,需使用含全部节点的高可用URI、启用heartbeatFrequencyMS,并避免硬编码IP。

做不到零中断,但可以压到单次 30 秒以内,且不丢写入。关键不是“不中断”,而是让客户端自动扛过闪断、不报错、不重试失败。
为什么 mongos 或应用直连 PRIMARY 一定会中断
副本集滚动升级时,PRIMARY 必须主动退位(rs.stepDown())才能安全停掉它。这个过程会触发一次选举,新 PRIMARY 选出前,整个副本集在几秒内无法接受写请求;即使只读,旧连接若还连着已降级的节点,也会因 NotMasterNoSlaveOk 报错断开。直连地址或没配 readPreference 的驱动,根本不知道该切到哪。
- 用
ConnectionStringURI高可用地址(含所有节点域名+?replicaSet=xxx)是硬性前提 - 驱动必须启用
heartbeatFrequencyMS(默认10000),否则发现主切慢,连接池里大量 stale 连接会持续失败 - 禁止在应用层硬编码某台机器的 IP 或端口——哪怕你加了负载均衡,只要没走 replica set discovery 机制,就等于裸奔
rs.stepDown() 后 PRIMARY 切换卡住的典型表现
日志里反复出现 election timeout,rs.status() 中多个节点 stuck 在 STARTUP2 或 RECOVERING,新 PRIMARY 的 optimeDate 落后太多。这不是网络问题,而是旧 PRIMARY 没真正释放 oplog 锁,或新节点启动时 storage.engine 配置错(比如误启 mmapv1,7.0 已不支持)。
- 执行
rs.stepDown(30)前,先确认rs.printSecondaryReplicationInfo()显示所有 SECONDARY 的optimeDate距离 PRIMARY 不超过10秒 - 停旧节点前,用
db.currentOp({secs_running: {$gt: 30}})检查长事务,避免 stepDown 被阻塞 - 新二进制启动后,立刻查日志是否有
Failed to load config或WiredTiger error—— 这类 ERROR 级别报错会导致节点拒绝加入集群,而不是静默失败
FCV 升级时机和驱动兼容性陷阱
setFeatureCompatibilityVersion 不能在升级完二进制后立刻调,也不能拖到所有节点都换完再调。它必须在“最后一个旧版本节点下线后、第一个新版本节点完成 initial sync 前”这个窄窗口执行。早了,旧节点起不来;晚了,新节点可能已按新规则写入数据(如 7.0 的 strictValidation),导致旧驱动解析失败。
- 5.0 → 6.0 → 7.0 升级路径中,每步 FCV 只能升一级,且升完必须等
24小时再进行下一步 - Java Driver 4.11+ 才完整支持 7.0 的
clusterTime v2和changeStreamPreAndPostImages,老版本驱动连上 7.0 会静默降级协议,聚合性能掉一半 - 升级期间禁用
mongod --repair:7.0 的 repair 逻辑已改,对 5.0 数据文件直接运行可能损坏索引
最易被忽略的一点:云厂商托管实例(如阿里云 MongoDB)的「可维护时间段」设置,和你手动滚动升级是两套机制。即使你全用脚本控制节奏,如果实例后台正跑着平台级维护任务,仍可能在你升级中途插入一次强制重启。务必提前查清当前实例是否处于维护等待队列中,用 db.adminCommand({getCmdLineOpts: 1}) 看 setParameter 里有没有平台注入的配置。











