Loading...

文章背景图

HAProxy 部署指南:高性能负载均衡与反向代理实战

2026-10-28
0
- 字
- 分钟
|

HAProxy Logo

一、项目介绍

HAProxy 是一个用 C 语言编写的开源、免费、非常快速可靠的反向代理与负载均衡器,专为高可用性、负载均衡以及基于 TCP 和 HTTP 应用的代理而设计。它诞生于 2001 年,由 Willy Tarreau 维护至今,是互联网行业使用最广泛的四层/七层负载均衡软件之一,被 GitHub、Reddit、Twitter、Stack Overflow、AWS、阿里云等大量公司和云厂商作为入口层负载均衡组件。

HAProxy 的核心优势在于极致性能:单实例可以处理数万并发连接、每秒数十万请求,延迟通常在亚毫秒级别。它支持 HTTP/1.1、HTTP/2、HTTP/3(QUIC)、WebSocket、TCP、SSL/TLS 终止、会话保持、健康检查、ACL 规则、Lua 脚本扩展、统计页、Prometheus 指标等丰富功能。与 Nginx 相比,HAProxy 在七层负载均衡、健康检查粒度、会话保持、统计可视化方面更专业;与云厂商 SLB 相比,它完全开源、可自托管、配置灵活、没有流量费用。

HAProxy 采用 GPL v2 许可证(头文件 LGPL v2.1),官方文档位于 docs.haproxy.org,项目仓库:github.com/haproxy/haproxy。它既可以作为独立的负载均衡器部署在物理机或虚拟机上,也可以以容器方式运行,还可以与 Keepalived 配合实现 VIP 高可用。

HAProxy 的性能来自几个关键设计:事件驱动、单线程非阻塞(1.8+ 引入多线程 nbthread)、零拷贝转发、连接池、专用内存池。它不 fork 进程、不创建线程处理每个请求,而是用 epoll/kqueue 同时管理数万连接,因此非常适合长连接(WebSocket、gRPC、数据库代理)场景。

HAProxy 还支持 HTTP/2(h2)、HTTP/3 over QUIC(3.0+)、gRPC 负载均衡、DNS 服务发现(自动从 DNS SRV 记录拉取后端列表)、Runtime API 动态配置、多进程 peers 同步会话表。它被大量云厂商用作内部 LB 数据面,包括 AWS Network Load Balancer、阿里云 SLB、腾讯云 CLB 的开源版本都参考了 HAProxy 的设计。

HAProxy 还提供 Education 与 Enterprise 版本(HAProxy Technologies 公司维护),在开源版基础上增加了商业支持、WAF、API Gateway 控制台、ARM 优化等功能。个人与中小企业使用开源版完全足够。

与商业负载均衡器(如 F5 BIG-IP)相比,HAProxy 完全免费、功能相当、社区活跃;与云厂商 SLB 相比,它没有按流量收费、没有单实例规格限制、可以部署在内网做东西向流量。这使得它成为中小型互联网公司、企业内网、开源项目首选的负载均衡方案。

典型使用场景包括:Web 入口层负载均衡(把流量分发到多台 Nginx 或应用服务器)、数据库读写分离代理(MySQL/PostgreSQL)、gRPC 服务负载均衡、WebSocket 长连接网关、API 网关、CDN 回源调度等。

本文以 HAProxy 3.0 LTS 为例,覆盖从单机安装、配置编写、Docker 部署、高可用、监控、动态管理到排错的完整流程,适合运维、后端、SRE 工程师作为日常查阅手册。

建议在测试环境熟悉 haproxy.cfg 的 DSL 后再上线,避免直接在生产改配置导致全站不可用。

二、项目结构与核心组件

HAProxy 仓库根目录结构经过二十多年演化,已经非常成熟。理解以下关键路径即可掌握整体骨架:

  • haproxy:编译后生成的主二进制,单文件即可运行。
  • src/:C 语言源码目录,包含协议解析、连接管理、队列、健康检查、ACL、 stick-table 等核心模块。
  • doc/:官方文档目录,包含 configuration.txt(配置参考手册)、intro.txt(入门介绍)、management.txt(管理指南)、lua.txt(Lua 扩展 API)、SPOE.txt(SPOE 引擎)、peers.txt(peers 协议)、network-namespaces.txt(网络命名空间)等。
  • examples/:示例配置目录,包含完整的 haproxy.cfg 样例。
  • contrib/:第三方扩展,包括 Lua 脚本、SPOE 代理、systemd unit 文件等。
  • addons/:可选编译模块,如 uri_normalizer、prometheus-exporter 等。
  • INSTALL:编译安装说明文件。
  • BRANCHES:版本生命周期说明,解释稳定版与开发版的区别。

HAProxy 的核心组件可以归纳为四个部分:frontend(前端,定义监听端口、ACL、规则)、backend(后端,定义一组后端服务器、负载均衡算法、健康检查)、defaults(默认参数块,被 frontend/backend 继承)、stats(统计页与管理接口)。配置文件 haproxy.cfg 采用段式语法,每段以 global、defaults、frontend、backend、listen 开头。

HAProxy 还支持 stick-table(粘性表)做连接跟踪与限流、SPOE(Stream Processing Offload Engine)把请求转发给外部代理做鉴权、Runtime API 通过 socket 动态调整后端权重、peers 协议在多实例间同步 stick-table 数据。

HAProxy 的配置文件采用段式 DSL,几个关键字段含义:bind 定义监听地址与端口、server 定义后端节点、balance 定义负载均衡算法(roundrobin、leastconn、source、uri、hdr)、check 启用健康检查、option httpchk 定义 HTTP 健康检查路径、timeout 各类超时、acl 定义访问控制列表、use_backend 根据 ACL 转发到不同后端。配置文件修改后必须先 haproxy -c -f haproxy.cfg 验证语法再 reload。

HAProxy 还支持多配置文件包含:在主配置中写 ###_/etc/haproxy/conf.d/*.cfg_### 即可引入多个片段,方便按业务线拆分配置。它还支持 Runtime API 通过 Unix socket 动态增删后端、改权重、查看会话表,不需要 reload,这在秒级扩缩容的云原生场景下非常有用。

三、版本与环境要求

HAProxy 版本号采用 主.次.修订 格式,偶数次版本为稳定版(如 2.8 LTS、2.9、3.0 LTS),奇数次版本为开发版。生产环境推荐使用 LTS 版本(2.8、3.0),官方维护周期长达 3-5 年。最新版本可在 Releases 页面查看。

编译与运行环境要求:

  • 操作系统:Linux(推荐,性能最佳)、FreeBSD、OpenBSD、NetBSD、macOS、Windows(WSL2)均可。
  • 编译器:GCC 4.2+ 或 Clang,需要支持 C99。
  • 依赖库:可选依赖包括 openssl(SSL/TLS)、lua(Lua 脚本)、pcre(正则)、zlib(压缩)、systemd(sd_notify)。不装这些依赖也能编译,但会缺少对应功能。
  • 资源:单实例日常运行只需几十 MB 内存;高并发场景建议至少 2 核 CPU、4GB 内存。文件描述符限制需要调到 65535 以上。
  • 网络:监听 80/443 端口需要 root 或 CAP_NET_BIND_SERVICE;后端服务器需与 HAProxy 网络互通。
  • 内核参数:建议调整 net.core.somaxconn=65535、net.ipv4.tcp_max_syn_backlog=65535、net.ipv4.ip_local_port_range=1024 65535。

官方 Docker 镜像为 haproxy:lts,基于 Alpine,体积不到 20 MB。多数 Linux 发行版的包管理器也提供 haproxy 包,但版本通常滞后,生产环境建议自行编译或使用官方镜像。

HAProxy 3.0 LTS 于 2024 年底发布,引入了 HTTP/3 over QUIC 服务端、Improved Lua API、新的观测指标。如果是新部署,强烈建议直接选 3.0 LTS;维护老系统则可以继续用 2.8 LTS(支持到 2026 年)。版本升级前务必阅读 CHANGELOG,某些旧配置项在新版本中已被移除或改名。

在 Kubernetes 场景下,HAProxy 通常以 Ingress Controller 的形式部署,官方项目是 haproxytech/kubernetes-ingress,通过 CRD(HAProxyBackend、HAProxyRoute)声明式管理路由。也可以使用社区维护的 haproxy-ingress。

四、本地部署

4.1 包管理器安装(最快上手)

# Debian/Ubuntu
sudo apt update && sudo apt install -y haproxy

# RHEL/CentOS/Rocky
sudo dnf install -y haproxy

# macOS
brew install haproxy

# 验证
haproxy -v

4.2 从源码编译(生产推荐)

sudo apt install -y build-essential libssl-dev libpcre3-dev zlib1g-dev lua5.4 liblua5.4-dev
wget https://www.haproxy.org/download/3.0/src/haproxy-3.0.5.tar.gz
tar -xzf haproxy-3.0.5.tar.gz
cd haproxy-3.0.5
make -j$(nproc) TARGET=linux-glibc \
  USE_OPENSSL=1 USE_LUA=1 USE_PCRE=1 USE_ZLIB=1 \
  USE_SYSTEMD=1 USE_THREAD=1
sudo make install
sudo cp examples/haproxy.init /etc/init.d/haproxy
sudo chmod +x /etc/init.d/haproxy
haproxy -v

TARGET=linux-glibc 针对 glibc 系统优化;musl 系统(Alpine)用 TARGET=linux-musl。

4.3 Docker 部署

cat > haproxy.cfg <<EOF
global
    stats socket /var/run/haproxy.sock mode 600 level admin
    stats timeout 2m

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

frontend web
    bind *:80
    default_backend app

backend app
    balance roundrobin
    server web1 10.0.0.11:80 check
    server web2 10.0.0.12:80 check

frontend stats
    bind *:8404
    stats enable
    stats uri /stats
    stats admin if TRUE
EOF

docker run -d --name haproxy --restart=unless-stopped \
  -p 80:80 -p 8404:8404 \
  -v $PWD/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro \
  haproxy:lts

4.4 最小 haproxy.cfg 示例

global
    log /dev/log local0
    log /dev/log local1 notice
    daemon

defaults
    log global
    mode http
    option httplog
    option dontlognull
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

frontend http_in
    bind *:80
    default_backend web_backend

backend web_backend
    balance roundrobin
    option healthcheck
    server s1 127.0.0.1:8080 check inter 5s rise 2 fall 3
    server s2 127.0.0.1:8081 check inter 5s rise 2 fall 3

listen stats
    bind *:8404
    stats enable
    stats uri /
    stats auth admin:yourpassword
# 检查配置语法
haproxy -f haproxy.cfg -c
# 前台启动测试
haproxy -f haproxy.cfg -db
# 后台启动
haproxy -f haproxy.cfg -D
# 热加载(不中断连接)
sudo systemctl reload haproxy

4.5 systemd 常驻

Debian/Ubuntu 安装包已经带 systemd unit,直接 sudo systemctl enable --now haproxy 即可。从源码编译时,可把 contrib/systemd/haproxy.service 复制到 /etc/systemd/system/。

4.6 Keepalived 高可用

两台 HAProxy 服务器通过 Keepalived 共享一个 VIP,主节点故障时 VIP 自动漂移到备节点:

sudo apt install -y keepalived
# /etc/keepalived/keepalived.conf 中配置 virtual_ipaddress 为 10.0.0.100
sudo systemctl enable --now keepalived

4.7 生产级 haproxy.cfg 完整示例

下面给出一个同时承担 HTTP/HTTPS 负载均衡、WebSocket、统计页、Prometheus 指标的完整配置:

global
    log /dev/log local0 info
    log /dev/log local1 notice
    daemon
    maxconn 100000
    nbthread 4
    stats socket /var/run/haproxy.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    tune.ssl.default-dh-param 2048

defaults
    log global
    mode http
    option httplog
    option dontlognull
    option forwardfor
    option redispatch
    timeout connect 5s
    timeout client 30s
    timeout server 30s
    timeout tunnel 1h
    timeout http-request 10s
    retries 3

frontend http_in
    bind *:80
    bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
    acl is_stats path_beg /stats
    use_backend stats_backend if is_stats
    default_backend web_backend

backend web_backend
    balance leastconn
    option httpchk GET /healthz HTTP/1.1\r\nHost:\ example.com
    cookie SERVERID insert indirect nocache
    server web1 10.0.0.11:443 ssl verify none check inter 5s rise 2 fall 3 cookie web1
    server web2 10.0.0.12:443 ssl verify none check inter 5s rise 2 fall 3 cookie web2
    server web3 10.0.0.13:443 ssl verify none check inter 5s rise 2 fall 3 cookie web3 backup

backend stats_backend
    stats enable
    stats uri /stats
    stats auth admin:StrongPassword
    stats admin if TRUE

frontend metrics
    bind *:8405
    http-request use-service prometheus-exporter if { path /metrics }

这份配置的关键点:nbthread 4 启用多线程、maxconn 100000 单实例最大连接数、balance leastconn 最少连接算法、cookie SERVERID insert 会话保持、backup 标记 web3 为备用节点、timeout tunnel 1h 支持 WebSocket 长连接、alpn h2,http/1.1 同时支持 HTTP/2 与 HTTP/1.1。

在云原生时代,HAProxy 也常被用来做服务网格数据面的替代方案:相比 Envoy,HAProxy 配置更简单、内存占用更低、性能更稳定。很多公司用 HAProxy 作为 Ingress、API Gateway、东西向流量代理,把它放在 K8s Node 上做 hostNetwork 部署,避免 kube-proxy 的额外一跳。

另外,HAProxy 对长连接的支持非常完善:WebSocket、gRPC stream、SSE、HTTP/2 多路复用都能稳定处理,timeout tunnel 参数专门控制隧道空闲超时。这让它成为即时通讯、实时推送、在线游戏等场景的首选入口层。

五、浏览器端可视化管理

HAProxy 内置了非常强大的统计页(Stats Page),这是它区别于其他负载均衡器的一大亮点。在 haproxy.cfg 中加入:

listen stats
    bind *:8404
    stats enable
    stats uri /haproxy_stats
    stats refresh 5s
    stats auth admin:StrongPassword
    stats admin if TRUE

启动后浏览器访问 http://your-server:8404/haproxy_stats,输入账号密码即可看到:每个 frontend/backend 的实时 QPS、连接数、响应时间、后端服务器 UP/DOWN 状态、健康检查失败次数、5xx 错误率、会话保持信息等。点击后端服务器还可以在浏览器里手动把它设为 MAINT(维护)、DRAIN(排水)、READY(恢复)。

除了内置统计页,HAProxy 还支持:

  • Prometheus Exporter:通过 prometheus-exporter 模块暴露 /metrics 端点,把指标接入 Prometheus + Grafana。Grafana 官方 Dashboard ID 为 2428、9365。
  • Runtime API:在 global 段配置 stats socket /var/run/haproxy.sock mode 660 level admin,然后 echo "show stat" | socat stdio /var/run/haproxy.sock 即可在命令行查询所有指标。
  • HAProxy Exporter 容器:社区有 prometheus/haproxy_exporter,把 socket 数据转成 Prometheus 格式。

除了统计页,HAProxy 还可以接入 WASM 插件(3.0+),用 Rust 或 TinyGo 编写自定义请求处理逻辑,性能接近原生 C。它还支持 SPOE(Stream Processing Offload Engine)把每个请求转发给外部鉴权服务(如 Open Policy Agent),根据鉴权结果决定放行或拒绝,这是大型企业做零信任网关的常用方案。

在浏览器端,除了官方统计页,社区还有 HAProxy Dashboard 等开源面板,把 socket 数据聚合成更美观的图表。Grafana 官方 Dashboard ID 9365 专门为 HAProxy Exporter 设计,能展示 QPS、P50/P95/P99 延迟、5xx 率、后端健康度、stick-table 大小等关键指标。

六、API 用法

HAProxy 本身不是 API 服务器,但它提供三种可编程接口:Stats HTTP、Runtime Socket、Lua。

6.1 用 curl 查询统计页(CSV 格式)

curl -u admin:StrongPassword http://127.0.0.1:8404/haproxy_stats;csv

返回 CSV 包含每个后端服务器的 status、weight、bin、bout、rate、hrsp_5xx 等字段。

6.2 通过 Runtime Socket 动态调整

# 列出所有后端
echo "show stat" | socat stdio /var/run/haproxy.sock
# 把 s1 设为维护模式
echo "set server web_backend/s1 state maint" | socat stdio /var/run/haproxy.sock
# 把 s1 权重调到 0(不引流但保持健康检查)
echo "set server web_backend/s1 weight 0" | socat stdio /var/run/haproxy.sock
# 恢复
echo "set server web_backend/s1 state ready" | socat stdio /var/run/haproxy.sock
echo "set server web_backend/s1 weight 1" | socat stdio /var/run/haproxy.sock

6.3 用 curl 做负载均衡验证

for i in $(seq 1 10); do
  curl -s http://127.0.0.1/ | grep -oE "s[12]"
done
# 应该轮询输出 s1 和 s2

6.4 Lua 脚本扩展

# global 段加入
#   lua-load /etc/haproxy/rewrite.lua
# rewrite.lua 内容:
core.register_action("my_rewrite", { "http-req" }, function(txn)
    local path = txn.sf:path()
    txn:set_path("/api" .. path)
end)

# frontend 中调用
#   http-request use-service lua.my_rewrite

6.5 限流与黑白名单

frontend web
    acl bad_ip src 1.2.3.4
    http-request deny if bad_ip
    stick-table type ip size 100k expire 30s store http_req_rate(10s)
    http-request track-sc0 src
    http-request deny deny_status 429 if { sc_http_req_rate(0) gt 50 }

6.6 用 curl 验证 HTTPS 终止与会话保持

# 验证 TLS 证书
curl -vI https://example.com/ 2>&1 | grep -E "subject|issuer|SSL"

# 验证会话保持(cookie)
curl -c /tmp/cj -b /tmp/cj http://127.0.0.1/ | grep -oE "s[123]"
# 多次请求应一直命中同一个后端

6.7 与 Keepalived 配合的 VIP 漂移验证

# 在主节点上
ip a | grep 10.0.0.100
# 停掉主节点的 haproxy
sudo systemctl stop haproxy
# 备节点应在 3 秒内接管 VIP
ssh backup-node "ip a | grep 10.0.0.100"

七、常见问题 FAQ 与相关链接

Q1:haproxy -c 报 "parsing [/etc/haproxy/haproxy.cfg:NN] : ..."。
A:按提示行号查看配置,常见错误是括号不匹配、server 行末尾缺 check、mode 不一致。修改后必须 haproxy -c 验证再 reload。

Q2:后端服务器一直显示 DOWN。
A:检查后端服务器是否真的监听、防火墙是否放行、健康检查路径是否正确。可以在 backend 加 option httpchk GET /healthz 并在 server 行加 check inter 2s rise 2 fall 3。用 echo "show stat" | socat stdio /var/run/haproxy.sock 查看检查失败原因。

Q3:80/443 端口启动失败 "Permission denied"。
A:HAProxy 以非 root 用户运行时需要 setcap cap_net_bind_service=+ep /usr/local/sbin/haproxy,或在 systemd unit 中加 AmbientCapabilities=CAP_NET_BIND_SERVICE。

Q4:如何做 WebSocket 负载均衡?
A:在 backend 中加 option httpchk,frontend 加 timeout tunnel 1h,并确保 mode http。HAProxy 原生支持 Upgrade: websocket 头。

Q5:如何终止 SSL?
A:frontend 中 bind *:443 ssl crt /etc/haproxy/certs/my.pem,pem 文件由证书+私钥+中间证书拼接而成。

Q6:热加载会断连吗?
A:HAProxy 1.8+ 支持无缝 reload(zero-downtime),旧进程会处理完存量连接再退出。但必须用 systemctl reload haproxy 或 kill -USR2 $(cat /var/run/haproxy.pid),不能直接 restart。

Q7:如何把 HAProxy 接入 Prometheus?
A:编译时加 USE_PROMEX=1,在 defaults 段加 prometheus-exporter,frontend 加 bind *:8405; http-request use-service prometheus-exporter if { path /metrics }。

Q8:HAProxy 与 Nginx 如何选择?
A:纯静态 Web 服务、反向代理、TLS 终止选 Nginx;高并发负载均衡、健康检查、会话保持、四层 TCP 代理、MySQL 代理选 HAProxy。大厂通常两者组合:Nginx 做静态与 TLS,HAProxy 做七层负载均衡。

Q9:如何做灰度发布(按权重切流)?
A:在 backend 中给不同 server 设置不同 weight,例如 server v1 10.0.0.11:80 weight 90、server v2 10.0.0.12:80 weight 10。然后通过 Runtime API 动态调整:echo "set server web_backend/v2 weight 50" | socat stdio /var/run/haproxy.sock,无需 reload 即可逐步切流。

Q10:如何做基于 URL 的路由?
A:使用 ACL:api_acl path_beg /api/,然后 use_backend api_backend if api_acl。HAProxy 的 ACL 非常强大,支持 path、host、header、cookie、source IP、regex 等多种匹配条件。

Q11:如何限制单 IP 并发连接数?
A:使用 stick-table:stick-table type ip size 1m expire 30s store conn_cur,然后 tcp-request track-sc0 src、tcp-request reject if { sc_conn_cur(0) gt 50 }。

Q12:HAProxy 能做 MySQL 读写分离吗?
A:可以。在 mode tcp 下,根据 MySQL 命令(COM_QUERY 包含 SELECT/UPDATE)做路由,但这种方式比较脆弱,生产环境更推荐用 ProxySQL。

Q13:日志里的 "TW" 是什么意思?
A:TCP 状态机中的 TIME_WAIT,说明连接是由客户端主动关闭的。如果 TW 数量很高,说明短连接过多,建议开启 keep-alive 或在客户端复用连接。

Q14:如何在 Docker 里暴露 Runtime Socket?
A:把 /var/run/haproxy.sock 挂载到宿主机:-v /tmp/haproxy.sock:/var/run/haproxy.sock,然后宿主机 echo "show stat" | socat stdio /tmp/haproxy.sock。

Q15:如何把访问日志输出到 JSON?
A:在 log 段使用 log-format '{"t":%Ts,"src":%ci,"req":"%r","status":%ST,"dur":%TR,"up":"%U"}',然后配合 filebeat 采集到 Elasticsearch。

Q16:HAProxy 能做 CDN 回源吗?
A:可以。把 CDN 回源地址指向 HAProxy 的 443 端口,HAProxy 根据 Host 头路由到不同业务后端,再配合缓存(通过 Nginx 或 Varnish)即可。

Q17:单机最大能扛多少 QPS?
A:官方基准测试显示,HAProxy 在 8 核 CPU 上可以轻松处理 50k+ HTTP QPS、数十万并发连接。实际瓶颈通常在后端应用而不是 HAProxy 本身。

相关链接:

评论交流

文章目录