rs.add()后节点卡在STARTUP2或RECOVERING,主因是bindIp配置错误、主机名解析失败、防火墙阻断或Docker网络配置不当;需确保各节点IP可达、端口开放、host可解析且一致。

为什么 rs.add() 后节点状态始终是 STARTUP2 或 RECOVERING
常见现象是新加入的副本集成员卡在 STARTUP2 长达数分钟,或反复切换为 RECOVERING,无法进入 SECONDARY。这通常不是同步慢,而是节点间无法完成初始握手——最常被忽略的是 bindIp 配置和主机名解析。
-
bindIp必须包含所有可被其他节点访问的 IP(如192.168.1.10,127.0.0.1),不能只写127.0.0.1;否则其他节点连不上它 - 所有节点的
host字段(在rs.add({host: "xxx"})中)必须能被彼此ping通,且nslookup xxx返回一致的 IP;用 IP 替代主机名更稳妥 - 防火墙需放行 MongoDB 默认端口(
27017)及选举端口(TCP/UDP 均需) - 如果使用 Docker,注意容器网络模式:
host模式下直接暴露宿主机端口,bridge模式需显式publish并确保容器间路由可达
如何正确配置奇数节点与仲裁节点(arbiterOnly: true)
副本集必须有奇数个投票成员(votes: 1),否则可能因票数平局导致无法选出主节点。但并非所有节点都该参与投票——数据节点要消耗磁盘和内存,而仲裁节点只参与投票、不存数据,适合部署在轻量资源上。
- 三节点标准部署:两个
data-bearing节点(votes: 1) + 一个仲裁节点(votes: 1, arbiterOnly: true) - 四节点场景下,不要给第四个数据节点设
votes: 1;应设为votes: 0, priority: 0,仅作备份读取,避免破坏投票奇偶性 - 仲裁节点必须单独启动(不能和数据节点共用进程),且其配置中
storage.dbPath可为空或指向临时目录,MongoDB 不会往里写数据 - 添加仲裁节点时,必须在已有 PRIMARY 上执行:
rs.add({host: "arbiter-host:27017", arbiterOnly: true}),不能在 SECONDARY 上操作
故障转移失败?检查 priority、hidden 和 slaveDelay 的组合影响
自动故障转移不触发,或者切到非预期节点,往往不是选举机制坏了,而是节点权重或角色设置互相冲突。MongoDB 选主时按顺序比对:优先级(priority)→ 数据新鲜度(optime)→ 成员 ID。
-
priority值越大越容易当选 PRIMARY,但hidden: true或slaveDelay > 0的节点即使priority高也不会参选——它们被明确标记为“不可用作主” - 若某节点设了
slaveDelay: 3600(延迟 1 小时同步),它永远无法成为 PRIMARY,因为它的optime永远落后 - 调整
priority必须通过rs.reconfig()全量更新配置,不能只改单个字段;且新配置需带_id和完整成员数组,否则报错replSetReconfig old config version is higher - 测试故障转移时,别 kill 进程——用
db.shutdownServer()更贴近真实崩溃场景;kill -9 可能导致 oplog 截断,引发回滚风险
如何验证自动故障转移是否真正生效
光看 rs.status().members[n].stateStr 是 PRIMARY 不够,得确认应用连接是否无缝续上。很多问题出在客户端驱动没启用副本集发现机制,或 DNS 缓存导致连接旧地址。
- 连接字符串必须含全部节点,例如:
mongodb://node1:27017,node2:27017,node3:27017/?replicaSet=rs0;只写一个地址等于单点连接 - 驱动默认有重试逻辑,但首次连接超时(
connectTimeoutMS)建议设为 5–10 秒,避免因主节点宕机时等待过久 - 手动触发一次故障:
db.adminCommand({replSetStepDown: 60})(强制降级并禁止 60 秒内参选),观察日志中是否出现election succeeded,以及应用日志是否有TopologyDescription changed - 真正关键的验证点是:故障期间写操作是否返回错误(如
NotPrimaryNoSecondaryOk)?恢复后是否自动重试成功?这需要在应用层埋点,而不是只盯 MongoDB 日志


















