外观
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秒时执行切换。
选择目标节点
选择合适的目标节点作为新的主节点,应考虑以下因素:
- 硬件性能:目标节点的硬件性能应与当前主节点相当或更好
- 复制延迟:复制延迟应尽可能小
- 地理位置:如果是跨数据中心部署,应选择距离应用更近的节点
- 节点角色:应选择具有投票权的SECONDARY节点
- 磁盘空间:确保目标节点有足够的磁盘空间
- 负载情况:选择负载较低的节点
通知相关团队
在执行手动故障切换前,应通知相关团队:
- 应用开发团队
- 运维团队
- 业务团队
- 监控团队
确保相关团队了解切换时间、影响范围和应急措施。
手动故障切换的执行步骤
方法一:使用 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. 恢复原始配置
切换完成后,记得恢复原始配置。
手动故障切换的注意事项
数据一致性
- 确保复制延迟较小:在执行切换前,确保所有从节点的复制延迟较小
- 等待 oplog 追赶:使用
secondaryCatchUpPeriodSecs参数等待从节点追赶 - 验证数据完整性:切换后验证关键数据的完整性
应用影响
- 短暂的写不可用:手动故障切换期间,写操作会有短暂的不可用
- 连接池管理:应用应正确处理主节点切换,包括重新连接和重试机制
- 读偏好设置:如果应用使用了特定的读偏好,应确保其在切换后仍然有效
监控与告警
- 开启监控:在切换过程中,密切监控复制集状态
- 准备告警规则:确保相关告警规则已配置,能够及时发现问题
- 记录切换过程:详细记录切换时间、步骤和结果
权限要求
执行手动故障切换需要具有 clusterManager 或 clusterAdmin 角色的用户权限。
javascript
// 创建具有 clusterManager 角色的用户
use admin
db.createUser({
user: "admin",
pwd: "password",
roles: ["clusterManager"]
})手动故障切换的最佳实践
计划性切换
- 选择合适的时间窗口:在业务低峰期执行切换
- 提前测试:在测试环境中演练切换流程
- 制定回滚计划:准备好切换失败时的回滚方案
- 逐步执行:分步骤执行,每一步都验证结果
监控与验证
- 实时监控:在切换过程中,实时监控复制集状态
- 验证应用连接:切换后验证应用能否正常连接和操作
- 检查复制状态:确保新的主节点正常复制数据
- 查看日志:检查相关节点的日志,确认切换过程正常
文档化
- 记录切换过程:详细记录切换时间、步骤、结果和遇到的问题
- 更新文档:根据实际切换情况,更新相关文档和流程
- 分享经验:与团队分享切换经验,持续改进流程
常见问题与解决方案
问题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 或第三方工具来自动化故障切换过程。
- MongoDB Atlas:提供自动故障切换和手动故障切换功能
- MongoDB Ops Manager:支持自动和手动故障切换,以及监控和告警
- 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: 手动故障切换的最佳实践包括:在业务低峰期执行、提前测试、制定回滚计划、实时监控、详细记录和持续改进。
