HAProxy+MySQL主主复制架构下故障切换与数据一致性问题咨询
解决MySQL主主架构下HAProxy主节点恢复后的数据一致性问题
针对你在主主+从复制架构下HAProxy流量调度遇到的主节点恢复后复制延迟一致性问题,我有几个实践过的优化方案,结合你的现有配置可以快速落地:
方案一:改进主节点健康检查脚本(核心解决思路)
你的核心痛点是主节点恢复后未追平复制就被HAProxy拉入写池,所以必须让主节点的健康检查同时满足「自身主状态正常」和「作为从节点追平了另一主的写操作」两个条件,同时要兼容另一主完全故障的场景(此时无需检查复制)。
修改你的9200端口检查脚本如下(每个主节点的脚本对应修改远程主IP):
#!/bin/bash # 配置项,根据实际环境修改 LOCAL_DB="127.0.0.1" REMOTE_MASTER_IP="2.2.2.2" # 另一个主节点的IP MAX_DELAY_THRESHOLD=5 # 允许的最大复制延迟(秒) DB_USER="haproxy_check" # 仅需SHOW MASTER/SLAVE权限的MySQL用户 DB_PASS="your_check_password" # 1. 检查自身主节点状态是否正常 master_check=$(mysql -h$LOCAL_DB -u$DB_USER -p$DB_PASS -e "SHOW MASTER STATUS;" 2>/dev/null) if [ -z "$master_check" ]; then echo "HTTP/1.1 503 Service Unavailable" exit 1 fi # 2. 检查远程主节点是否在线 ping -c 2 -W 3 $REMOTE_MASTER_IP >/dev/null 2>&1 remote_alive=$? if [ $remote_alive -eq 0 ]; then # 远程主节点在线,必须检查复制状态和延迟 slave_status=$(mysql -h$LOCAL_DB -u$DB_USER -p$DB_PASS -e "SHOW SLAVE STATUS\G" 2>/dev/null) io_running=$(echo "$slave_status" | grep -i "Slave_IO_Running" | awk '{print $2}') sql_running=$(echo "$slave_status" | grep -i "Slave_SQL_Running" | awk '{print $2}') delay_sec=$(echo "$slave_status" | grep -i "Seconds_Behind_Master" | awk '{print $2}') # 处理延迟值为NULL的情况(比如刚启动复制) if [ -z "$delay_sec" ] || [ "$delay_sec" = "NULL" ]; then delay_sec=9999 fi if [ "$io_running" != "Yes" ] || [ "$sql_running" != "Yes" ] || [ "$delay_sec" -gt $MAX_DELAY_THRESHOLD ]; then echo "HTTP/1.1 503 Service Unavailable" exit 1 fi fi # 所有检查通过,返回健康状态 echo "HTTP/1.1 200 OK" exit 0
关键逻辑说明:
- 当另一主节点在线时,当前主节点必须是正常的从节点(复制线程运行正常+延迟达标)才会被HAProxy判定为健康
- 当另一主节点完全故障(ping不通),则跳过复制检查,只保留自身主状态检查,确保当前主节点可以正常承接所有写请求
方案二:配合HAProxy slowstart 参数实现平滑流量过渡
在方案一的基础上,给HAProxy的主节点配置slowstart参数,让恢复后的主节点在复制追平后,逐渐承接流量,避免瞬间流量冲击:
修改你的mariadb-writes监听块中的server配置:
listen mariadb-writes bind 0.0.0.0:3307 mode tcp option allbackups option httpchk GET / balance roundrobin # 9200检查主状态+复制延迟,slowstart设置为5分钟(可根据你的数据量调整) server mariadb1 1.1.1.1:3306 check port 9200 slowstart 300s server mariadb2 2.2.2.2:3306 check port 9200 backup slowstart 300s
slowstart的作用是:节点恢复健康后,在指定时间内将其权重从0逐渐提升到100,避免突然承接全部写流量,同时给复制留一点缓冲时间(即使方案一的检查已经通过,也能更稳妥)。
方案三:动态权重调整(进阶灵活控制)
如果需要更精细的流量控制,可以利用HAProxy的Runtime API,结合外部监控脚本动态调整主节点的权重:
- 首先在HAProxy的global块中开启Runtime API:
global log 127.0.0.1 local0 notice stats socket /var/run/haproxy/admin.sock mode 660 level admin
- 编写监控脚本(示例),定期检查主节点的复制延迟,超过阈值时将权重设为0,恢复后调回100:
#!/bin/bash HAPROXY_SOCK="/var/run/haproxy/admin.sock" DB_USER="haproxy_check" DB_PASS="your_check_password" MAX_DELAY=5 # 检查mariadb1的复制延迟 delay=$(mysql -h1.1.1.1 -u$DB_USER -p$DB_PASS -e "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Seconds_Behind_Master" | awk '{print $2}') if [ "$delay" -gt $MAX_DELAY ] || [ "$delay" = "NULL" ]; then # 延迟过高,设置权重为0 echo "set server mariadb-writes/mariadb1 weight 0" | socat stdio $HAPROXY_SOCK else # 延迟正常,恢复权重 echo "set server mariadb-writes/mariadb1 weight 100" | socat stdio $HAPROXY_SOCK fi
将这个脚本加入crontab,比如每10秒执行一次,就能动态控制主节点的流量占比。
额外注意事项
- 主主架构必须确保双向复制的正确性,比如设置不同的
auto_increment_offset和auto_increment_increment避免主键冲突 - 给HAProxy检查用的MySQL用户最小权限:只需要
SELECT权限(因为SHOW MASTER/SLAVE STATUS属于SELECT范畴) - 测试故障场景:手动停掉主节点,模拟大量写请求,然后恢复主节点,观察健康检查的状态变化和HAProxy的流量调度情况
内容的提问来源于stack exchange,提问作者Henrique
相关产品推荐
相关产品推荐

