Skip to content

高可用方案

高可用要解决的问题是:主库挂了之后,服务多快能恢复、数据会不会丢。它和备份、复制经常放在一起讨论,但三者解决的是不同层面的问题——备份管"过去的数据还在不在",复制管"数据能不能传到其他实例",高可用管"故障发生时服务能不能继续对外提供访问"。

一、单机 MySQL 的风险

风险影响单机能解决吗
主机宕机所有读写请求失败不能,需要冗余实例
磁盘故障数据不可访问或丢失不能,靠备份恢复
MySQL 进程崩溃连接全部断开通常能自动重启,但有中断
网络隔离应用访问不到数据库不能,需要多实例和切换入口
误操作数据被删改不能,靠备份 + binlog 恢复

高可用主要解决的是服务可用性的问题——让故障发生后尽快恢复访问。但对于误删数据、错误更新、业务逻辑 bug 导致的数据错误,高可用不能自动修复,仍然要靠备份恢复和 binlog 回放。

二、常见方案怎么排

方案组件适合什么环境
主从 + 手工切换MySQL 原生复制 + 人工操作小规模、可接受分钟到小时级恢复时间
MHA传统主从自动切换存量大规模主从环境,需要自动化切换
Orchestrator拓扑管理和故障切换复杂复制拓扑,需要可视化和管理能力
InnoDB ClusterGroup Replication + MySQL Shell + Router新环境,需要官方集群方案
云厂商高可用云厂商托管运维负担小,但要了解云厂商高可用的具体实现细节
中间件读写分离ProxySQL、MyCat 等读写分离 + 连接入口管理

选方案不只是看"能自动切换"——切换之后,应用怎么找到新主、旧主怎么处理、数据有没有丢失、回切怎么做,这些问题要全部搞清楚才算能用。

三、主从手工切换的基本流程

最基础的切换步骤:

text
1. 确认主库不可用或需要主动下线
2. 在所有从库里选延迟最小、数据最全的那台
3. 停止这个从库的复制,确认不再从旧主接收变更
4. 关闭只读,宣布新主
5. 修改应用连接入口(VIP/DNS/配置中心)
6. 其他从库改挂新主
7. 旧主恢复后以从库身份加入

核心 SQL 操作:

sql
-- 在要提升的从库上执行
STOP REPLICA;
RESET REPLICA ALL;
SET GLOBAL read_only = OFF;
SET GLOBAL super_read_only = OFF;
sql
-- 在其他从库上执行,改挂新主
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST='10.0.0.20',      -- 新主库 IP
  SOURCE_PORT=3306,
  SOURCE_USER='repl',
  SOURCE_PASSWORD='ReplPassword_123!',
  SOURCE_AUTO_POSITION=1;

START REPLICA;

手工切换在小规模环境可行,但要有清晰的 SOP。故障中临时想步骤,容易把旧主、新主、各个从库的状态搞乱。至少把"选主标准"和"提升新主的命令序列"提前写好。

四、切换前后必须确认的三件事

主从切换不是"把新主提起来"就算完成:

确认事项具体检查为什么不能漏
新主是不是最新GTID 已执行集合、主从延迟、和其他从库对比提了一个数据落后的从库,切换后数据永久不一致
旧主不会继续写网络隔离、只读状态、VIP/入口是否已移走双主写入是恢复起来最麻烦的一类问题
应用真的恢复了写接口、读接口、连接池重建、错误率数据库能连不等于业务能正常运转

新主确认:

sql
SELECT @@read_only, @@super_read_only;   -- 必须是 OFF,否则写不进去
SHOW MASTER STATUS;                      -- 确认 binlog 状态正常

主从延迟没有收敛时强行提升,主库上最近的提交可能还没到新主——这就是数据缺口。判断能不能切的依据是 Seconds_Behind_Source 和 GTID 集合差异,而不是"看起来差不多了"。

五、读写分离——延迟是核心问题

text
写请求 → 主库
读请求 → 从库

读写分离提高了读的扩展能力,但引入了一个根本问题:复制延迟。刚写到主库的数据,去从库马上读,可能还没同步过来。

处理延迟的几种方式:

做法说明代价
关键路径读主写完后立刻要读到最新结果的请求发给主库主库读压力增加
延迟过大摘除从库落后太多的从库从读的列表里移除剩余从库分摊更多读
会话粘滞同一会话的写和读走同一实例需要中间件或应用支持
业务容忍允许读到几秒前的旧数据看业务能不能接受

读写分离不是加越多从库越好。从库增多 → 复制链路增多 → 延迟监控、故障摘除都更复杂。每加一个从库都要确认:它能不能扛住分配的读流量,延迟够不够低。

六、半同步复制——降低丢数据的概率

异步复制不等待从库确认,主库宕机时最后一部分事务可能丢失。半同步复制要求至少一个从库确认收到日志后,主库才返回提交成功:

sql
INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so';
INSTALL PLUGIN rpl_semi_sync_replica SONAME 'semisync_replica.so';

SET GLOBAL rpl_semi_sync_source_enabled = ON;
SET GLOBAL rpl_semi_sync_replica_enabled = ON;

半同步提升了数据安全性——已提交事务至少已经到了一个从库的 relay log 里。但代价是:如果从库或网络异常,主库提交被卡住,可能会退化成异步(依赖超时参数设置)。它保证的是"至少一个从库收到了日志",不等于"从库已经完成 SQL 回放"——所以延迟仍然要监控。

七、应用连接入口

切换新主后,应用怎么找到新地址:

入口方式优点注意事项
VIP 漂移对应用透明,切换也快依赖网络环境支持 VIP
DNS 切解析简单、通用TTL 和连接池缓存可能导致切过去后旧地址还连着
代理层路由可以做健康检查、读写分离和连接池代理自身也需要高可用,否则是单点
配置中心动态刷新控制灵活应用要支持动态刷新连接配置

DNS 切换不只是改解析记录。很多数据库连接池创建后不会主动重新解析 DNS——它们会一直连着旧 IP 直到连接被断开或超时重建。所以 DNS 切换后还要观察连接数分布,确认流量真的切走了。

八、数据一致性检查

主从延迟不等同于数据不一致——延迟只是"回放还没到那个位点"。真正的数据不一致是指:同样的行在主从上有不同的值。可能因为:跳过过某个复制事务、直接写了从库、复制错误被忽略。

用工具检查:

bash
pt-table-checksum \
  --host=10.0.0.10 \
  --user=checksum \
  --password='ChecksumPassword_123!' \
  --replicate=percona.checksums

它在主库上把每张表分成小块,对每块算校验和,写入 percona.checksums 表并复制到从库。从库上再对同样的块算校验和,和主库对比。发现差异后用 pt-table-sync 修复。但同步修复语句生成后需人工审查,确认不会覆盖合法的新数据。

一致性检查会消耗 CPU 和 IO,大库要放在低峰运行。

九、演练——没演练过的高可用不能信任

"故障时会自动切换"如果没有经过实际验证,就不算可依赖的高可用。

演练内容:

演练场景观察什么
kill 主库 MySQL 进程是否正确检测到故障,是否完成切换,耗时多久
断开主库网络是否误判、是否出现脑裂(旧主仍以为自己是主)
从库延迟很大是否跳过落后节点、是否阻止切换
旧主恢复是否自动重新加入、是否需要人工处理
应用连接切换是否自动重连、错误率和延迟变化

演练记录不但要保留,还要有具体数字:

text
演练时间:
故障注入方式:
检测耗时:从故障发生到系统检测到的用时
切换耗时:从检测到开始切换到新主可写的用时
应用恢复时间:从切换完成到应用恢复正常处理请求的用时
是否丢数据:
人工介入点:
遗留问题:

十、RTO 和 RPO——两个数字定方案

高可用方案最终落到两个指标:

指标含义决定什么
RTO从故障到服务恢复需要多久自动化程度、切换入口设计、演练频率
RPO最多能接受丢多少数据复制方式(异步/半同步)、binlog 刷盘策略

业务能接受的 RTO 和 RPO 直接决定了架构取舍。如果 RPO=0(不能丢任何已提交事务),异步复制就不够,要用半同步甚至强一致方案。如果 RTO=30 秒,手工切换基本不可能,必须上自动切换。如果 RTO=4 小时,人工操作空间就大很多。

不是所有系统都需要最严格的 RTO/RPO——按业务实际需求分级,核心交易系统用强一致方案,报表和分析库可以接受异步复制和较长恢复时间。把每个库的 RTO/RPO 明确下来,高可用方案就不会变成"尽量别挂"这种模糊的目标。