数据库高可用并不是让MySQL永远不宕机,而是在故障发生时尽可能缩短不可用时间,并避免数据丢失。一个完整的MySQL高可用架构通常包含三个层面:数据复制层负责把写入操作同步到多个节点;故障检测层负责判断主库是否还活着;切换层负责在必要时把从库提升为新主库,并让应用流量快速指向新节点。如果只配置了主从复制而没有自动切换,仍然需要人工介入,高可用目标就无法达成。

理解这一点之后,选择方案时会更有针对性。例如,异步复制虽然对主库性能影响小,但主库崩溃时可能会丢失已经提交但尚未同步的事务;半同步复制可以降低丢失概率,却会增加写入延迟;组复制则通过多数派共识机制在一致性和可用性之间取得平衡。下面先从主从复制的配置入手,再逐步扩展到自动切换方案。
一、先搭建可靠的主从复制基础
主从复制是高可用架构中最常见的起点。主库把每个写操作记录到binary log,从库通过I/O线程拉取这些日志并写入relay log,再由SQL线程重放,从而实现数据同步。为了让后续故障切换更安全,建议开启GTID模式。GTID给每个事务分配全局唯一标识,从库在切换主库时可以自动定位需要继续同步的位置,减少手动指定binlog文件名和偏移量带来的出错概率。
在配置主库时,需要保证server-id在集群内唯一,并启用行级复制格式。行级复制比语句级复制更能避免某些函数或触发器在主从环境产生不一致。主库的配置片段如下:
[mysqld] server-id=1 log-bin=mysql-bin binlog_format=ROW gtid_mode=ON enforce_gtid_consistency=ON log_slave_updates=ON
从库同样需要开启GTID和binlog,因为从库在将来可能被提升为主库,提前写好binlog可以避免切换时重新配置。从库最好设置只读,防止误写入导致主从数据不一致。
[mysqld] server-id=2 relay-log=mysql-relay-bin log-bin=mysql-bin binlog_format=ROW gtid_mode=ON enforce_gtid_consistency=ON read_only=ON
主库上需要创建一个专用的复制账号,授权范围应精确到从库所在网段,不要使用root账号。复制账号只需要REPLICATION SLAVE权限即可。
CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY 'Repl@123456'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%'; FLUSH PRIVILEGES;
在从库执行CHANGE MASTER语句时,使用MASTER_AUTO_POSITION=1可以让GTID自动协调复制位置,不再需要手动记录主库当前的binlog文件和偏移量。随后启动复制并检查状态。
CHANGE MASTER TO MASTER_HOST='192.168.1.101', MASTER_USER='repl', MASTER_PASSWORD='Repl@123456', MASTER_PORT=3306, MASTER_AUTO_POSITION=1; START SLAVE;
可以通过SHOW SLAVE STATUS\G查看复制是否正常,重点关注Slave_IO_Running和Slave_SQL_Running是否都为Yes。如果使用了GTID,还可以检查Retrieved_Gtid_Set和Executed_Gtid_Set是否在持续增长。主从复制本身只能保证数据被同步到从库,并不能在主库故障时自动切换,因此接下来需要叠加故障检测和切换能力。
二、用Keepalived实现轻量级自动切换
对于规模不大、希望快速落地的环境,主从复制配合Keepalived是一种常见选择。Keepalived通过VRRP协议在多台服务器之间维护一个虚拟IP,应用连接这个虚拟IP,正常时虚拟IP绑定在主库,主库宕机后自动漂移到从库。这个过程通常只需要几秒,应用不需要修改连接地址。
不过Keepalived本身并不感知MySQL的复制状态。如果只监测服务器是否存活,可能出现主库进程卡死但机器还活着的情况,此时虚拟IP不会切换。因此需要自定义检测脚本,在发现MySQL不可用时主动停止Keepalived,触发VIP漂移。同时要注意脑裂问题:当两台机器之间网络抖动但彼此都认为对方故障时,可能同时持有虚拟IP,导致数据写入冲突。生产环境建议把Keepalived的检测脚本与MySQL状态强绑定,并配合防火墙隔离或STONITH类机制降低脑裂风险。
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.200/24
}
track_script {
chk_mysql
}
}
上面的配置中,track_script引用了一个检测MySQL进程的脚本。脚本可以简单判断本机MySQL是否存活,如果连接失败则返回非0值,Keepalived会降低本机优先级或停止实例,从而让出虚拟IP。需要特别指出,主从复制加Keepalived的方案存在数据一致性隐患:如果主库刚提交事务但从库尚未同步完成,主库突然宕机,切换后的新主库会缺少这部分事务。异步复制几乎必然存在这种窗口,半同步复制可以缩小窗口,但无法彻底消除。
更关键的是,从库被提升为新主库后,原主库恢复上线时不能直接加入集群,否则可能和当前主库发生数据冲突。此时需要人工判断原主库落后了多少事务,决定是重建从库还是通过工具补齐数据。可见Keepalived方案虽然部署简单,但自动切换后的数据校验和回退方案仍然需要运维团队提前设计。
三、使用MySQL InnoDB Cluster替代传统手工切换
MySQL InnoDB Cluster是官方提供的高可用方案,底层使用组复制协议。与普通主从复制不同,组复制基于Paxos变种协议,事务提交前需要在多数派节点上达成一致,因此可以避免主库故障时已经提交的事务丢失。在单主模式下,集群自动选举一个主节点提供读写,其余节点作为从节点。当主节点故障时,剩下的节点会重新投票选出新主节点,应用通过MySQL Router连接集群,由Router感知拓扑变化并转发请求。
组复制对网络延迟和稳定性要求较高。如果节点之间网络抖动频繁,可能导致成员被驱逐甚至整个集群不可用。在生产环境使用InnoDB Cluster时,建议至少部署三个节点,并让它们分布在不同的物理机或可用区。两个节点的组复制在发生脑裂时无法形成多数派,反而更容易出现不可用,不适合作为高可用方案。
使用MySQL Shell可以快速初始化集群。首先在每台实例上执行配置检查,确保server_id、GTID和复制参数符合要求:
mysqlsh -- dba configure-instance root@mysql1:3306 mysqlsh -- dba configure-instance root@mysql2:3306 mysqlsh -- dba configure-instance root@mysql3:3306
然后登录任意一个实例,创建集群并加入其他节点:
var cluster = dba.createCluster('prodCluster');
cluster.addInstance('root@mysql2:3306');
cluster.addInstance('root@mysql3:3306');
cluster.status();
创建成功后,cluster.status()会显示当前主节点和从节点的状态。应用端需要连接MySQL Router,而不是直连某一个MySQL实例。Router启动后提供两个端口:读写端口把所有写操作转发到当前主节点,只读端口在从节点之间做负载均衡。这样主库切换后,Router会自动更新路由表,应用基本无感知。
InnoDB Cluster的另一个优势是内置了恢复机制。被驱逐的节点重新加入集群时,组复制会自动识别它缺少哪些事务,并从其他节点获取缺失的GTID进行补齐。相比传统主从复制的手工重建,这个流程要安全得多。但需要注意的是,组复制不是万能方案,如果多数派节点同时故障,集群仍然不可用,此时需要结合备份和跨机房架构来提升整体可用性。
四、方案对比与生产落地建议
不同高可用方案在切换时间、数据丢失风险和维护成本上差异明显。主从加Keepalived适合对RPO要求不高的内部系统,部署简单但切换后可能出现数据丢失或脑裂。MHA是较早流行的MySQL高可用工具,可以自动补齐日志并切换主库,但维护已经不如官方方案活跃。Orchestrator配合VIP或ProxySQL可以管理复杂拓扑,适合需要细粒度拓扑管理和自动恢复的大型环境。InnoDB Cluster则更偏向一体化方案,牺牲一定性能换取更强一致性保证。
| 方案 | 切换耗时 | 数据丢失风险 | 维护复杂度 |
|---|---|---|---|
| 主从+Keepalived | 秒级 | 异步复制可能丢少量事务 | 低但需处理脑裂 |
| MHA | 通常30秒内 | 依赖半同步可降低 | 中等 |
| Orchestrator | 秒级到分钟级 | 依赖复制模式 | 高但灵活 |
| InnoDB Cluster | 秒级 | 多数派提交,丢失概率低 | 中等 |
落地之前需要明确两个关键指标:RPO和RTO。RPO表示故障后允许丢失多少数据,如果业务不能接受任何已提交事务丢失,就应当优先考虑组复制或半同步复制加合理切换策略。RTO表示故障后多久恢复服务,如果必须在几秒内恢复,自动切换机制和动态路由缺一不可。很多团队只做了主从复制就认为完成了高可用,实际上没有故障检测和自动切换,RTO可能长达几十分钟。
另一个常见误区是把高可用等同于备份。备份解决的是误删除、数据损坏等逻辑故障,高可用解决的是节点故障导致的停机问题,二者必须同时存在。即使集群中有三个实时复制节点,如果业务误执行了删库操作,这个操作同样会被复制到所有节点,备份仍然是最后一道防线。
最后要强调的是演练。高可用架构的价值只有在真实故障中才能体现。建议定期执行主库切换演练,验证应用是否能在新主库上正常写入,Router或VIP是否按预期切换,监控告警是否准确。没有经过演练的切换配置,往往在真正故障时暴露出脚本路径、权限、连接地址等意想不到的问题。