MySQLNotes

第 26 章:高可用架构

zjc 于 2026-01-26 发布

这是《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

适合:

  1. 小规模系统;
  2. RPO 可容忍少量丢失;
  3. 故障时可人工切换;
  4. 备份和报表走从库。

一主两从半同步

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 故障检测

检测信号包括:

  1. MySQL 进程存活;
  2. 端口连通性;
  3. SELECT 1
  4. 只读状态;
  5. 复制状态;
  6. GTID 位点;
  7. 磁盘空间;
  8. 主从延迟;
  9. 延迟分布;
  10. 事务错误率。

仅检测端口存活不够。进程存在但磁盘满、只读、锁死或复制断裂时,服务已经不可用。

推荐健康检查:

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 步:必须先隔离旧主,再提升新主。

隔离方式:

  1. 修改防火墙;
  2. 交换机端口禁用;
  3. 云安全组;
  4. 分布式锁和运维平台;
  5. STONITH / 电源控制;
  6. MySQL Router 下线目标;
  7. 应用配置中心摘除。

26.5 候选节点选择

评估候选节点:

  1. GTID 集合是否最新;
  2. 复制延迟;
  3. 已接收未应用的 Relay Log;
  4. 机器规格;
  5. 剩余容量;
  6. 机房位置;
  7. 历史稳定性;
  8. 是否承载特殊流量。

查看 GTID:

SELECT @@GLOBAL.gtid_executed;

比较集合是否包含其他候选节点。数据旧的节点不能因为网络更容易访问而被优先提升。

26.6 路由层

常见方式:

方式 特点
MySQL Router 官方,适合 InnoDB Cluster
ProxySQL 规则丰富,读写分离强
HAProxy + Keepalived 简单稳定,需外部感知主从
服务发现 灵活,依赖平台能力
DNS 有缓存延迟,不适合快速切换
应用配置中心 可控,需发布或动态刷新

应用还必须处理:

  1. 连接池重建;
  2. 事务中断重试;
  3. 读写路由区分;
  4. 半开连接;
  5. 切换期间的熔断;
  6. 幂等写入。

高可用的最后一公里在应用代码里。

26.7 防止脑裂

脑裂:

旧主认为自己可写;
新主也被提升为可写;
两个主同时接收写入;

后果:

  1. 数据分叉;
  2. 主键冲突;
  3. 复制无法继续;
  4. 修复成本极高。

防护:

  1. 切换前强制隔离旧主;
  2. 候选节点必须只读等待提升;
  3. 依赖多数派仲裁;
  4. 应用路由和数据库状态双确认;
  5. 人工紧急切换也必须双人复核;
  6. 定期演练。

26.8 洪泛保护和过载保护

主库故障恢复后可能遇到:

  1. 积压连接;
  2. 缓存失效导致读洪峰;
  3. 从库追复制占用 IO;
  4. Buffer Pool 冷;
  5. 重试风暴。

策略:

  1. 连接池限流;
  2. 应用退避和抖动;
  3. 逐步放量;
  4. 关闭非核心任务;
  5. 先预热再放量;
  6. 对只读故障降级;
  7. 保护交易主链路。

26.9 备份与高可用

高可用副本不能替代备份:

场景 高可用是否有用
机器故障
网络故障
误删表 / 误更新 副本会快速重放错误
逻辑 bug 写坏数据 副本同样写坏
勒索加密 副本可能同样受影响
版本升级缺陷 可能全部受影响

必须有独立备份、离线或对象存储副本、保留窗口和恢复演练。

26.10 演练设计

至少每季度演练:

演练 目标
主库进程崩溃 自动检测和切换
网络分区 防脑裂和多数派行为
从库延迟 读写路由降级
磁盘满 预警和快速扩容
误删表 时间点恢复
机房级故障 异地接管
应用重试风暴 限流和熔断

演练必须记录:

  1. 检测时间;
  2. 决策时间;
  3. 切换时间;
  4. 恢复时间;
  5. 丢事务数量;
  6. 错误率变化;
  7. 人工介入点;
  8. 改进项和负责人。

26.11 故障切换 Runbook

事故名称:MySQL 主库不可用

1. 确认现象
   - 应用错误率、连接失败、慢查询
   - 主库进程、端口、健康检查

2. 通告
   - 值班群、业务负责人、事故频道

3. 初步决策
   - 只读故障:切读或降级
   - 不可写:准备切换
   - 网络抖动:观察短窗口

4. 切换前检查
   - 候选 GTID 最新
   - 延迟范围
   - 磁盘和容量
   - 只读状态

5. 隔离旧主
   - 路由摘除
   - 防火墙阻断写

6. 提升新主
   - 关闭 read_only
   - 修改路由
   - 应用验证

7. 恢复复制
   - 其他从库指向新主
   - 观察延迟

8. 事后
   - 检查数据
   - 分析根因
   - 补齐监控
   - 更新演练

本章小结

高可用设计先明确 RPO 和 RTO,再选择异步、半同步、组复制或分片架构。切换必须先隔离旧主,再提升数据最新的候选节点。路由层和应用重试是切换能否真正生效的关键。高可用不能替代备份,所有方案都要通过真实演练验证。

思考题

  1. RPO 和 RTO 分别决定什么架构选择?
  2. 为什么故障切换前必须隔离旧主?
  3. 如何判断候选从库的数据最新?
  4. 应用在主从切换时需要处理哪些问题?
  5. 写一份你们系统的数据库不可用 Runbook。