Skip to content

MongoDB 手动故障切换

手动故障切换前的准备

检查复制集状态

在执行手动故障切换前,需要检查复制集的状态,确保所有节点都正常运行:

javascript
// 连接到复制集
mongo "mongodb://primary:27017,secondary1:27017,secondary2:27017/admin?replicaSet=rs0"

// 检查复制集状态
rs.status()

需要关注的关键信息:

  • 所有节点的状态(StateStr):应显示为 PRIMARY、SECONDARY 或 ARBITER
  • 节点的健康状态(health):应为 1
  • 复制延迟(optimeDate 或 heartbeatIntervalMillis):应尽可能小
  • 选举多数派(votingMembersCount):确保有足够的投票节点

检查复制延迟

确保所有从节点与主节点的复制延迟较小,避免切换后数据不一致:

javascript
// 检查复制延迟
rs.printSecondaryReplicationInfo()

复制延迟(secs behind primary)应尽可能接近0,建议在延迟小于10秒时执行切换。

选择目标节点

选择合适的目标节点作为新的主节点,应考虑以下因素:

  1. 硬件性能:目标节点的硬件性能应与当前主节点相当或更好
  2. 复制延迟:复制延迟应尽可能小
  3. 地理位置:如果是跨数据中心部署,应选择距离应用更近的节点
  4. 节点角色:应选择具有投票权的SECONDARY节点
  5. 磁盘空间:确保目标节点有足够的磁盘空间
  6. 负载情况:选择负载较低的节点

通知相关团队

在执行手动故障切换前,应通知相关团队:

  • 应用开发团队
  • 运维团队
  • 业务团队
  • 监控团队

确保相关团队了解切换时间、影响范围和应急措施。

手动故障切换的执行步骤

方法一:使用 rs.stepDown() 命令

rs.stepDown() 命令是执行手动故障切换的首选方法,它会使当前主节点主动降级为从节点,并触发新的选举。

1. 连接到当前主节点

bash
mongo "mongodb://primary:27017/admin"

2. 执行 stepDown 命令

javascript
// 执行 stepDown 命令,等待30秒让其他节点完成选举
rs.stepDown(30)

命令参数说明:

  • stepDownSecs:主节点降级后保持降级状态的时间(秒)
  • secondaryCatchUpPeriodSecs:等待从节点追赶的时间(秒)

3. 验证切换结果

javascript
// 检查新的主节点
rs.status().members.forEach(member => {
  if (member.stateStr === 'PRIMARY') {
    print(`新的主节点:${member.name}`);
  }
});

方法二:使用 rs.freeze() + rs.stepDown() 组合命令

如果需要更精确地控制切换过程,可以使用 rs.freeze() 命令冻结某些节点,然后执行 rs.stepDown()

1. 冻结不需要成为主节点的节点

javascript
// 冻结节点300秒
rs.freeze(300)

2. 执行 stepDown 命令

javascript
rs.stepDown(30)

3. 解冻被冻结的节点

javascript
// 解冻节点
rs.freeze(0)

方法三:使用 rs.reconfig() 命令

在某些特殊情况下,可以通过重新配置复制集来强制故障切换。

1. 获取当前配置

javascript
const cfg = rs.conf()

2. 修改配置

javascript
// 修改主节点的优先级(可选)
cfg.members[0].priority = 0.5
cfg.members[1].priority = 1.0

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

3. 恢复原始配置

切换完成后,记得恢复原始配置。

手动故障切换的注意事项

数据一致性

  1. 确保复制延迟较小:在执行切换前,确保所有从节点的复制延迟较小
  2. 等待 oplog 追赶:使用 secondaryCatchUpPeriodSecs 参数等待从节点追赶
  3. 验证数据完整性:切换后验证关键数据的完整性

应用影响

  1. 短暂的写不可用:手动故障切换期间,写操作会有短暂的不可用
  2. 连接池管理:应用应正确处理主节点切换,包括重新连接和重试机制
  3. 读偏好设置:如果应用使用了特定的读偏好,应确保其在切换后仍然有效

监控与告警

  1. 开启监控:在切换过程中,密切监控复制集状态
  2. 准备告警规则:确保相关告警规则已配置,能够及时发现问题
  3. 记录切换过程:详细记录切换时间、步骤和结果

权限要求

执行手动故障切换需要具有 clusterManagerclusterAdmin 角色的用户权限。

javascript
// 创建具有 clusterManager 角色的用户
use admin
db.createUser({
  user: "admin",
  pwd: "password",
  roles: ["clusterManager"]
})

手动故障切换的最佳实践

计划性切换

  1. 选择合适的时间窗口:在业务低峰期执行切换
  2. 提前测试:在测试环境中演练切换流程
  3. 制定回滚计划:准备好切换失败时的回滚方案
  4. 逐步执行:分步骤执行,每一步都验证结果

监控与验证

  1. 实时监控:在切换过程中,实时监控复制集状态
  2. 验证应用连接:切换后验证应用能否正常连接和操作
  3. 检查复制状态:确保新的主节点正常复制数据
  4. 查看日志:检查相关节点的日志,确认切换过程正常

文档化

  1. 记录切换过程:详细记录切换时间、步骤、结果和遇到的问题
  2. 更新文档:根据实际切换情况,更新相关文档和流程
  3. 分享经验:与团队分享切换经验,持续改进流程

常见问题与解决方案

问题1:执行 rs.stepDown() 命令失败

症状:执行 rs.stepDown() 命令后返回错误

可能原因

  • 没有足够的投票节点
  • 复制延迟过大
  • 权限不足
  • 节点状态异常

解决方案

javascript
// 检查复制集状态
rs.status()

// 检查投票节点数量
const members = rs.status().members.filter(m => m.votes > 0)
print(`投票节点数量:${members.length}`)

// 检查复制延迟
rs.printSecondaryReplicationInfo()

// 尝试使用 force 参数
rs.stepDown(30, {force: true})

问题2:切换后应用无法连接

症状:切换后应用无法连接到 MongoDB

可能原因

  • 应用连接字符串配置错误
  • 新的主节点防火墙未开放
  • 应用未正确处理主节点切换

解决方案

javascript
// 检查新的主节点
rs.status().members.forEach(member => {
  if (member.stateStr === 'PRIMARY') {
    print(`新的主节点:${member.name}`);
  }
});

// 检查节点的监听地址
db.adminCommand({getCmdLineOpts: 1}).parsed.net.bindIp

// 测试连接
mongo "mongodb://new-primary:27017"

问题3:切换后复制延迟增加

症状:切换后新的主节点复制延迟增加

可能原因

  • 新的主节点硬件性能不足
  • 新的主节点负载过高
  • 网络问题

解决方案

javascript
// 检查节点状态
rs.status()

// 检查系统资源使用情况
db.serverStatus().process

// 检查网络连接
ping new-primary

// 调整复制相关参数
db.adminCommand({setParameter: 1, replWriterThreadCount: 4})

手动故障切换的自动化

使用脚本自动化

可以编写脚本来自动化手动故障切换过程,提高效率和准确性。

javascript
// 自动故障切换脚本示例
function autoFailover() {
  // 检查复制集状态
  const status = rs.status();
  const primary = status.members.find(m => m.stateStr === 'PRIMARY');
  const secondaries = status.members.filter(m => m.stateStr === 'SECONDARY');
  
  // 选择最合适的从节点
  const targetSecondary = secondaries.sort((a, b) => {
    // 按复制延迟排序
    const delayA = a.replicationInfo?.syncSourceHost ? a.replicationInfo.secondsBehindMaster : 0;
    const delayB = b.replicationInfo?.syncSourceHost ? b.replicationInfo.secondsBehindMaster : 0;
    return delayA - delayB;
  })[0];
  
  if (!targetSecondary) {
    throw new Error('No suitable secondary found');
  }
  
  print(`准备将主节点从 ${primary.name} 切换到 ${targetSecondary.name}`);
  
  // 执行故障切换
  rs.stepDown(30, {secondaryCatchUpPeriodSecs: 10});
  
  // 验证结果
  const newStatus = rs.status();
  const newPrimary = newStatus.members.find(m => m.stateStr === 'PRIMARY');
  
  print(`故障切换完成,新的主节点:${newPrimary.name}`);
  
  return newPrimary;
}

使用第三方工具

可以使用 MongoDB Atlas、Ops Manager 或第三方工具来自动化故障切换过程。

  1. MongoDB Atlas:提供自动故障切换和手动故障切换功能
  2. MongoDB Ops Manager:支持自动和手动故障切换,以及监控和告警
  3. Kubernetes Operators:如 MongoDB Enterprise Kubernetes Operator,可以自动化故障切换

常见命令参考

检查复制集状态

javascript
// 基本状态
rs.status()

// 详细状态,包括复制延迟
rs.printSecondaryReplicationInfo()

// 打印主节点信息
rs.isMaster()

故障切换相关命令

javascript
// 使主节点降级
rs.stepDown(stepDownSecs, secondaryCatchUpPeriodSecs)

// 冻结节点,使其在指定时间内不参与选举
rs.freeze(seconds)

// 重新配置复制集
rs.reconfig(config, options)

// 强制重新配置(仅在紧急情况下使用)
rs.reconfig(config, {force: true})

监控命令

javascript
// 监控复制集状态
db.adminCommand({replSetGetStatus: 1})

// 查看 oplog 状态
db.getReplicationInfo()

// 查看节点的系统状态
db.serverStatus()

常见问题(FAQ)

Q1: 手动故障切换和自动故障切换有什么区别?

A1: 手动故障切换由管理员主动执行,可控性强,适用于计划性维护;自动故障切换由MongoDB自动执行,适用于突发故障场景。

Q2: 执行手动故障切换需要多长时间?

A2: 手动故障切换通常需要几秒钟到几十秒钟,具体取决于网络延迟、复制延迟和节点数量。

Q3: 手动故障切换会导致数据丢失吗?

A3: 正常情况下不会导致数据丢失,因为MongoDB会等待从节点追赶完成后再执行切换。但如果复制延迟过大,可能会导致数据丢失。

Q4: 可以在只有两个节点的复制集中执行手动故障切换吗?

A4: 不建议在只有两个节点的复制集中执行手动故障切换,因为可能会导致选举失败。建议使用至少三个节点的复制集。

Q5: 如何回滚手动故障切换?

A5: 如果手动故障切换出现问题,可以再次执行手动故障切换,将主节点切换回原来的节点。

Q6: 手动故障切换会影响读操作吗?

A6: 手动故障切换主要影响写操作,读操作可以继续在从节点上执行(如果应用配置了合适的读偏好)。

Q7: 如何监控手动故障切换的过程?

A7: 可以使用MongoDB的监控工具(如Atlas、Ops Manager)或第三方工具(如Prometheus+Grafana)来监控手动故障切换的过程。

Q8: 手动故障切换需要停止应用吗?

A8: 不需要停止应用,但应用可能会遇到短暂的写不可用。建议应用实现自动重连和重试机制。

Q9: 如何选择合适的目标节点?

A9: 应选择硬件性能好、复制延迟小、负载低、地理位置合适的节点作为目标节点。

Q10: 手动故障切换的最佳实践是什么?

A10: 手动故障切换的最佳实践包括:在业务低峰期执行、提前测试、制定回滚计划、实时监控、详细记录和持续改进。