MySQL高可用架构选型:从故障切换耗时到数据一致性,三种方案实测对比

举报
数据库小学妹 发表于 2026/07/08 10:26:07 2026/07/08
【摘要】 花两周在测试环境跑通MHA、MGR、InnoDB Cluster三种高可用方案,对比故障切换耗时、数据一致性、部署运维复杂度,附完整配置命令、五个真实踩坑案例和选型决策框架

大家好,我是数据库小学妹 👋

上个月凌晨主库挂了,没有自动切换。我手动切了十五分钟,丢了好几万订单。

那天之后,我花两周把MHA、MGR、InnoDB Cluster都搭了一遍。今天把完整对比写出来。

先放一张三种方案的架构对比,帮你建立全局认知:

MHA架构                  MGR单主架构              InnoDB Cluster架构
┌──────────┐            ┌──────────┐            ┌──────────┐
│ Manager  (监控)      │  Node A  ()        │  Router  (代理)
└────┬─────┘            │  Paxos   │            └────┬─────┘
     │监控              └──┬───┬───┘                 │路由
┌────┴─────┐           ┌───┴┐ ┌┴───┐           ┌────┴─────┐
│ Master   ()       │Node│ │Node│           │  Shell   (管理)
└────┬─────┘           │ B  │ │ C  │           └────┬─────┘
     │复制             └────┘ └────┘                │
┌────┴─────┐           三节点Paxos共识           ┌───┴────┐
│ Slave×2  ()MGR单主  (复制)
└──────────┘                                    └───┬────┘
Manager单点决策         共识协议决策                 │
VIP漂移切换             毫秒级选主              自动路由切换

故障切换的核心指标:RTO和RPO

先搞清楚两个数。

RTO,故障切换耗时。主库挂了多久业务能恢复。电商超过30秒就是事故,内部管理系统停几分钟问题不大。

RPO,数据丢失量。切换过程中丢了多少数据。RPO为零意味着一条都不能丢。

不同业务对这两个指标的要求差别很大。选方案之前,先跟业务方确认能接受多大的损失。

MHA:最成熟的"老将"

架构原理

MHA(Master High Availability)的思路很直接。一个Manager进程监控主库,发现主库挂了,就从从库里挑一个数据最新的提升为新主。然后把其他从库都切过去。

关键步骤是补日志。主库宕机时,从库之间可能数据不一致。MHA会对比所有从库的relay log,找出差异。然后把缺失的event补到新主上,尽量少丢数据。

但MHA不是基于共识协议,靠的是Manager单点决策。Manager挂了集群还能跑,但没法自动切换。选型的时候这个短板要认真考虑。

部署配置

MHA要装两部分:Manager节点和所有MySQL节点上的Node。

# Manager配置 /etc/mha/app1.cnf
[server default]
manager_workdir=/var/log/mha/app1
manager_log=/var/log/mha/app1/manager.log
user=mha
password=mha_pass
ssh_user=root
repl_user=repl
repl_password=repl_pass
ping_interval=3
master_ip_failover_script=/usr/local/bin/master_ip_failover
master_ip_online_change_script=/usr/local/bin/master_ip_online_change

[server1]
hostname=192.168.1.101
port=3306

[server2]
hostname=192.168.1.102
port=3306
candidate_master=1

[server3]
hostname=192.168.1.103
port=3306
no_master=1

candidate_master=1表示这个从库优先被选为新主。no_master=1表示永远不选它当主库,通常用来标记备库或者资源差的节点。

部署完要跑检查:

# 检查SSH连通性
masterha_check_ssh --conf=/etc/mha/app1.cnf

# 检查复制状态
masterha_check_repl --conf=/etc/mha/app1.cnf

我第一次部署,SSH检查就报错了。原因是三台机器的ssh免密配的用户不一致,Manager用root连,但Node上配的是mha用户。改了半天才统一。

故障切换实测

MHA的故障切换分三步:检测主库不可用→选新主→VIP漂移。

检测靠的是ping_interval配置的间隔去尝试连接主库,默认3秒连不上就再试。连续失败次数够了才判定宕机。这个阈值可以调,但调太小容易误判,调太大切换就慢。

我测出来的平均切换时间是12秒左右,最慢一次18秒。慢的那次是因为从库relay log差了几百个event,补日志花了额外时间。

踩坑:SSH误判

这是我在MHA上遇到的最头疼的问题。

测试环境有一次,主库运行得好好的,Manager却判定它挂了,触发了一次切换。业务被迫中断了几秒。

排查发现,是测试环境的网络有抖动。Manager的SSH连接超时了,连续几次ping失败,就误判为宕机。

解决办法是改检测策略。把ping_interval调到5秒,同时加上TCP端口检测做双重验证。SSH检测作为辅助,不再作为唯一的判断依据。

# 加上secondary_check_script做双重验证
secondary_check_script=/usr/local/bin/masterha_secondary_check \
  --port=3306 --user=mha --password=mha_pass

这个脚本会从另一个网络路径去检测主库,两边都失败才判定宕机。

MGR:基于Paxos的"新锐"

为什么Paxos能保证零丢失

MGR(MySQL Group Replication)是5.7.17引入的。底层用的Paxos协议。

传统主从复制是"发了就不管"。主库写完binlog就返回成功。MGR不一样,事务提交前要过半数节点确认。主库才给客户端返回成功。

假设三个节点A、B、C,A是主:

  1. A执行事务,写本地binlog
  2. A把binlog event发给B和C
  3. B和C收到后返回确认
  4. A收到至少一个确认(加上自己是两个,过半),提交事务

如果A这时候挂了,B和C中至少有一个有完整数据。所以能做到零丢失。

不过代价也明显。每次写入多了一轮网络往返。写入延迟从异步复制的0.5ms涨到了2-5ms。并发量一上去,延迟会叠加。

部署配置

MGR的配置比MHA复杂得多,每个节点都要配,而且引导节点和普通节点的配置有区别。

# 所有节点公共配置 my.cnf
[mysqld]
server_id=1                      # 每个节点不同
gtid_mode=ON
enforce_gtid_consistency=ON
binlog_checksum=NONE
log_bin=binlog
binlog_format=ROW
log_slave_updates=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
transaction_write_set_extraction=XXHASH64

# MGR核心参数
plugin_load_add='group_replication.so'
group_replication_group_name="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
group_replication_start_on_boot=OFF
group_replication_local_address="192.168.1.101:33061"
group_replication_group_seeds="192.168.1.101:33061,192.168.1.102:33061,192.168.1.103:33061"
group_replication_single_primary_mode=ON

注意group_replication_group_name要所有节点一样,是集群的唯一标识。group_replication_local_address是节点间通信的地址,要和MySQL端口分开,用另一个端口。

引导第一个节点和加入节点的SQL不一样:

-- 第一个节点(引导节点)
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;

-- 其他节点(加入节点)
START GROUP_REPLICATION;

我第一次部署,引导节点忘关group_replication_bootstrap_group了。后面每次重启这个节点都会创建新组,其他节点全掉线。排查了半天才反应过来。

流控:最容易被忽略的机制

MGR有个流控(Flow Control)机制。很多团队上生产之后才发现还有这个东西。

当从节点回放速度跟不上主节点写入速度时,MGR会主动减慢主节点。让从节点追上来。

监控里能看到这个参数:

SHOW STATUS LIKE 'group_replication_flow_control%';

这个参数控制的是认证队列的长度阈值。默认25000,超过就触发流控。

我在压测时遇到过这个问题。QPS到8000左右,流控突然触发,主库响应时间从2ms飙到200ms。排查时看到监控里certifier队列爆了,才意识到是流控在限速。

解决办法有两个:调大阈值,或者优化从节点的回放能力(比如开并行复制)。如果业务允许,也可以关闭流控,但那样从节点会严重落后。

-- 调大流控阈值(根据业务量调整)
SET GLOBAL group_replication_flow_control_certifier_threshold=50000;

生产环境建议先测清楚触发流控的QPS是多少,提前做好规划。

多主模式:看起来很美

MGR支持多主模式,所有节点都能写入。但我不推荐轻易用。

多主模式下,两个节点同时修改同一行会冲突。MGR会回滚其中一个。但应用层感知不到冲突,以为操作成功了。

我测试的时候模拟过这个场景。两个连接同时更新同一条记录,一个成功一个报错。如果应用没处理这个错误,数据就丢了。

除非你的业务天然适合多写,要不还是老实选单主。

InnoDB Cluster:官方的"全家桶"

三件套怎么配合

InnoDB Cluster是MySQL官方的高可用方案,由三个组件组成:

Group Replication负责数据复制和一致性。就是上面讲的MGR,这里用的是单主模式。

MySQL Shell是管理工具。集群的创建、成员管理、状态检查都通过Shell完成。

MySQL Router是透明代理。应用连Router不连MySQL。主库切换时,Router自动把请求路由到新主。应用端完全不用改代码。

这三个组件分工很清楚。Shell管运维,MGR管复制,Router管流量。主库挂了,MGR选新主,Router感知后自动切路由。应用根本不知道主库换过。

部署体验

InnoDB Cluster的部署比纯MGR省事多了。

// MySQL Shell中创建集群
dba.configureInstance('root@192.168.1.101:3306')
var cluster = dba.createCluster('myCluster')

// 添加其他节点
cluster.addInstance('root@192.168.1.102:3306')
cluster.addInstance('root@192.168.1.103:3306')

// 查看集群状态
cluster.status()

Shell帮你处理了MGR那堆繁琐的配置。不需要手动写my.cnf,不需要手动引导节点,两行命令搞定。

Router的配置也是自动生成的:

# 启动Router,自动读取集群元数据
mysqlrouter --bootstrap root@192.168.1.101:3306 --directory /etc/mysqlrouter
systemctl start mysqlrouter

Router启动后会在6446端口监听读写请求,6447端口监听只读请求。应用连6446就行,主库怎么切都不用改连接。

我第一次部署InnoDB Cluster,从零到三节点集群跑起来,一个半小时。MGR纯手工部署花了三个小时。

Router的心跳机制

Router通过定期查询集群元数据,来感知主库变化。默认心跳间隔是1秒。主库切换后,Router最多1秒就能切换路由。

但切换不是完全无损的。正在执行的请求会失败,应用层要自己做重试。

# Spring Boot配置示例
spring.datasource.hikari.connection-timeout: 3000
spring.datasource.hikari.maximum-pool-size: 20

我测过,主库切换期间,HikariCP默认重试3次,每次间隔1秒。配合Router的1秒感知,业务恢复总耗时大概5-6秒。

故障切换与运维:三种方案全面对比

故障切换耗时

我在三节点环境下模拟主库宕机,每种方案测了十次取平均值:

方案 平均RTO 最长RTO RPO
MHA 12秒 18秒 最多丢1-2秒
MGR单主 5秒 8秒 零丢失
InnoDB Cluster 6秒 9秒 零丢失

MHA慢在三个步骤串行执行。MGR和InnoDB Cluster快是因为基于共识协议,选主是毫秒级的。

MHA的数据丢失量取决于从库的复制延迟。从库越落后丢得越多。MGR和InnoDB Cluster因为多数派提交,不存在这个问题。

部署与运维

维度 MHA MGR InnoDB Cluster
部署耗时 约2小时 约3小时 约1.5小时
配置项 约20个 约35个 约15个
运维工具 命令行 SQL命令 MySQL Shell
自动切换 需要VIP脚本 内置 Router自动路由
Manager单点
MySQL版本 5.5及以上 5.7.17及以上 8.0及以上(推荐)

MHA最大的问题是Manager单点。Manager挂了,集群还能跑,但没法自动切换。要么加个Keepalived做Manager高可用,要么接受这个风险。

MGR的运维工具就是SQL命令,没有专门的管理平台。状态检查要手动敲performance_schema里的表。不够直观。

InnoDB Shell的cluster.status()输出很清晰,一眼能看到每个节点的状态、延迟、角色。

选型决策框架

光看技术指标没用,得结合自己的业务场景和团队能力来选。

场景一:MySQL 8.0以上,中小团队

直接上InnoDB Cluster。部署简单,官方维护,Router对应用透明。

这是我现在推荐最多的方案。省心,出了问题社区资源也多。

场景二:还在5.7,短期升不了

用MHA。MGR虽然5.7就有了,但早期版本bug多,生产环境别冒险。5.7上MGR的流控、认证机制都有过hotfix。

场景三:数据一致性要求极高

MGR单主模式。Paxos协议保证零丢失,适合金融、支付场景。

但要注意写入延迟。如果业务对延迟敏感(比如要求写入p99<5ms),要先压测确认MGR的延迟在可接受范围。

场景四:不想折腾

云数据库的高可用版本。RDS自带主从切换,不需要自己操心架构。省下来的时间精力比方案本身值钱。

场景五:需要多写能力

MGR多主模式。但说实话,多主的冲突处理很复杂。我见过不少团队上了多主又退回单主的。除非业务天然适合多写,否则慎选。

避坑清单

MHA的SSH检测是单点依赖。 网络一抖就可能误判主库宕机。我在测试环境遇到过,主库好好的却触发了切换。后来加上TCP端口检测做双重验证才解决。网络环境不够稳定的话,一定要加secondary check。

MGR上生产之前,建议先压测摸清楚流控触发的QPS。我在压测时QPS到8000,流控就启动了,响应时间从2ms飙到200ms。调整那个流控阈值参数,同时开启从节点并行复制,基本能缓解。

InnoDB Cluster的Router不是完全无损切换。 切换期间正在执行的请求会失败。应用必须做好重试,否则用户会看到报错。建议连接池配好重试策略。

还有一点容易忽略。group_replication_bootstrap_group只在第一次引导时开启,之后必须关掉。忘了关的话,每次重启都会创建新组,其他节点全掉线。建议写进运维手册,或者用InnoDB Shell自动管理。

不管哪种方案,从库必须开super_read_only。我见过不止一次,开发误连从库写数据。排查了好久才发现,这个要写进标准搭建流程里。


回到开头的问题。三种方案各有所长:MHA胜在成熟和兼容老版本,MGR胜在数据零丢失,InnoDB Cluster胜在易用和生态。但没有哪个方案能解决所有问题,选型的关键是匹配你的业务和团队。

你们生产环境用的哪种高可用方案?踩过什么坑?评论区聊聊。

我是数据库小学妹,咱们下篇见 👋

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。