安全关闭mongodb副本集的正确顺序是:先执行rs.stepdown(30)使主节点主动降级为secondary,再逐个调用db.shutdownserver()关闭节点;必须先关从节点,最后关已降级的原主节点。

rs.stepDown() 必须在 shutdownServer() 之前执行
直接对主节点调用 db.shutdownServer() 会触发强制选举,未同步到多数节点的 oplog 可能丢失,客户端收到 NotWritablePrimary 错误。真正安全的顺序是:先让主节点主动退位,再关进程。
执行 rs.stepDown(30) 后,该节点会拒绝新写入、等待当前写操作完成,并阻塞最多 30 秒(避免频繁切换)。期间它仍是“逻辑主节点”,但只读;一旦降级成功,rs.status().myState 变为 2(SECONDARY),rs.status().primary 指向新主节点。
- 若返回
NotMaster,说明已开始或完成降级,不用重试 - 若超时后
stateStr仍为PRIMARY,检查db.serverStatus().metrics.repl.buffer.sizeBytes是否积压过大,或是否存在长事务阻塞 - 不要用
rs.freeze()替代——它不改变主身份,仍收写请求,维护窗口不可控
shutdownServer() 要逐节点执行,且必须确认状态后再操作
db.shutdownServer() 是安全终止命令,但只作用于当前连接的节点。它不是集群级操作,也不能跳过状态校验直接调用。
每个节点都需单独连接(用 mongo --host <node_ip>:27017</node_ip>),切到 admin 数据库,再执行命令。顺序上:先关所有从节点,最后关已降级的原主节点。
- 关从节点前,确认它在
rs.status()中的lastHeartbeatRecv时间距今 - 关原主节点前,再次运行
rs.status(),确保它的optimeDate≤ 新主节点的optimeDate,否则说明复制延迟未追平 - 如果某从节点提示
"No electable secondaries caught up",说明新主还没完成选举或同步,需等待并重试rs.status()
避免用 kill -9 或 mongod --shutdown 管理副本集节点
mongod --shutdown 和 kill -9 都绕过 MongoDB 内部状态机,不等待 oplog 刷盘、不通知其他成员,极易导致数据不一致或启动失败。
它们只适用于单机调试场景。在副本集中,mongod --shutdown 无法感知复制状态,也不会触发选举协调;而 kill -9 会让剩余节点在 10–30 秒内发起无准备选举,期间写入可能被丢弃。
- 正确做法永远是:shell 连接 →
use admin→db.runCommand("shutdown")或db.shutdownServer() - 如果进程无响应,优先用
kill -2(SIGINT)代替kill -9,它会触发同shutdownServer类似的清理流程 - Kubernetes 环境下,不要
kubectl delete pod,应kubectl exec进入容器后执行 shutdown 命令
应用层连接和驱动配置容易被忽略
即使 MongoDB 节点已按序关闭,客户端也可能因缓存旧连接或配置不当持续报错。PyMongo、Node.js driver 等默认使用 readPreference=primary,降级后会自动重连新主——但这依赖 DNS 解析、连接池刷新和重试策略。
硬编码直连某个 IP(如 mongodb://192.168.2.150:27017)的代码,在原主节点降级后会持续失败,直到连接池超时重建。
- 检查应用是否设置了
connectTimeoutMS和socketTimeoutMS,过长会导致卡住数秒 - 确认连接字符串中包含全部副本集成员(如
mongodb://a,b,c/?replicaSet=rs1),而非仅一个地址 - 运维期间可临时把应用的
maxPoolSize设小,加速连接释放,避免残留连接占用原主端口
stateStr: "SECONDARY" 就以为万事大吉——其实 oplog 同步可能刚追到一半,optimeDate 还没赶上新主。这时候关进程,等于亲手删掉那几十秒的写入。











