You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,结合外部监控脚本动态调整主节点的权重:

  1. 首先在HAProxy的global块中开启Runtime API:
global
    log 127.0.0.1 local0 notice
    stats socket /var/run/haproxy/admin.sock mode 660 level admin
  1. 编写监控脚本(示例),定期检查主节点的复制延迟,超过阈值时将权重设为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秒执行一次,就能动态控制主节点的流量占比。

额外注意事项

  1. 主主架构必须确保双向复制的正确性,比如设置不同的auto_increment_offset和auto_increment_increment避免主键冲突
  2. 给HAProxy检查用的MySQL用户最小权限:只需要SELECT权限(因为SHOW MASTER/SLAVE STATUS属于SELECT范畴)
  3. 测试故障场景:手动停掉主节点,模拟大量写请求,然后恢复主节点,观察健康检查的状态变化和HAProxy的流量调度情况

内容的提问来源于stack exchange,提问作者Henrique

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:05:26