滚动重启需确保副本集持续可用,核心是先以standalone模式重启从节点、再stepDown主节点并降级重启,全程避免oplog落后、选举震荡和索引冲突。

滚动重启不是简单地挨个 kill -9 再启动,而是必须让副本集在大部分时间保持可写、可读,同时避免 oplog 落后、选举震荡或唯一索引冲突。核心在于:从节点先独立重启,主节点最后降级再处理。
从节点必须以 standalone 模式重启
直接在 replSet 模式下重启从节点,会触发不必要的连接重试和心跳超时,还可能因配置变更(如 replication.oplogSizeMB)导致启动失败。正确做法是临时切为独立模式:
- 注释掉配置文件中的
replication.replSetName,并修改net.port到备用端口(如从 27017 改为 27217) - 在
setParameter中添加disableLogicalSessionCacheRefresh: true,防止 session cache 刷新失败阻塞启动 - 如果该节点是分片或 config server 成员,还需注释
sharding.clusterRole并加skipShardingConfigurationChecks: true - 用新端口启动后,确认
mongosh --port 27217能连上,且db.isMaster()返回"ismaster": true(此时它就是个 standalone)
主节点不能直接重启,必须先 rs.stepDown()
对主节点执行 db.shutdownServer() 或 systemctl restart,会强制触发一次完整选举,新 PRIMARY 可能尚未加载完新配置(比如新版本的 WiredTiger 参数),造成写入阻塞 10–30 秒甚至数据回滚。必须主动让权:
- 先在主节点上运行
rs.stepDown(60)(参数 60 表示至少 60 秒内不参选),确保有足够时间完成切换 - 等
rs.status()显示原主已变成"stateStr": "SECONDARY",且新 PRIMARY 状态稳定 - 再对原主节点执行 shutdown + standalone 重启流程(同从节点)
- 最后用原始配置(恢复
replSetName等)重启,让它作为 SECONDARY 加入,自动同步 oplog
oplog 大小和写入暂停是隐形雷区
滚动重启期间,被重启的节点会暂时脱离复制链,靠重放 oplog 追平。如果 oplog 不够大,或者应用持续写入,该节点重启后可能无法追上,最终进入 "RECOVERING" 或 "STALE" 状态,甚至被踢出副本集:
- 重启前用
rs.printReplicationInfo()查看 oplog 当前保留窗口,确保它大于预期维护总耗时(建议预留 2 倍余量) - 若要调整,需在所有节点都在线时,通过
replSetResizeOplog命令或replication.oplogSizeMB配置项修改——但注意:该操作本身也会触发一次全量同步风险 - 构建唯一索引等敏感操作,必须配合
db.fsyncLock()暂停写入,否则滚动过程中不同节点索引状态不一致,会导致写冲突或主从不一致
自动化工具(Ops Manager / Atlas)的滚动行为差异
Ops Manager 的滚动重启看似省事,但它默认按“一次更新一个从节点 → stepDown 主 → 更新原主”执行,底层仍是上述逻辑。但你得清楚它不帮你做三件事:
- 不会自动检查 oplog 是否够用,
replication.oplogSizeMB改了也不会实时生效,必须提前调大 - 不会帮你停写,遇到唯一索引构建需求时,它仍会报错
Cannot create unique index on a replica set while writes are enabled - 如果集群里混着不同 MongoDB 版本(比如 config server 是 6.0,shard 是 7.0),它可能跳过兼容性校验,直接升级导致路由失效
真正麻烦的从来不是“怎么点按钮”,而是重启前后那几分钟里,oplog 是否撑得住、PRIMARY 切换是否干净、以及你有没有意识到:那个被你注释掉的 replication.replSetName,必须在重启后原样还原,漏一个字符都会让节点卡在 "STARTUP2" 状态不动。











