mongodb副本集选举不看启动顺序,只依据priority权重和oplog同步进度;priority范围0–1000,默认1,设0则永不参选;修改需连primary执行rs.reconfig(),且oplog落后超10秒将失去参选资格。

副本集选举不看“谁先启动”,只看优先级+数据同步状态
MongoDB 副本集的 Primary 选举不是按启动顺序排队,也不是谁 ping 得快谁上;它本质是一场带权重的投票——priority 是核心加权项,但光有高 priority 不顶用,optime(oplog 同步进度)必须够新。如果一个 priority=5 的节点 oplog 落后主节点 2 分钟,它大概率会被跳过,哪怕其他节点 priority 只有 1。
-
priority取值范围是 0–1000,默认为 1;设为 0 表示该节点永远不能成为 Primary,也不能发起选举(常用于备份节点或延迟从库) - 修改
priority必须通过rs.reconfig(),不能直接改rs.conf()返回的对象——那是只读副本 - 选举前所有参与节点必须能互相心跳(默认
heartbeatTimeoutMillis=10000),且至少有 (N/2 + 1) 个有投票权的节点在线(N 是总投票成员数)
怎么安全调高某节点的 priority 并生效
别连 secondary 改配置,也别在业务高峰期执行;必须连到当前 Primary 执行,否则 rs.reconfig() 会报 NotMaster 错误。
- 先查当前配置:
cfg = rs.conf() - 定位目标成员(注意索引可能变):
cfg.members.find(m => m.host === "node3.example.com:27017"),然后记下它的_id或数组下标 - 改 priority(比如设为 3):
cfg.members[2].priority = 3(假设它是第 3 个成员) - 强制重载配置:
rs.reconfig(cfg, {force: true})—— 加{force: true}是为了绕过“多数节点不可达”时的校验(仅限紧急恢复场景,平时不用)
执行后,原 Primary 可能立即 stepDown(尤其当新 priority 节点数据足够新),整个过程通常 5–15 秒,期间写入会短暂阻塞。
为什么改了 priority 却没当选 Primary?常见三类漏判
Priority 高 ≠ 自动上位。选举失败往往卡在隐性条件上,而不是配置本身写错了。
-
oplog 进度太旧:用
rs.printSecondaryReplicationInfo()看各节点落后多少秒;若 >catchUpTimeoutMillis(默认 10 秒),该节点直接失去参选资格 -
投票权被禁用:检查
cfg.members[i].votes是否为 0(默认是 1);votes=0的节点不参与投票,也不被投票 -
网络分区残留:曾发生过网络抖动的节点,可能还缓存着旧 term 或 vote 请求;重启 mongod 进程可清空状态(比
rs.stepDown()更彻底)
raft 协议?MongoDB 其实没用 Raft
MongoDB 副本集用的是自己实现的 election protocol v1(基于 Paxos 思想改良),不是 Raft。虽然都靠多数派投票、term 递增、log 匹配等机制保证一致性,但细节差异很大——比如 MongoDB 没有 leader lease,也没有 Raft 的 pre-vote 阶段;它的 electionTimeoutMillis 是随机漂移的(避免多个节点同时发起选举导致分裂投票)。
所以别套用 Raft 教程去调 heartbeat.interval 或模拟 follower timeout;MongoDB 的故障转移节奏由 settings.electionTimeoutMillis(默认 10s)、protocolVersion: 1 和 catchUpTimeoutMillis 共同决定,其中后者才是影响“能否抢在 w:1 写入丢失前完成切换”的关键参数。
真正容易被忽略的,是 priority 修改后不会立刻触发选举——得等下次心跳超时或主动 stepDown;而 oplog 同步延迟这种“看不见”的状态,往往比配置本身更早卡住整个流程。










