这是《MySQL 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 高可用不是安装一个工具,而是围绕故障检测、数据边界、流量切换、应用重试和演练建立的一整套能力。目标是让故障可预测、可控制、可恢复。
26.1 明确目标
上线前必须明确:
| 指标 | 问题 |
|---|---|
| RPO | 最多接受丢多少数据 |
| RTO | 最多接受多久不可写 |
| 可用性目标 | 99.9%、99.99% 分别对应多少停机时间 |
| 故障域 | 机架、机房、区域如何隔离 |
| 读写一致性 | 哪些读必须强一致 |
| 运维边界 | 自动切换还是人工确认 |
可用性时间参考:
| 目标 | 年停机预算 |
|---|---|
| 99.9% | 约 8 小时 46 分钟 |
| 99.99% | 约 52 分钟 |
| 99.999% | 约 5 分钟 |
目标越高,越要求自动检测、自动隔离和成熟演练,而不是更复杂的口头流程。
26.2 典型架构
一主一从
App -> Primary
| async replication
Replica
适合:
- 小规模系统;
- RPO 可容忍少量丢失;
- 故障时可人工切换;
- 备份和报表走从库。
一主两从半同步
App -> Primary
| semi-sync
Replica A(另一个故障域)
Replica B(延迟副本 / 备份)
适合核心在线业务,RPO 要求明显高于普通异步。
InnoDB Cluster
App -> MySQL Router
-> MGR Primary
-> MGR Replica x2
适合自动故障切换、读写端口分离和较少人工介入的场景。
分片高可用
App -> Shard Proxy
-> shard 1 HA group
-> shard 2 HA group
-> shard N HA group
适合写入超过单机容量、可以按业务键拆分的系统。
26.3 故障检测
检测信号包括:
- MySQL 进程存活;
- 端口连通性;
SELECT 1;- 只读状态;
- 复制状态;
- GTID 位点;
- 磁盘空间;
- 主从延迟;
- 延迟分布;
- 事务错误率。
仅检测端口存活不够。进程存在但磁盘满、只读、锁死或复制断裂时,服务已经不可用。
推荐健康检查:
SELECT 1;
SELECT @@read_only, @@super_read_only;
SHOW REPLICA STATUS;
26.4 故障切换流程
安全切换流程:
1. 检测原主异常;
2. 确认异常不是网络分区;
3. 阻断旧主写入,避免脑裂;
4. 选择数据最新的候选节点;
5. 等候选节点追平或达到 RPO 决策;
6. 提升候选节点为主;
7. 打开写流量;
8. 其他节点指向新主;
9. 恢复旧主并重新加入;
10. 校验数据和应用状态;
最关键的是第 3 步:必须先隔离旧主,再提升新主。
隔离方式:
- 修改防火墙;
- 交换机端口禁用;
- 云安全组;
- 分布式锁和运维平台;
- STONITH / 电源控制;
- MySQL Router 下线目标;
- 应用配置中心摘除。
26.5 候选节点选择
评估候选节点:
- GTID 集合是否最新;
- 复制延迟;
- 已接收未应用的 Relay Log;
- 机器规格;
- 剩余容量;
- 机房位置;
- 历史稳定性;
- 是否承载特殊流量。
查看 GTID:
SELECT @@GLOBAL.gtid_executed;
比较集合是否包含其他候选节点。数据旧的节点不能因为网络更容易访问而被优先提升。
26.6 路由层
常见方式:
| 方式 | 特点 |
|---|---|
| MySQL Router | 官方,适合 InnoDB Cluster |
| ProxySQL | 规则丰富,读写分离强 |
| HAProxy + Keepalived | 简单稳定,需外部感知主从 |
| 服务发现 | 灵活,依赖平台能力 |
| DNS | 有缓存延迟,不适合快速切换 |
| 应用配置中心 | 可控,需发布或动态刷新 |
应用还必须处理:
- 连接池重建;
- 事务中断重试;
- 读写路由区分;
- 半开连接;
- 切换期间的熔断;
- 幂等写入。
高可用的最后一公里在应用代码里。
26.7 防止脑裂
脑裂:
旧主认为自己可写;
新主也被提升为可写;
两个主同时接收写入;
后果:
- 数据分叉;
- 主键冲突;
- 复制无法继续;
- 修复成本极高。
防护:
- 切换前强制隔离旧主;
- 候选节点必须只读等待提升;
- 依赖多数派仲裁;
- 应用路由和数据库状态双确认;
- 人工紧急切换也必须双人复核;
- 定期演练。
26.8 洪泛保护和过载保护
主库故障恢复后可能遇到:
- 积压连接;
- 缓存失效导致读洪峰;
- 从库追复制占用 IO;
- Buffer Pool 冷;
- 重试风暴。
策略:
- 连接池限流;
- 应用退避和抖动;
- 逐步放量;
- 关闭非核心任务;
- 先预热再放量;
- 对只读故障降级;
- 保护交易主链路。
26.9 备份与高可用
高可用副本不能替代备份:
| 场景 | 高可用是否有用 |
|---|---|
| 机器故障 | 有 |
| 网络故障 | 有 |
| 误删表 / 误更新 | 副本会快速重放错误 |
| 逻辑 bug 写坏数据 | 副本同样写坏 |
| 勒索加密 | 副本可能同样受影响 |
| 版本升级缺陷 | 可能全部受影响 |
必须有独立备份、离线或对象存储副本、保留窗口和恢复演练。
26.10 演练设计
至少每季度演练:
| 演练 | 目标 |
|---|---|
| 主库进程崩溃 | 自动检测和切换 |
| 网络分区 | 防脑裂和多数派行为 |
| 从库延迟 | 读写路由降级 |
| 磁盘满 | 预警和快速扩容 |
| 误删表 | 时间点恢复 |
| 机房级故障 | 异地接管 |
| 应用重试风暴 | 限流和熔断 |
演练必须记录:
- 检测时间;
- 决策时间;
- 切换时间;
- 恢复时间;
- 丢事务数量;
- 错误率变化;
- 人工介入点;
- 改进项和负责人。
26.11 故障切换 Runbook
事故名称:MySQL 主库不可用
1. 确认现象
- 应用错误率、连接失败、慢查询
- 主库进程、端口、健康检查
2. 通告
- 值班群、业务负责人、事故频道
3. 初步决策
- 只读故障:切读或降级
- 不可写:准备切换
- 网络抖动:观察短窗口
4. 切换前检查
- 候选 GTID 最新
- 延迟范围
- 磁盘和容量
- 只读状态
5. 隔离旧主
- 路由摘除
- 防火墙阻断写
6. 提升新主
- 关闭 read_only
- 修改路由
- 应用验证
7. 恢复复制
- 其他从库指向新主
- 观察延迟
8. 事后
- 检查数据
- 分析根因
- 补齐监控
- 更新演练
本章小结
高可用设计先明确 RPO 和 RTO,再选择异步、半同步、组复制或分片架构。切换必须先隔离旧主,再提升数据最新的候选节点。路由层和应用重试是切换能否真正生效的关键。高可用不能替代备份,所有方案都要通过真实演练验证。
思考题
- RPO 和 RTO 分别决定什么架构选择?
- 为什么故障切换前必须隔离旧主?
- 如何判断候选从库的数据最新?
- 应用在主从切换时需要处理哪些问题?
- 写一份你们系统的数据库不可用 Runbook。