选举失败的根本原因是法定多数无法达成,即存活且有投票权的节点数不足⌊n/2⌋+1;需通过rs.status()检查health和statestr,结合rs.conf()确认votes、priority及网络连通性。

是,但“投票节点不足”只是表象,真正卡住选举的是法定多数(majority)无法达成——即存活且有投票权的节点数 ⌊n/2⌋ + 1。
rs.status() 显示 DOWN 或 UNKNOWN 就等于投票节点失效
副本集不会因为“某个节点进程还在跑”就把它算进法定票数。只要 rs.status() 里某个成员的 health 是 0,或 stateStr 是 "DOWN"、"UNKNOWN"、"STARTUP"(非 "PRIMARY"/"SECONDARY"),它就不参与投票,哪怕 mongod 进程没挂。
- 常见诱因:该节点
bindIp只配了127.0.0.1,其他成员连不上它,心跳失败后自动标记为DOWN - 防火墙没放行 27017 端口,
telnet <node-ip> 27017</node-ip>通不过,也会导致持续health: 0 - 日志里反复出现
"heartbeat to <host> failed after 10000ms"</host>,说明心跳断了,节点已被踢出投票池
votes: 0 和 priority: 0 节点不计入 majority 计算
一个节点即使在线、健康、能同步 oplog,只要它的配置里 votes: 0 或 priority: 0(且 hidden: true),它就不在法定多数分母里——不是“少一票”,而是“直接不算人”。
- 3 节点副本集,如果其中一个是
votes: 0的延迟备份节点,那实际投票节点只剩 2 个,majority = ⌊2/2⌋ + 1 = 2,看起来够;但如果另一个节点也因网络问题掉线,立刻变成 1 个有效投票者,1 ,选举卡死 -
rs.conf()里看每个成员的votes字段,别只信进程状态;hidden: true默认带votes: 0,但显式写出来更稳妥 - 仲裁节点(arbiter)必须
votes: 1且priority: 0,否则它既不投票也不被选,纯属占坑
强制重配 rs.reconfig() 前必须核对 configVersion 和 replSetName
用 rs.reconfig() 清理掉失联节点或修正 votes 设置时,如果新配置的 _id(即 replSetName)和原集群不一致,或者 configVersion 没递增,节点会拒绝加载,继续 stuck 在旧配置里。
- 执行前先运行
rs.conf(),记下当前_id和version字段 - 修改
members数组时,只保留stateStr: "SECONDARY"且health: 1的节点,删掉所有"DOWN"或"UNKNOWN"条目 - 新配置对象里
version必须比原值大 1,_id必须完全一致,否则rs.reconfig(cfg, {force: true})也救不回来
最常被忽略的是:节点间 DNS 解析失败或 host 写错(比如用了 localhost 或容器内网 IP),会导致重配后新成员始终卡在 STARTUP2,看似在线实则无法加入投票闭环——此时 rs.status() 里它可能显示 "RECOVERING",但 health 仍是 1,容易误判。











