选举根本不会触发,因为至少半数以上投票节点必须在线且能互相心跳通信;若rs.status()显示votingMembersCount不足半数(如3节点集群仅1个健康)、members[n].lastHeartbeatRecv停滞或stateStr为"OTHER",则无法发起选举。

rs.status() 显示多数节点不可达,选举根本不会触发
副本集选举的前提是:**至少半数以上投票节点在线且能互相心跳通信**。如果主节点宕机时,另外两个从节点也因网络分区、防火墙拦截或自身崩溃而无法互通,rs.status() 会显示大量 stateStr: "OTHER" 或 health: 0,此时没有足够成员发起或参与投票,选举直接被跳过。
常见错误现象:rs.status() 中 votingMembersCount 小于总投票节点数的一半(比如 3 节点集群只剩 1 个健康节点,votingMembersCount = 1);members[n].lastHeartbeatRecv 时间戳停滞在宕机前。
- 检查每个节点是否真实运行:
ps aux | grep mongod+ 端口连通性(telnet 192.168.x.x 27017) - 确认防火墙放行了所有节点间的 27017 端口(双向)和心跳端口(默认同服务端口)
- 仲裁节点(arbiter)不存数据,但必须在线——它算 1 票,缺它就可能卡在 2/3 投票门槛
心跳超时未到,旧主仍被视作“活着”,新选举被抑制
MongoDB 默认每 2 秒发一次心跳,连续 10 秒收不到响应才标记节点为不可达。这意味着主节点实际宕机后,其余节点要等满 10 秒才会开始考虑选举——这期间整个副本集写入不可用,但你不会看到任何“正在切换”的提示。
容易踩的坑:
-
settings.electionTimeoutMillis被误设为极大值(如 60000),导致故障响应拖到 1 分钟以上 - 网络延迟高或丢包严重,使心跳偶尔超时,触发频繁误判和震荡选举
- 旧主进程僵死但端口仍监听(如 OOM 后卡住),其他节点能连上却收不到有效响应,陷入“假存活”状态
验证方式:在从节点上执行 rs.conf(),检查 settings.electionTimeoutMillis 值;再看 rs.status().members[n].lastHeartbeat 和 lastHeartbeatRecv 的时间差是否稳定 ≤2s。
有节点 priority=0 或 votes=0,可用候选者不足
即使心跳正常、节点都在线,如果所有健康的从节点都被配置为 priority: 0 或 votes: 0,它们将主动放弃参选资格。此时哪怕只剩一个从节点活着,它也不会尝试成为主节点——因为配置上它“不允许当主”。
典型场景:
- 把灾备机房的从节点设为
priority: 0防止跨机房抢主,但主节点和同城从节点同时出事,灾备节点就沉默了 - 误删了仲裁节点,又把某个从节点的
votes改成 0,3 节点集群实际只剩 1 票,达不到选举最低要求(需 ≥2) -
rs.conf()中members[n].buildIndexes为 false 且priority为 0,双重锁定参选能力
修复命令示例(在当前主节点或任意可写节点上):
cfg = rs.conf(); cfg.members[1].priority = 1; rs.reconfig(cfg, {force: true})
oplog 同步严重滞后,选举被主动拒绝
选举算法会优先选择 optimeDate 最新的节点。但如果所有从节点的 oplog 都比主节点落后太多(比如 >30 分钟),MongoDB 会认为“没有一个节点的数据够新”,拒绝启动选举,避免选出一个明显丢数据的主节点。
关键指标:
-
rs.status().members[n].optimeDate:该节点最后应用的操作时间 -
rs.status().members[n].lastAppliedWallTime:更精确的时间戳(4.2+) - 对比主节点的
optimeDate,差值超过settings.catchUpTimeoutMillis(默认 10 秒)即视为同步失败
同步滞后常因磁盘 I/O 慢、从节点负载高、或主节点写入突增导致。不要只看 stateStr: "SECONDARY" —— 状态正常不代表数据新鲜。
真正卡住自动切换的,往往不是单个配置错误,而是多个条件叠加:网络分区 + 低优先级节点 + 同步延迟。排查时别只盯着“为什么没切”,先用 rs.status() 和 rs.conf() 锁定哪一环断了——选举不是魔法,它严格依赖心跳、票数、数据新鲜度三者同时满足。


















