服务公告

服务公告 > 综合新闻 > HAProxy - 健康检查 新手入门教程

HAProxy - 健康检查 新手入门教程

发布时间:2026-05-01 08:01
HAProxy健康检查配置:TCP/HTTP主动探测与自定义脚本实战。解决后端已挂但流量仍在发送的痛点,覆盖基础配置、进阶技巧、故障排查。

前言

搞过的人都知道,最烦的是HAProxy后端明明已经挂了,流量还在往上面扔。健康检查配了,但有时候根本不生效,或者检查太频繁把服务器打挂。这次把健康检查的配置讲透,从基础的TCP/HTTP检查到自定义脚本,让你真正做到"挂了就知道"。

一、操作步骤

步骤1:理解健康检查核心参数

配置文件里跟健康检查相关的参数就这几个,搞清楚它们的关系就懂了:

# 关键参数说明 inter # 健康检查间隔(毫秒),默认2000 rise # 连续多少次成功才认为服务器健康,默认2 fall # 连续多少次失败才认为服务器挂了,默认3 timeout check # 检查超时时间,默认5秒 fastinter # 故障期间的快速检查间隔 downinter # 服务器标记为DOWN后的检查间隔

默认配置下,一台后端从挂掉到被摘掉需要至少6秒(2次失败×3秒间隔)。生产环境可以根据业务容忍度调整。

步骤2:TCP层健康检查配置

最基础的检查方式,只检测端口能不能建立连接。适合MySQL、Redis等非HTTP服务:

# CentOS/RHEL: /etc/haproxy/haproxy.cfg # Ubuntu: /etc/haproxy/haproxy.cfg backend mysql_backend mode tcp balance roundrobin server mysql1 10.0.0.11:3306 check inter 3000 rise 2 fall 3 server mysql2 10.0.0.12:3306 check inter 3000 rise 2 fall 3

预期输出:

# 查看后端状态 $ sudo systemctl restart haproxy $ echo "show stat" | sudo socat stdio /var/lib/haproxy/stats # 输出示例(筛选mysql_backend相关行) mysql_backend,FRONTEND,,,0,0,0,0,0,0,0,,0,0,0,0,0,,0,0,0,0,0,,,,,UP,0,0,0,0,0,0,0,0,0,,,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, mysql_backend,mysql1,10.0.0.11:3306,0,0,0,,0,0,0,0,0,0,0,0,0,,0,0,0,0,0,0,,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

最后一列是"UP"表示健康。状态码含义:UP=正常,DOWN=挂了,UP 1/3=正在上线(需要rise次成功)。

步骤3:HTTP层健康检查配置

比TCP检查更进一步,能检测应用层是否真的在服务。适合Web后端:

backend web_backend mode http balance roundrobin option httpchk http-check expect status 200 server web1 10.0.0.21:8080 check inter 5000 rise 2 fall 3 server web2 10.0.0.22:8080 check inter 5000 rise 2 fall 3

预期输出:

# 模拟后端正常返回200 $ curl -s http://10.0.0.21:8080/health {"status":"ok"} # HAProxy日志查看检查状态(CentOS/RHEL: /var/log/haproxy.log,Ubuntu: /var/log/haproxy/haproxy.log) $ sudo tail -f /var/log/haproxy.log Nov 15 10:23:45 haproxy[12345]: Server web_backend/web1 is UP, reason: Layer7 check passed, code: 200 # 模拟后端返回500(模拟应用挂了) $ curl -s http://10.0.0.21:8080/health {"error":"database connection failed"} # 几秒后查看状态 $ echo "show stat" | sudo socat stdio /var/lib/haproxy/stats | grep web1 web_backend,web1,10.0.0.21:8080,...,DOWN,2,0,0,... # 最后一列变成DOWN

注意:默认检查路径是"/",如果后端没有这个路径会误判。可以指定检查路径和期望内容:

http-check send meth GET uri /health.html http-check expect string "OK"

步骤4:带Basic Auth的健康检查

如果后端需要认证,可以用这种方式:

backend protected_backend mode http option httpchk http-check send meth GET uri /health hdr Authorization "Basic YOUR_BASE64_CREDENTIALS" server app1 10.0.0.31:8000 check inter 5000 rise 2 fall 3

预期输出:

# 生成Basic Auth的base64编码(注意:实际使用时请用真实凭证替换) $ echo -n "admin:YOUR_PASSWORD" | base64 YWRtaW46UEFTU1dPUkQ= # 检查配置语法 $ sudo haproxy -c -f /etc/haproxy/haproxy.cfg Configuration file is valid # 查看认证后的健康检查日志 $ sudo tail /var/log/haproxy.log Nov 15 11:05:23 haproxy[12345]: Server protected_backend/app1: HTTP status 401, so no more check attempts on this server. Nov 15 11:05:26 haproxy[12345]: Server protected_backend/app1 is DOWN, reason: Layer7 timeout, check duration: 5001ms.

返回401会被判定为DOWN。如果业务上认证失败也要认为服务正常,改用字符串匹配而不是状态码:

http-check expect status 200,401 # 200和401都认为正常

步骤5:自定义检查脚本实现复杂逻辑

有时候标准检查不够用,比如要检测MySQL主从同步状态、Redis集群可用性:

# 创建检查脚本(CentOS/RHEL和Ubuntu通用路径) $ sudo cat > /usr/local/bin/mysql_replication_check.sh << 'EOF' #!/bin/bash # 检查MySQL主从同步延迟,超过阈值就返回失败 MYSQL_CONN="/usr/bin/mysql -u health_user -pYOUR_PASSWORD -h HOSTNAME" SYNC_DELAY=$($MYSQL_CONN -e "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Seconds_Behind_Master" | awk '{print $2}') if [ "$SYNC_DELAY" == "NULL" ] || [ "$SYNC_DELAY" -gt 30 ]; then exit 1 # 检查失败 fi exit 0 # 检查成功 EOF $ sudo chmod +x /usr/local/bin/mysql_replication_check.sh

⚠️ 警告:生产环境中请使用最小权限的健康检查专用MySQL用户,不要用root。

# HAProxy配置使用外部检查脚本 backend mysql_replication mode tcp balance leastconn option external-check external-check command /usr/local/bin/mysql_replication_check.sh server mysql1 10.0.0.41:3306 check inter 3000 rise 2 fall 3 server mysql2 10.0.0.42:3306 check inter 3000 rise 2 fall 3

预期输出:

# 检查配置语法 $ sudo haproxy -c -f /etc/haproxy/haproxy.cfg [ALERT] 324/110523: config: external checks need to be enabled by 'external-check' # 需要在全局配置启用external-check $ sudo vi /etc/haproxy/haproxy.cfg # 在global段添加: global external-check # 再次验证 $ sudo haproxy -c -f /etc/haproxy/haproxy.cfg Configuration file is valid # 重启服务 $ sudo systemctl restart haproxy # CentOS/RHEL $ sudo service haproxy restart # Ubuntu # 查看检查状态 $ echo "show stat" | sudo socat stdio /var/lib/haproxy/stats | grep mysql mysql_replication,mysql1,10.0.0.41:3306,...,UP,0,0,0,...

步骤6:主动检查与被动检查配合

主动检查(health检查)负责探测后端状态,被动检查(出演检查)负责根据真实请求判断后端是否可用。两者配合才能做到精准:

backend web_backend mode http balance roundrobin # 主动健康检查 option httpchk http-check expect status 200 server web1 10.0.0.21:8080 check inter 5000 rise 2 fall 3 # 被动检查配置 option tcp-smart-accept option tcp-smart-connect server web2 10.0.0.22:8080 check inter 5000 rise 2 fall 3

关键参数说明:

option tcp-smart-accept # 连接失败立即摘掉后端,不等健康检查 option tcp-smart-connect # 连接后端前先探测,不等健康检查发现挂了 option redispatch # 失败后尝试重试其他后端 retries 3 # 失败重试次数

预期输出:

# 查看当前后端状态 $ echo "show servers state" | sudo socat stdio /var/lib/haproxy/stats # 输出示例: 2 # be_id be_name srv_id srv_addr srv_name srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_health srv_check_rise srv_check_fall srv_check_code srv_agent_status srv_agent_rise srv_agent_fall 1 web_backend 1 10.0.0.21 8080 web1 0 0 1 1 5 2 3 0 0 0 0 0 0 1 web_backend 2 10.0.0.22 8080 web2 0 0 1 1 5 2 3 0 0 0 0 0 0 # 手动触发一台后端故障测试 $ curl -v http://10.0.0.22:8080/unknown-endpoint 2>&1 | head -20 * Connection refused # 连接被拒绝后,HAProxy会自动尝试其他后端 # 查看日志确认重试 $ sudo tail /var/log/haproxy.log | grep web2 Nov 15 12:00:15 haproxy[12345]: web_backend/web2: Connection failure (repeated 3 times), action: kill

步骤7:渐进式恢复与优雅上线

后端服务重启时,如果直接全部上线,瞬间流量可能把刚启动的服务打挂。用rise参数控制渐进式恢复:

backend web_backend mode http balance roundrobin option httpchk # 正常状态:5秒检查一次 server web1 10.0.0.21:8080 check inter 5000 rise 5 fall 3 # 如果后端故障恢复期间,用快速检查确认 # rise值越大,恢复越慢,但更稳妥

预期输出:

# 模拟后端服务重启 $ sudo systemctl restart web-server # CentOS/RHEL $ sudo service web-server restart # Ubuntu # 查看健康检查状态变化 $ watch -n 1 "echo 'show stat' | sudo socat stdio /var/lib/haproxy/stats | grep web1 | cut -d',' -f2,18,34" # 输出序列: # 刚重启时: web1,DOWN,0 # 检查开始: web1,DOWN,1 # 第一次检查失败 web1,DOWN,2 # 第二次检查失败 # 服务恢复后: web1,UP 1/5,1 # 第一次检查成功,但需要5次才能完全UP # 5次检查全部成功后: web1,UP,2 # 完全UP,权重正常

如果业务需要更快的恢复速度,可以临时调低rise值,重启后改回来:

# 临时使用:在控制台执行,无需重启HAProxy $ echo "set server web_backend/web1 state ready" | sudo socat stdio /var/lib/haproxy/stats $ echo "set server web_backend/web1 weight 50" | sudo socat stdio /var/lib/haproxy/stats # 或通过socket手动调整参数 $ echo "enable agent web_backend/web1" | sudo socat stdio /var/run/haproxy.sock

步骤8:验证与监控

配置完成后要确认检查真的在工作,设置告警防止"假健康":

# 使用HAProxy统计页面(默认监听9999端口) # CentOS/RHEL和Ubuntu配置相同 listen stats mode http bind *:9999 stats enable stats uri /stats stats refresh 10s # 在后端配置中添加agent检查(可选,用于更详细的监控) server web1 10.0.0.21:8080 check inter 5000 rise 2 fall 3 agent-check agent-inter 10000

预期输出:

# 浏览器访问 http://YOUR_HAPROXY_IP:9999/stats # 页面中可以看到每个后端的状态: # - Status: UP/DOWN # - LastChk: L7OK/200 in 2ms # - Ctrl: 4/2/3 (rise/fall/current) # 通过命令行查看详细状态 $ echo "show servers states" | sudo socat stdio /var/lib/haproxy/stats 2 # be_id be_name srv_id srv_addr srv_name srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_health srv_check_rise srv_check_fall srv_check_code srv_agent_status srv_agent_rise srv_agent_fall srv_fsm_time 1 web_backend 1 10.0.0.21 8080 web1 2 0 1 1 120 6 2 3 200 0 0 0 5000 1 web_backend 2 10.0.0.22 8080 web2 2 0 1 1 90 5 2 3 0 0 0 0 5000 # 各字段含义: # srv_op_state: 0=down, 1=up, 2=going up/down transition # srv_check_status: 0=none, 1=in progress, 2=up, 3=down, 4=error # srv_check_health: 连续成功次数(达到rise值后变为rise) # srv_check_fall: 连续失败次数(达到fall值后标记为down)

二、常见问题FAQ

Q:健康检查配了但后端还是被流量打死?

先看检查间隔和超时时间。默认inter=2000ms、timeout check=5s,如果后端响应慢(数据库查询超过5秒),检查就会超时被误判为DOWN。建议:HTTP检查的timeout要比业务实际响应时间多2-3倍。另外检查脚本本身也要加超时,防止卡死:

# 在检查脚本里加超时 curl -s --connect-timeout 3 --max-time 5 http://localhost:8080/health || exit 1

Q:检查通过但请求全部失败,怎么回事?

这是"假健康"——端口在监听,应用却挂了不响应请求。TCP检查只验证三次握手,HTTP检查只验证状态码,两者都没法确认应用真正能处理业务。解决方案:用自定义检查脚本测试实际的API接口,检查脚本要执行真实的业务逻辑,比如查数据库、读缓存。

Q:两台后端都在UP,但请求全部超时怎么办?

大概率是连接数超限或者后端本身负载太高。HAProxy的检查只看后端是否响应,不管后端的负载情况。需要在后端加上agent-check,脚本里检查load average、连接数、内存:

# agent检查脚本 #!/bin/bash LOAD=$(awk '{print $1}' /proc/loadavg) CONNECTIONS=$(ss -s | grep tcp | awk '{print $4}' | cut -d',' -f1) if [ "$LOAD" -gt 10 ] || [ "$CONNECTIONS" -gt 1000 ]; then echo "busy" # 告诉HAProxy这台后端当前压力大 exit 1 fi exit 0

Q:SSL后端如何配置健康检查?

直接检查HTTPS:

backend https_backend mode http option ssl-hello-chk # SSL隧道检查,适合非HTTP的HTTPS服务 server web1 10.0.0.21:443 check inter 5000 rise 2 fall 3

如果是HTTPS的Web后端,要检查具体路径:

option httpchk http-check send meth GET uri /health.html ssl

Q:HAProxy重启后所有后端都短暂变成DOWN?

正常现象,因为检查是从零开始的。可以配置持久化检查状态(需要额外配置),或者用init-addr参数在启动时先记录状态:

server web1 10.0.0.21:8080 check inter 5000 rise 2 fall 3 init-addr last,libc

这样HAProxy会尝试读取上一次的状态文件,启动时不会立即标记DOWN。

三、总结

核心要点:

  • TCP检查只验证端口,HTTP检查能验证应用层,agent检查可以验证业务逻辑——根据实际需求选对检查方式
  • inter、rise、fall、timeout check这四个参数决定检查的灵敏度和容错性,生产环境需要根据业务容忍度调优
  • 被动检查(出演检查)和主动检查配合才能真正做到"挂了就知道"和"恢复就上线"
  • 自定义脚本可以实现任意复杂度的检查逻辑,但要注意超时和权限控制
  • 配置完成后必须在生产环境验证,别只靠语法检查

延伸阅读: