MySQL主从切换实战:自动故障转移配置
在现代数据中台架构中,数据库的高可用性是保障业务连续性的核心环节。尤其在数字孪生、实时可视化和大规模数据处理场景下,任何一次数据库宕机都可能导致决策延迟、数据丢失或服务中断。MySQL作为最广泛使用的开源关系型数据库,其主从复制架构是构建高可用体系的基础。但仅配置主从复制远远不够——真正的高可用,必须实现自动故障转移(Automatic Failover)。本文将深入讲解MySQL主从切换的实战配置流程,涵盖架构设计、监控机制、切换脚本、验证方法与生产环境最佳实践。
在开始自动故障转移前,必须确保主从复制稳定可靠。标准架构如下:
-- 主库配置示例(my.cnf)[mysqld]server-id = 1log-bin = mysql-binbinlog-format = ROWgtid-mode = ONenforce-gtid-consistency = ONbinlog-ignore-db = mysql-- 从库配置示例[mysqld]server-id = 2relay-log = mysql-relay-binlog-slave-updates = ONgtid-mode = ONenforce-gtid-consistency = ON配置完成后,使用CHANGE MASTER TO命令建立复制关系,并通过SHOW SLAVE STATUS\G验证Slave_IO_Running和Slave_SQL_Running均为Yes。
✅ 关键提示:在生产环境中,建议部署至少两个从库,一个用于读负载均衡,另一个作为热备节点,专用于故障转移。
手动切换主从存在三大致命缺陷:
自动故障转移系统通过监控、决策、执行三步闭环,实现:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| MHA(Master High Availability) | 成熟稳定,支持多从库,自动选主,支持binlog server | 配置复杂,依赖SSH,不支持MySQL 8.0全特性 | 中小型企业,稳定环境 |
| Orchestrator | Web界面,支持拓扑可视化,自动修复,兼容MySQL 8.0 | 资源消耗大,需Go环境,部署复杂 | 大型集群,运维团队能力强 |
| 自定义脚本 + ProxySQL + Keepalived | 轻量灵活,可深度定制,成本低 | 需自行开发监控逻辑,维护成本高 | 技术团队自主可控,追求可控性 |
推荐中小型数据中台团队采用 “自定义脚本 + ProxySQL + Keepalived” 组合方案,兼顾成本与可控性。
在主库和从库上安装Keepalived,配置虚拟IP(如192.168.1.100),由主库持有。当主库宕机,从库自动接管VIP。
# /etc/keepalived/keepalived.conf(主库)vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.100 } notify_master "/etc/keepalived/notify_master.sh" notify_fault "/etc/keepalived/notify_fault.sh"}# /etc/keepalived/notify_master.sh(主库上线脚本)#!/bin/bashecho "$(date): Master elected" >> /var/log/keepalived.log# 通知ProxySQL更新后端权重curl -X POST http://localhost:6032/admin -d '{"username":"admin","password":"admin","hostgroup_id":1,"hostname":"192.168.1.10","port":3306,"weight":1000}'# /etc/keepalived/notify_fault.sh(主库下线脚本)#!/bin/bashecho "$(date): Master failed, promoting slave" >> /var/log/keepalived.log# 执行切换脚本/usr/local/bin/mysql_failover.sh该脚本完成以下逻辑:
STOP SLAVE; RESET SLAVE ALL;CHANGE MASTER TO使其他从库指向新主#!/bin/bash# mysql_failover.shMASTER_IP="192.168.1.10"SLAVE1_IP="192.168.1.11"SLAVE2_IP="192.168.1.12"# 检查主库是否存活if ! timeout 5 bash -c "echo > /dev/tcp/$MASTER_IP/3306"; then echo "Master $MASTER_IP is unreachable. Starting failover..." # 获取各从库的GTID执行状态 MASTER_GTID=$(mysql -h$MASTER_IP -umonitor -p'password' -e "SHOW MASTER STATUS;" 2>/dev/null | grep -v "Master" | awk '{print $6}') SLAVE1_GTID=$(mysql -h$SLAVE1_IP -umonitor -p'password' -e "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Executed_Gtid_Set" | awk '{print $2}') SLAVE2_GTID=$(mysql -h$SLAVE2_IP -umonitor -p'password' -e "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Executed_Gtid_Set" | awk '{print $2}') # 选择GTID最全的从库作为新主 if [[ -n "$SLAVE1_GTID" && ( -z "$SLAVE2_GTID" || "$SLAVE1_GTID" > "$SLAVE2_GTID" ) ]]; then NEW_MASTER=$SLAVE1_IP echo "Promoting $SLAVE1_IP as new master" else NEW_MASTER=$SLAVE2_IP echo "Promoting $SLAVE2_IP as new master" fi # 停止新主的复制,清除旧配置 mysql -h$NEW_MASTER -umonitor -p'password' -e "STOP SLAVE; RESET SLAVE ALL;" # 使其他从库指向新主 mysql -h$SLAVE2_IP -umonitor -p'password' -e "CHANGE MASTER TO MASTER_HOST='$NEW_MASTER', MASTER_USER='repl', MASTER_PASSWORD='replpass', MASTER_AUTO_POSITION=1;" mysql -h$SLAVE1_IP -umonitor -p'password' -e "CHANGE MASTER TO MASTER_HOST='$NEW_MASTER', MASTER_USER='repl', MASTER_PASSWORD='replpass', MASTER_AUTO_POSITION=1;" # 更新ProxySQL:将新主设为写组,旧主设为只读 curl -X POST http://localhost:6032/admin -uadmin:admin -d "{\"username\":\"admin\",\"password\":\"admin\",\"hostgroup_id\":1,\"hostname\":\"$NEW_MASTER\",\"port\":3306,\"weight\":1000}" curl -X POST http://localhost:6032/admin -uadmin:admin -d "{\"username\":\"admin\",\"password\":\"admin\",\"hostgroup_id\":2,\"hostname\":\"$NEW_MASTER\",\"port\":3306,\"weight\":1000}" # 发送告警 curl -X POST "https://oapi.dingtalk.com/robot/send?access_token=xxx" \ -H "Content-Type: application/json" \ -d '{"msgtype": "text", "text": {"content": "MySQL主从切换完成!新主库:'$NEW_MASTER',原主库已下线。"}}' echo "Failover completed. New master: $NEW_MASTER"fi⚠️ 注意:脚本需以
root或具有MySQL权限的用户运行,并配置SSH免密登录用于远程执行。
ProxySQL作为中间层,将写请求路由至写组(hostgroup_id=1),读请求路由至读组(hostgroup_id=2)。当主从切换发生时,只需更新ProxySQL的后端配置,应用无需重启。
-- 在ProxySQL中配置INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (1, '192.168.1.10', 3306, 1000), -- 原主库(2, '192.168.1.11', 3306, 1000), -- 从库1(2, '192.168.1.12', 3306, 1000); -- 从库2LOAD MYSQL SERVERS TO RUNTIME;SAVE MYSQL SERVERS TO DISK;当新主库上线后,脚本会自动将新主加入hostgroup_id=1,旧主移出,实现无缝切换。
systemctl stop mysqltail -f /var/log/keepalived.logmysql -h192.168.1.100 -e "SELECT @@server_id;"SELECT * FROM mysql_servers;✅ 成功标志:5秒内完成VIP漂移,15秒内完成数据同步重定向,应用无报错。
| 实践项 | 说明 |
|---|---|
| 监控告警 | 使用Prometheus + Alertmanager监控Slave_Delay、Slave_IO_Running、MySQL_Uptime |
| 日志审计 | 所有切换操作记录到ELK系统,便于事后追溯 |
| 定期演练 | 每季度模拟一次主库宕机,验证切换流程是否正常 |
| 备份策略 | 主从均开启全量+增量备份,切换后立即触发备份 |
| 连接池重置 | 应用端使用HikariCP或Druid,设置connectionTestQuery,避免连接缓存导致写入失败 |
Seconds_Behind_Master → 脚本中加入阈值判断(如>30s不切换)pt-heartbeat持续监控延迟在数字孪生和实时数据可视化系统中,数据库的稳定性直接决定业务洞察的时效性。MySQL主从切换不是一次性的配置任务,而是一个需要持续监控、优化、演练的系统工程。自动故障转移不是锦上添花,而是数据服务的底线要求。
如果你正在构建企业级数据中台,却仍依赖人工干预数据库切换,那么你的系统正暴露在巨大风险中。我们建议立即部署上述自动化方案,并结合监控平台实现闭环管理。
申请试用&https://www.dtstack.com/?src=bbs申请试用&https://www.dtstack.com/?src=bbs申请试用&https://www.dtstack.com/?src=bbs
通过自动化、标准化、可观测的数据库运维体系,你将不再为凌晨三点的报警电话而焦虑。真正的高可用,始于一次果断的切换,成于一套严谨的机制。
申请试用&下载资料