Skip to content

MongoDB 自动故障转移

故障检测机制

心跳检测

心跳过程

  • 每个节点定期向其他节点发送心跳包
  • 默认每 2 秒发送一次
  • 心跳包包含节点状态、复制延迟等信息
  • 节点通过心跳检测其他节点的可用性

故障判断条件

  • 连续多次未收到心跳响应
  • 默认超时时间为 10 秒(5 个心跳间隔)
  • 可以通过配置参数调整
  • 当多数节点认为主节点不可用时,触发选举

网络分区处理

脑裂问题

  • 网络分区导致副本集分裂成多个子集群
  • 每个子集群可能尝试选举自己的主节点
  • 可能导致数据不一致

解决方案

  • 使用多数票机制,只有获得多数票的节点才能成为主节点
  • 确保网络分区后只有一个子集群能获得多数票
  • 避免使用偶数个节点,防止无法形成多数票

选举机制

选举触发条件

主要触发条件

  • 主节点故障或网络中断
  • 副本集初始化
  • 主节点主动降级(step down)
  • 副本集配置变更
  • 选举超时

选举过程

  1. 从节点检测到主节点不可用
  2. 从节点将自己的状态改为 "候选节点"(Candidate)
  3. 候选节点向所有投票节点发送选举请求
  4. 投票节点根据选举规则进行投票
  5. 候选节点统计收到的票数
  6. 获得多数票的候选节点成为新主节点
  7. 新主节点通知所有节点,更新自身状态

选举规则

投票节点资格

  • 必须是健康的节点
  • 必须能够与多数节点通信
  • 必须具有投票权(votes: 1)
  • 必须是数据节点(不是仲裁节点)

候选人资格

  • 必须是从节点
  • 必须具有最新的 oplog
  • 必须能够与多数节点通信
  • 优先级(priority)越高,越有可能被选为新主节点

投票规则

  • 每个投票节点只能投一票
  • 节点只能投票给比自己数据更新的候选人
  • 节点不能投票给自己(除非没有其他候选人)
  • 获得多数票的候选人成为新主节点

故障转移配置

配置参数

心跳相关参数

yaml
replication:
  replSetName: rs0
  heartbeatIntervalMillis: 2000  # 心跳间隔,默认 2000 毫秒
  electionTimeoutMillis: 10000   # 选举超时时间,默认 10000 毫秒
  catchUpTimeoutMillis: 2000    # 数据追赶超时时间,默认 2000 毫秒

优先级配置

yaml
replication:
  replSetName: rs0
  members:
    - host: "localhost:27017"
      priority: 2  # 主节点优先级
    - host: "localhost:27018"
      priority: 1  # 从节点优先级
    - host: "localhost:27019"
      priority: 1  # 从节点优先级
    - host: "localhost:27020"
      arbiterOnly: true  # 仲裁节点

运行时调整

调整心跳间隔

javascript
db.adminCommand({
  setParameter: 1,
  heartbeatIntervalMillis: 1000  // 将心跳间隔调整为 1 秒
})

调整选举超时时间

javascript
db.adminCommand({
  setParameter: 1,
  electionTimeoutMillis: 5000  // 将选举超时时间调整为 5 秒
})

手动触发故障转移

javascript
// 主节点主动降级
rs.stepDown()

// 强制重新配置副本集
rs.reconfig(cfg, { force: true })

故障转移监控

状态查看

查看副本集状态

javascript
rs.status()

查看当前主节点

javascript
rs.status().members.find(m => m.stateStr === "PRIMARY").name

查看节点状态码

  • 0: STARTUP - 正在启动
  • 1: PRIMARY - 主节点
  • 2: SECONDARY - 从节点
  • 3: RECOVERING - 恢复中
  • 5: STARTUP2 - 正在同步数据
  • 6: ARBITER - 仲裁节点
  • 7: DOWN - 不可用
  • 8: ROLLBACK - 回滚中
  • 9: UNKNOWN - 未知状态

日志监控

选举日志

2023-01-01T12:00:00.000+0000 I REPL     [replexec-0] Scheduled new election in 0ms to choose new PRIMARY.
2023-01-01T12:00:00.000+0000 I REPL     [replexec-0] conducting a dry run election to see if we could be elected
2023-01-01T12:00:00.000+0000 I REPL     [replexec-0] dry election run succeeded, running for election
2023-01-01T12:00:00.000+0000 I REPL     [replexec-0] election succeeded, assuming primary role in term 2
2023-01-01T12:00:00.000+0000 I REPL     [replexec-0] transition to PRIMARY from SECONDARY

故障检测日志

2023-01-01T12:00:00.000+0000 I REPL     [heartbeatReceiver] Heartbeat failed for member primary:27017; Location18918: Our replica set configuration is invalid or does not include us
2023-01-01T12:00:00.000+0000 I REPL     [ReplicationExecutor] Member primary:27017 is now in state DOWN
2023-01-01T12:00:00.000+0000 I REPL     [ReplicationExecutor] Starting an election, since we've seen no PRIMARY in the past 10000ms

性能监控

监控指标

  • 选举次数和频率
  • 故障转移时间
  • 复制延迟
  • 心跳成功率
  • 节点状态变化

监控工具

  • MongoDB Atlas 监控面板
  • mongostat 和 mongotop
  • 第三方监控工具(如 Prometheus + Grafana)
  • 日志分析工具

故障转移最佳实践

副本集配置

节点数量

  • 建议使用奇数个节点(3、5 或 7 个)
  • 避免使用偶数个节点,防止无法形成多数票
  • 考虑业务的可用性要求和成本

节点分布

  • 跨可用区部署,提高容灾能力
  • 避免所有节点部署在同一物理位置
  • 考虑网络延迟,确保节点间通信顺畅

优先级配置

  • 为重要节点设置较高的优先级
  • 为延迟节点设置较低的优先级
  • 避免频繁的主节点切换

性能优化

网络优化

  • 确保节点间网络带宽充足
  • 减少节点间的网络延迟
  • 避免网络拥塞

资源配置

  • 为主节点分配足够的 CPU 和内存
  • 使用 SSD 存储,提高数据同步速度
  • 确保足够的磁盘空间

配置优化

  • 根据实际情况调整心跳间隔和选举超时时间
  • 优化复制配置,减少复制延迟
  • 确保所有节点的配置一致

故障转移测试

定期测试

  • 定期模拟主节点故障,测试自动故障转移
  • 记录故障转移时间和过程
  • 验证故障转移后的系统状态
  • 测试客户端重新连接

测试方法

  • 关闭主节点进程
  • 断开主节点网络连接
  • 使用 rs.stepDown() 命令手动触发
  • 模拟网络分区

测试注意事项

  • 在业务低峰期进行测试
  • 提前通知相关团队
  • 准备回滚方案
  • 记录测试结果和经验教训

常见问题(FAQ)

Q1: 如何查看副本集的当前状态?

A1: 可以使用 rs.status() 命令查看副本集的当前状态,包括节点状态、主节点信息、复制延迟等。

Q2: 故障转移需要多长时间?

A2: 故障转移通常需要 10-30 秒,具体取决于:

  • 副本集配置(心跳间隔、选举超时时间)
  • 网络状况
  • 节点数量和分布
  • 复制延迟

Q3: 如何减少故障转移时间?

A3: 可以通过以下方式优化:

  • 减小心跳间隔(heartbeatIntervalMillis)
  • 减小选举超时时间(electionTimeoutMillis)
  • 确保低复制延迟
  • 优化网络连接
  • 合理配置节点优先级

Q4: 什么是脑裂问题?如何避免?

A4: 脑裂问题是指网络分区导致副本集分裂成多个子集群,每个子集群可能尝试选举自己的主节点。避免方法:

  • 使用奇数个节点,确保网络分区后只有一个子集群能获得多数票
  • 跨可用区部署,减少网络分区的影响
  • 合理配置节点优先级

Q5: 如何手动触发故障转移?

A5: 可以使用 rs.stepDown() 命令让主节点主动降级,触发新的选举。

Q6: 仲裁节点在故障转移中起什么作用?

A6: 仲裁节点不存储数据,只参与选举投票,帮助副本集在偶数节点情况下达成多数票,提高选举成功率。

Q7: 如何确保故障转移后数据一致性?

A7: MongoDB 使用 oplog 保证数据的最终一致性,故障转移过程中:

  • 只有数据最新的节点才能被选为新主节点
  • 新主节点会继续从旧主节点的 oplog 同步数据
  • 可以使用 write concern 确保数据写入多数节点

Q8: 故障转移对客户端有什么影响?

A8: 故障转移期间:

  • 可能出现短暂的服务不可用(10-30 秒)
  • 客户端需要重新连接到新主节点
  • 建议客户端使用副本集连接字符串,自动发现新主节点
  • 可以配置合适的连接超时和重试机制