直接修改rs.conf()返回对象的priority无效,必须深拷贝配置、递增version并调用rs.reconfig();priority=0节点不参选但可读可复制;改priority后需配合rs.stepDown()才能触发主切换。

直接改 rs.conf() 返回对象的 priority 字段没用——它是个只读副本,必须深拷贝+递增 version+重写整个配置才能生效。
rs.conf() 返回的是只读对象,不能原地修改
很多人执行 cfg = rs.conf() 后直接写 cfg.members[1].priority = 5,以为改完了。其实这个 cfg 是 shell 封装的只读代理,字段赋值不触发底层更新。后续调用 rs.reconfig(cfg) 要么静默失败,要么报错 "new configuration not greater than current"。
- 正确做法:先用
cfg = rs.conf()拿到当前配置,再用JSON.parse(JSON.stringify(cfg))或手动重建对象完成深拷贝 - 索引别搞混:
members[0]对应数组第一个节点,和节点自身的_id字段无关 - 改完记得检查:
cfg.members[0].priority确实是你设的值,不是还显示1
rs.reconfig() 前必须手动递增 cfg.version
rs.reconfig() 会校验版本号是否严格递增。如果只改了 priority 却漏掉 cfg.version++,MongoDB 直接拒绝应用,错误信息通常是 "reconfig in progress" 或 "new configuration not greater than current"。
- 安全写法:
cfg.version = cfg.version + 1(别用++,某些 mongosh 版本有坑) - 版本号是整数,不能是浮点数;也不能跳着加(比如从 5 直接到 10),必须每次 +1
- 如果副本集刚做过 reconfig,
rs.conf().version可能还是旧值,建议执行前先rs.status()确认主节点状态
priority=0 的节点不参选但可读可复制
设成 priority: 0 是让节点彻底退出选举博弈的最常用方式,比如备份机、报表节点或延迟节点。但它仍是副本集一员,持续拉取 oplog、响应读请求(需客户端显式设置 readPreference=secondary)。
-
priority取值范围是0到1000,支持浮点数(如0.5、2.3),默认是1 - 非投票节点(
votes: 0)的priority必须为0;反过来,priority > 0的节点votes必须为1 - 隐藏节点(
hidden: true)也必须配priority: 0,否则配置校验通不过
改完 priority 不等于立刻切主,得配合 rs.stepDown()
就算你把某节点 priority 调到 10,只要当前 PRIMARY 还健康在线,它就不会自动退位。MongoDB 不会在 rs.reconfig() 后触发选举。
- 稳妥做法:在当前主节点上执行
rs.stepDown(60),让它主动下台并禁选 60 秒,给高优先级节点留出窗口 - 危险操作:直接
db.shutdownServer()关主节点,可能造成短暂不可写,甚至多数派失联导致整个副本集不可用 - 验证是否成功:执行完后立刻查
rs.isMaster().primary和rs.status().myState,别只信 shell 提示的 “ok: 1”
真正容易被忽略的是:priority 只影响“谁更可能赢”,不保证“一定赢”。即使 priority 最高,如果该节点数据滞后、心跳超时或网络不通,照样落选。所以调完 priority,务必确认目标节点的 optimeDate 和 lastHeartbeatRecv 是新鲜的。











