导读:本期聚焦于剑客创作的《如何编写HAProxy健康检查脚本来实现自定义后端监控?》,敬请观看详情。HAProxy自带的健康检查只能判断端口是否可连通,一旦业务层面的可用性需要更细粒度的判断,就不得不借助外部脚本。本文围绕HAProxy健康检查脚本的编写展开,先讲清楚自带检查与外部检查的区别,再说明agent-check、external-check以及httpchk几种方式的适用场景,随后给出一个可直接落地的shell脚本示例,包括退出码约定、超时控制、日志输出等细节,最后分析脚本执行失败、检查抖动等常见问题的排查思路,帮助读者搭建稳定可靠的自定义后端监控方案。

HAProxy的健康检查机制是保证后端服务高可用的核心手段,但默认的TCP四层检查只能确认端口处于监听状态,无法感知应用是否真正具备处理请求的能力。比如一个Java服务端口开着,但线程池已经耗尽、数据库连接全部挂掉,此时TCP检查依然会返回成功,流量照常被转发到一台"僵尸"节点上。要解决这个问题,就需要编写自定义的健康检查脚本,让HAProxy根据脚本的退出码来决定节点状态。本文将从检查方式的选择、脚本编写规范、配置落地以及常见问题排查几个方面,完整讲解HAProxy健康检查脚本的编写方法。

如何编写HAProxy健康检查脚本来实现自定义后端监控?

一、HAProxy支持的几种健康检查方式对比

在动手写脚本之前,必须先弄清楚HAProxy提供了哪些检查能力,以及它们各自的判断逻辑。很多人一上来就写脚本,结果选错了挂载点,导致脚本根本没被调用。HAProxy的检查能力主要分为内置检查和外部检查两大类,内置检查由HAProxy进程自身完成,外部检查则通过执行脚本或访问agent端口来完成。

1. 内置检查:httpchk与tcp-check

option httpchk是最常用的七层检查方式,HAProxy会主动向后端发起一个HTTP请求,根据响应状态码判断健康状态。可以通过http-check expect指令细化判断条件,例如要求状态码为200,或者要求响应体中包含特定字符串。这种方式无需编写脚本,性能开销小,是HTTP类服务的首选。而tcp-check则用于四层检查,可以按顺序执行connect、send、expect一系列动作,模拟简单的协议交互,适合Redis、MySQL这类有握手协议的服务。

2. 外部检查:external-check与agent-check

当内置检查无法满足需求时,就需要引入脚本。external-check通过external-check pathexternal-check command指令在服务器节点上执行命令,命令的退出码直接决定健康状态。需要注意它依赖nbthread 1或者在较新版本中的特殊支持,且默认出于安全考虑需要显式开启external-check模块允许。agent-check则是另一种思路:HAProxy主动连接后端某个端口(由agent-addragent-port指定),该端口上运行的任意程序(可以是你写的脚本,也可以是systemd服务)返回一个字符串来报告状态,支持up、down、ready、drain、maint等状态值,还能携带权重百分比。agent方式的优势在于检查逻辑与HAProxy配置解耦,脚本崩溃不会影响HAProxy本身的稳定性。

3. 三种方式的选择建议

简单总结选择原则:纯HTTP服务优先用httpchk加expect,这是成本最低的方案;需要检查数据库连接、磁盘空间、依赖服务可用性等复合条件时,用external-check执行脚本;希望在节点上常驻一个轻量状态上报程序、并且支持动态调整权重(比如灰度摘流)时,用agent-check。下面我们重点讲解脚本编写部分,这也是实践中最容易出错的地方。

二、健康检查脚本的编写规范与实例

无论是external-check还是agent模式,脚本的质量直接决定监控的可靠性。HAProxy对脚本有一个硬性约定:退出码0表示检查通过,非0表示失败。除此之外,超时控制、幂等性、资源消耗这三点是脚本必须保证的,否则一个写得不好的脚本可能把整个负载均衡集群拖垮。

1. 脚本退出码与超时控制

HAProxy执行外部检查时有inter参数控制检查间隔,但脚本自身的执行时间也必须受限。如果脚本内部有curl或数据库连接操作,一定要设置超时参数,否则脚本可能无限挂起,堆积大量僵尸进程。下面是一个综合检查HTTP接口和磁盘空间的脚本示例:

#!/bin/bash
# HAProxy外部健康检查脚本
# 退出码: 0 = 健康, 1 = 不健康

# 接收HAProxy传入的参数,这里假设是目标地址
TARGET=$1
LOG_TAG="haproxy-healthcheck"

# 检查HTTP接口,5秒超时,要求返回200且响应体包含ok
HTTP_RESULT=$(curl -s -m 5 -o /tmp/hc_body -w "%{http_code}" "http://${TARGET}/healthz")
if [ "$HTTP_RESULT" != "200" ]; then
    logger -t "$LOG_TAG" "HTTP check failed, code=$HTTP_RESULT target=$TARGET"
    exit 1
fi

if ! grep -q "ok" /tmp/hc_body 2>/dev/null; then
    logger -t "$LOG_TAG" "healthz body invalid, target=$TARGET"
    exit 1
fi

# 检查磁盘使用率,超过90%判定不健康
DISK_USAGE=$(df /data | awk 'NR==2 {gsub("%",""); print $5}')
if [ "$DISK_USAGE" -gt 90 ]; then
    logger -t "$LOG_TAG" "disk usage too high: ${DISK}%"
    exit 1
fi

exit 0

脚本中的curl -m 5将整个请求的超时限制在5秒,配合HAProxy侧的inter间隔(例如3秒)和timeout check设置,可以保证检查节奏可控。logger命令将失败原因写入系统日志,排查问题时通过grep haproxy-healthcheck /var/log/messages即可快速定位是哪一项检查失败,这比只看到一个"DOWN"状态有用得多。

2. 避免脚本层面的常见坑

第一个坑是脚本报错被静默吞掉。如果脚本第一行没有#!/bin/bash,或者文件没有可执行权限,external-check执行时会直接失败,HAProxy把节点标记为DOWN,但日志里信息很少。务必在部署后手动执行一次脚本验证退出码:echo $?。第二个坑是脚本中产生了大量临时文件但没有清理,长期运行后磁盘被打满,健康检查反而因为磁盘问题失效,形成恶性循环。建议用mktemp创建临时文件并在脚本末尾用trap清理。第三个坑是并发问题,多进程同时执行脚本时避免竞争同一个文件,参数化命名或使用管道代替临时文件是更稳妥的做法。

三、在HAProxy配置中接入脚本

脚本写好后,需要在HAProxy配置中正确挂载。下面演示external-check方式的完整配置片段:

global
    # 开启外部检查,1.9之后的版本需要显式允许
    external-check

defaults
    mode http
    timeout connect 5s
    timeout client 30s
    timeout server 30s

listen web_cluster
    bind *:80
    balance roundrobin

    # 检查间隔3秒,连续2次失败判定DOWN,连续2次成功恢复UP
    default-server inter 3s fall 2 rise 2

    server web1 192.168.1.11:8080 check external-check command "/opt/scripts/healthcheck.sh 192.168.1.11:8080"
    server web2 192.168.1.12:8080 check external-check command "/opt/scripts/healthcheck.sh 192.168.1.12:8080"

这里有几个关键点值得展开。external-check command后面跟的是完整命令行,参数直接写在命令里,HAProxy不会自动替换目标地址,所以每个server都要写明自己的参数。fall 2 rise 2的含义是连续两次失败才摘除节点、连续两次成功才重新加入,这个防抖机制非常重要,如果设置为fall 1,一次网络抖动就会导致节点被踢出,流量来回切换造成服务不稳定。另外,脚本路径建议使用绝对路径,并且确保HAProxy运行用户(通常是haproxy)对脚本有执行权限、对相关命令有访问权限,必要时还需要调整SELinux策略或setsebool开关。

agent-check的配置示例

如果倾向于agent方式,配置和脚本结构会有所不同。后端节点上需要一个常驻进程监听指定端口并输出状态:

backend web_backend
    mode http
    server web1 192.168.1.11:8080 check agent-check agent-addr 192.168.1.11 agent-port 12345 agent-inter 5s

节点侧可以用一个极简的循环脚本配合nc或socat输出状态字符串,例如输出50%表示健康但权重减半,输出down表示需要摘除。这种方式的典型用途是维护窗口:运维人员在节点上手动执行命令把agent输出切换为maint,HAProxy会在下一次agent交互时将节点转入维护模式,无需修改配置或reload。

四、检查异常与抖动的排查思路

脚本上线后最常见的两类问题是"明明服务正常但被判定DOWN"和"节点状态频繁抖动"。对于前者,先手动以HAProxy运行用户身份执行脚本:sudo -u haproxy /opt/scripts/healthcheck.sh 192.168.1.11:8080; echo $?,环境变量差异、权限不足、PATH缺失是最常见的三类原因。对于后者,重点检查脚本内的超时设置是否接近甚至超过inter间隔,以及后端服务是否存在间歇性慢响应,可以适当加大inter、提高fall值来缓解。同时建议开启HAProxy的stats页面,观察每个节点的检查状态变化历史,结合系统日志中的脚本输出交叉定位。

最后需要提醒的是,健康检查本身也是一种对后端的请求压力,检查间隔设置得过短会在大集群场景下形成可观的额外负载。合理规划inter、fall、rise三个参数,让脚本保持轻量、快速、可观测,才能让这套自定义监控方案长期稳定地运行下去。

HAProxy健康检查脚本后端监控修改时间:2026-09-01 16:58:47

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。