频繁选主是集群健康度出问题的明确信号,会导致写入中断、已提交数据回滚及应用超时或重复失败,必须立即排查而非等待自愈。

频繁选主不是“偶尔抖一下”,而是集群健康度出问题的明确信号——写入会中断,已提交的数据可能回滚,应用端感知为超时或重复失败。必须立刻排查,不能等它自己恢复。
查选举发生频率和时间点
先确认是不是真频繁:在任意节点连上 mongosh,反复执行 rs.status(),重点关注 members[n].stateStr 和 members[n].uptime 变化;更直接的是看日志里有没有密集出现 ELECTION 组件条目。
- 每小时超过 1 次选举,基本可判定异常;每天几次且发生在维护窗口内,属正常
- 用
grep "ELECTION" /var/log/mongodb/mongod.log | tail -50快速筛最近 50 条选举记录 - 注意日志中紧邻的两行:
"看不到该设立的大多数,放弃主节点"(旧主降级)和"transition to PRIMARY from SECONDARY"(新主上位),中间间隔若短于 30 秒,说明网络或心跳异常
验证多数派是否稳定在线
选举失败或反复触发,根源几乎总是“够票数的节点数不足”。MongoDB 要求存活且可投票节点数 ≥ ceil(N/2),N 是总投票节点数(members[n].votes === 1 的才算)。
- 运行
rs.status().members.filter(m => m.stateStr !== "ARBITER" && m.health > 0).length,结果必须 ≥ 多数票数(如 4 节点需 ≥ 3,3 节点需 ≥ 2) - 特别警惕“偶数节点 + 无仲裁者”组合:4 节点集群挂掉 2 个,剩 2 个也无法选出主;而 3 节点挂 1 个,剩 2 个照常工作
-
members[n].health为 0 表示该节点被其他成员标记为失联,不参与投票,哪怕它进程还在跑
检查心跳超时与网络连通性
心跳失败是多数派断裂的直接诱因。默认心跳间隔 2 秒、超时 10 秒,但网络抖动、高延迟或防火墙策略可能让心跳包丢弃率飙升。
- 在每个节点上执行
ping -c 5 <其他节点IP>和telnet <其他节点IP> 27017,确认双向 TCP 连通 - 检查
rs.conf().settings.heartbeatTimeoutSecs是否被误设为过小值(如 5),这会让短暂抖动直接触发选举 - 不要调低
heartbeatTimeoutSecs来“加快故障发现”——它只会增加误判,真正该优化的是网络质量或增加仲裁节点(仅用于奇数补足,不加在 shard 上)
盯住 oplog 和复制滞后
复制严重滞后会导致节点被踢出投票组,间接破坏多数派。主节点 oplog 若太小,从节点追不上就会进入 STARTUP2 或 RECOVERING 状态,不再参与选举。
- 在主节点运行
rs.printReplicationInfo(),看log length start to end是否低于 1 小时(理想应 ≥ 24 小时) - 在主节点运行
rs.printSecondaryReplicationInfo(),检查各从节点syncedTo时间差,滞后 > 60 秒即算异常 - 滞后常见原因:磁盘 IO 不足(
iostat -x 1查 %util)、网络带宽打满、大事务阻塞 oplog 应用
最容易被忽略的点是:你以为节点“活着”,但它已被集群集体拉黑——health: 0 不等于进程崩溃,可能是心跳连续失败后被静默剔除。别只看 ps aux | grep mongod,得进 shell 看 rs.status() 里每个成员的真实状态字段。

















