rs.reconfig()用于原子性替换整个副本集配置,风险高、易出错,需手动递增version并严格校验;日常增删节点应优先使用rs.add()/rs.addarb()/rs.remove()等安全命令。

rs.config() 返回的是当前副本集的配置文档,不是管理入口。真正用来修改副本集结构的操作,全靠 rs.reconfig() ——但这个命令风险高、限制多,不能当成常规配置工具用。
rs.reconfig() 为什么容易出错
它不是“更新某个字段”,而是原子性地替换整个副本集配置。一旦新配置不合法(比如重复 _id、votes 超过 7、priority 非数字),主节点会拒绝加载并报错:replSetReconfig invalid config。
更麻烦的是,执行成功也会触发强制选举:当前主节点立刻下台,所有客户端连接中断。这不是“热更新”,是“服务抖动”。
- 必须在主节点上执行,从节点连
rs.config()都只读 - 新配置里
version字段必须比当前值大 1,否则被拒绝 - 如果副本集里混了不同 MongoDB 版本(比如 6.0 和 7.0),
rs.reconfig()可能因字段校验规则差异直接失败 -
rs.reconfig()不支持单字段 PATCH,改一个hidden也得把整个members数组重传
添加/移除节点该用什么命令
日常增删成员,优先走专用命令,它们内部做了校验和滚动同步,比手写 rs.reconfig() 安全得多:
- 加普通节点:
rs.add("host:port")—— 自动分配_id,设votes: 1,priority: 1 - 加仲裁节点:
rs.addArb("host:port")—— 自动设arbiterOnly: true,不占votes名额 - 删节点:
rs.remove("host:port")—— 主动通知其他成员剔除该节点,不触发全量重配
这些命令背后仍会调用 rs.reconfig(),但封装了安全边界。比如 rs.addArb() 会确保不突破 7 个投票上限;rs.remove() 会先等待该节点状态变为 REMOVED 再提交配置。
隐藏节点或延时节点必须用 rs.reconfig()
像设置 hidden: true、secondaryDelaySecs: 3600 这类高级属性,没有快捷命令,只能靠 rs.reconfig()。操作流程固定:
- 先
cfg = rs.config()拿到当前配置 - 定位目标成员:
cfg.members[n](注意是数组索引,不是_id) - 改字段:
cfg.members[n].hidden = true、cfg.members[n].priority = 0 - 递增版本:
cfg.version += 1 - 提交:
rs.reconfig(cfg)
关键点:改完必须手动加 cfg.version,MongoDB 不会自动帮你升版;n 是 rs.status().members 里看到的顺序索引,不是配置里的 _id——这两个值经常不一致。
Config 里 votes 和 priority 的区别
新手常混淆这两个字段:
-
votes: 1表示该节点有选举投票权,副本集最多只允许 7 个votes: 1的成员 -
priority: 0表示该节点永不参选主节点,但它仍可投票(只要votes: 1) - 仲裁节点(
arbiterOnly: true)默认votes: 1且priority: 0,但不存数据 - 隐藏节点(
hidden: true)必须配priority: 0,否则可能意外被选为主(虽然客户端看不到它)
真正想让一个节点“只备份不参与任何决策”,得同时设 votes: 0、priority: 0、hidden: true ——但要注意,votes: 0 的节点无法参与选举,也不能被选为同步源,只适合纯冷备场景。
hidden 字段,也要确认当前主节点健康、oplog 足够长、所有成员网络可达——否则 rs.reconfig() 提交后卡在同步,副本集就僵住了。











