搞负载均衡这么多年,HAProxy一直是我心目中的“瑞士军刀”。从最早的1.4版本用到现在,看着它从一个单纯的TCP/HTTP代理,进化成了支持QUIC、HTTP/3的现代化负载均衡器。很多人一提负载均衡就想到Nginx,但在纯粹的代理转发场景下,HAProxy的性能和功能细粒度控制是Nginx比不了的。我在某电商平台做过对比测试,同等硬件条件下,HAProxy的QPS能高出约15-20%,而且高并发时CPU占用更低。
它的核心优势在于专注。不像Nginx要兼顾Web服务器功能,HAProxy所有的设计都围绕着“如何更高效地转发请求”,这种专注带来的就是更直观的配置和更极致的性能。
一、HAProxy 3.0 新特性与适用场景
HAProxy 3.0相比之前版本有几个值得关注的更新,尤其是在性能和可管理性上:
- 原生QUIC/HTTP3支持:终于不用再依赖第三方补丁了。虽然标记为实验性,但在我们的测试环境里跑了三个月,稳定性没问题。
- 成熟的多线程架构:从2.x开始的多线程模型在3.0里彻底稳定了。以前担心的锁竞争问题基本解决,
nbthread参数可以放心大胆地用。
- 增强的运行时API:通过Runtime API可以实现不重启热更新后端服务器,这在微服务动态伸缩的场景下太实用了。
- 优化的内存管理:新的内存池机制让长连接场景下的内存占用更稳定。
根据我的实战经验,HAProxy最适合以下场景:
- API网关:需要精细化流量控制、限流、熔断的场景。
- 微服务入口:支持服务发现集成,动态后端管理。
- 数据库代理:MySQL/PostgreSQL读写分离、连接池管理。
- WebSocket长连接:稳定的长连接保持能力是强项。
- 高性能HTTP代理:追求极致转发性能的场景。
不太适合的场景:需要复杂URL重写、静态文件服务(这些交给Nginx更合适)。
环境要求参考
| 组件 |
版本 |
说明 |
| HAProxy |
3.0.5 |
2025年1月稳定版 |
| 操作系统 |
Rocky Linux 9.3 / Ubuntu 24.04 LTS |
推荐使用Rocky Linux |
| 内核版本 |
5.14+ |
需要支持io_uring |
| CPU |
4核+ |
生产环境建议8核起步 |
| 内存 |
4GB+ |
根据连接数调整,每个连接约32KB |
| GCC |
12+ |
编译安装时需要 |
| OpenSSL |
3.0+ |
QUIC支持需要 |
二、从系统优化到HAProxy安装部署
在安装HAProxy之前,先调好系统参数。这些参数在生产环境高并发时至关重要,不调可能会出各种奇怪的问题。
2.1 系统内核与资源优化
首先,调整系统参数,创建一个配置文件 /etc/sysctl.d/99-haproxy.conf:
# /etc/sysctl.d/99-haproxy.conf
# 文件描述符相关
fs.file-max = 2097152
fs.nr_open = 2097152
# 网络核心参数
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 262144
net.core.wmem_default = 262144
# TCP 参数优化
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_tw_buckets = 1440000
net.ipv4.ip_local_port_range = 1024 65535
# 开启 TCP Fast Open
net.ipv4.tcp_fastopen = 3
# 连接追踪(如果用 iptables)
net.netfilter.nf_conntrack_max = 1048576
应用配置:
sysctl -p /etc/sysctl.d/99-haproxy.conf
然后,修改进程资源限制,创建文件 /etc/security/limits.d/99-haproxy.conf:
# /etc/security/limits.d/99-haproxy.conf
haproxy soft nofile 1048576
haproxy hard nofile 1048576
haproxy soft nproc 65535
haproxy hard nproc 65535
这些调优是构建高性能代理服务的基础,涉及到核心的 网络/系统 参数。
2.2 安装 HAProxy 3.0
Rocky Linux 9的官方仓库版本可能较老,建议使用官方仓库或源码编译。
方法一:使用官方仓库安装(推荐)
# 添加 HAProxy 官方仓库
dnf install -y epel-release
dnf copr enable -y bors/haproxy
# 安装 HAProxy 3.0
dnf install -y haproxy30
方法二:源码编译安装(追求极致性能与控制)
# 安装依赖
dnf install -y gcc make pcre2-devel openssl-devel systemd-devel \
lua-devel readline-devel zlib-devel
# 下载源码
cd /usr/local/src
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
# 编译参数说明:
# TARGET=linux-glibc: 使用 glibc
# USE_OPENSSL=1: 启用 SSL 支持
# USE_PCRE2=1: 使用 PCRE2 正则库
# USE_SYSTEMD=1: 启用 systemd 集成
# USE_LUA=1: 启用 Lua 脚本支持
# USE_QUIC=1: 启用 QUIC/HTTP3(实验性)
# USE_PROMEX=1: 启用 Prometheus 导出器
make -j$(nproc) TARGET=linux-glibc \
USE_OPENSSL=1 USE_PCRE2=1 USE_SYSTEMD=1 \
USE_LUA=1 USE_QUIC=1 USE_PROMEX=1 \
USE_THREAD=1
make install PREFIX=/usr/local/haproxy
对于编译安装,需要创建systemd服务文件 /etc/systemd/system/haproxy.service:
# /etc/systemd/system/haproxy.service
[Unit]
Description=HAProxy Load Balancer
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
EnvironmentFile=-/etc/sysconfig/haproxy
ExecStartPre=/usr/local/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c -q
ExecStart=/usr/local/haproxy/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID
KillMode=mixed
Restart=always
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
三、核心配置模块详解与实战示例
HAProxy配置分为四大块:global、defaults、frontend、backend。理解这个结构是玩转它的基础。
3.1 全局配置 (Global)
/etc/haproxy/haproxy.cfg 的全局部分,定义了进程级别的参数。
global
# 日志配置 - 发送到本地 rsyslog
log /dev/log local0 info
log /dev/log local1 notice
# 运行身份
user haproxy
group haproxy
# 后台运行
daemon
# 多线程配置 - 关键参数
# nbthread 建议设置为 CPU 核心数,但不超过 64
nbthread 8
# CPU 绑定 - 减少上下文切换
cpu-map auto:1/1-8 0-7
# 最大连接数 - 根据内存调整
# 每个连接大约占用 32KB 内存
maxconn 100000
# SSL 配置
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
# 运行时 API - 用于动态管理
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
# 性能调优
tune.ssl.default-dh-param 2048
tune.bufsize 32768
tune.maxrewrite 1024
tune.http.maxhdr 128
# Lua 脚本路径
lua-load /etc/haproxy/lua/init.lua
3.2 默认配置 (Defaults)
为后续的frontend和backend设置默认值。
defaults
# 工作模式:http 或 tcp
mode http
# 继承全局日志配置
log global
# 记录 HTTP 请求日志
option httplog
# 不记录空连接
option dontlognull
# 启用 HTTP 连接关闭
option http-server-close
# 转发客户端 IP
option forwardfor except 127.0.0.0/8
# 后端服务器健康检查失败时重新派发
option redispatch
retries 3
# 超时配置 - 生产环境调优后的结果
timeout connect 5s # 连接后端超时
timeout client 60s # 客户端超时
timeout server 60s # 服务端超时
timeout http-request 10s # HTTP 请求超时
timeout http-keep-alive 10s # Keep-Alive 超时
timeout queue 30s # 队列等待超时
timeout check 5s # 健康检查超时
# 错误文件
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
3.3 前端配置 (Frontend)
定义客户端如何连接进来,并进行初步的流量分类和策略应用。
HTTP前端 (端口80)
# HTTP 前端 - 80 端口
frontend http_front
bind *:80
# 定义 ACL 规则
acl is_api path_beg /api/
acl is_static path_end .css .js .png .jpg .gif .ico
acl is_websocket hdr(Upgrade) -i WebSocket
# 根据 Host 头分流
acl host_app1 hdr(host) -i app1.example.com
acl host_app2 hdr(host) -i app2.example.com
# 限流 ACL - 每个 IP 每秒最多 100 个请求
stick-table type ip size 100k expire 30s store http_req_rate(10s)
acl is_abuse sc_http_req_rate(0) gt 100
http-request deny deny_status 429 if is_abuse
http-request track-sc0 src
# 添加请求头
http-request set-header X-Forwarded-Proto http
http-request set-header X-Real-IP %[src]
# 路由规则
use_backend api_servers if is_api
use_backend static_servers if is_static
use_backend ws_servers if is_websocket
use_backend app1_servers if host_app1
use_backend app2_servers if host_app2
# 默认后端
default_backend web_servers
HTTPS前端 (端口443)
# HTTPS 前端 - 443 端口
frontend https_front
# 绑定 443 端口,启用 SSL
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
# HTTP/2 相关配置
http-request set-header X-Forwarded-Proto https
# HSTS 头
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains"
# 复用 HTTP 前端的 ACL 和路由
acl is_api path_beg /api/
use_backend api_servers if is_api
default_backend web_servers
3.4 后端配置 (Backend)
定义请求被转发到哪一组服务器,以及该组服务器间的负载均衡策略。这里可以看到它如何与后端 数据库/中间件/技术栈 协同工作。
Web服务器后端
backend web_servers
# 负载均衡算法
balance roundrobin
# 会话保持 - 基于 cookie
cookie SERVERID insert indirect nocache
# HTTP 健康检查
option httpchk GET /health HTTP/1.1\r\nHost:\ localhost
http-check expect status 200
# 后端服务器列表
# weight: 权重
# check: 启用健康检查
# inter: 检查间隔
# fall: 连续失败次数标记为 down
# rise: 连续成功次数标记为 up
server web1 192.168.1.11:8080 weight 100 cookie web1 check inter 3s fall 3 rise 2
server web2 192.168.1.12:8080 weight 100 cookie web2 check inter 3s fall 3 rise 2
server web3 192.168.1.13:8080 weight 100 cookie web3 check inter 3s fall 3 rise 2
# 备用服务器 - 所有主服务器 down 时启用
server web_backup 192.168.1.20:8080 backup
API服务器后端
backend api_servers
balance leastconn # API 适合用最少连接算法
option httpchk GET /api/health HTTP/1.1\r\nHost:\ localhost
http-check expect status 200
# 连接复用 - 减少后端连接数
http-reuse safe
# 重试配置
retry-on conn-failure empty-response response-timeout
server api1 192.168.1.21:3000 check inter 2s fall 2 rise 2 maxconn 1000
server api2 192.168.1.22:3000 check inter 2s fall 2 rise 2 maxconn 1000
WebSocket后端
backend ws_servers
balance source # WebSocket 需要会话保持
# WebSocket 超时要设长一些
timeout tunnel 3600s
timeout server 3600s
server ws1 192.168.1.31:8080 check
server ws2 192.168.1.32:8080 check
静态资源后端
backend static_servers
balance roundrobin
# 静态资源可以开启压缩
compression algo gzip
compression type text/html text/css text/javascript application/javascript
# 缓存头
http-response set-header Cache-Control "public, max-age=86400"
server static1 192.168.1.41:80 check
server static2 192.168.1.42:80 check
3.5 状态监控页面
# 统计页面 - 生产环境建议限制访问 IP
frontend stats
bind *:8404
mode http
# IP 白名单
acl allowed_ip src 10.0.0.0/8 192.168.0.0/16
http-request deny unless allowed_ip
stats enable
stats uri /stats
stats refresh 10s
stats admin if TRUE
stats auth admin:your_secure_password
# Prometheus 指标导出
http-request use-service prometheus-exporter if { path /metrics }
四、启动验证与生产级完整配置示例
4.1 启动与基础验证
# 检查配置语法
haproxy -c -f /etc/haproxy/haproxy.cfg
# 启动服务
systemctl daemon-reload
systemctl enable haproxy
systemctl start haproxy
# 查看状态
systemctl status haproxy
# 查看监听端口
ss -tlnp | grep haproxy
# 测试健康检查
curl -I http://localhost/health
# 查看后端状态(使用Runtime API)
echo "show stat" | socat stdio /run/haproxy/admin.sock
4.2 生产环境完整配置示例
这是一个来自某电商平台的真实配置精简版,日均处理数百万请求。
# /etc/haproxy/haproxy.cfg
# 电商平台负载均衡配置 - HAProxy 3.0.5
global
log /dev/log local0 info
user haproxy
group haproxy
daemon
nbthread 8
cpu-map auto:1/1-8 0-7
maxconn 200000
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384
ssl-default-bind-options ssl-min-ver TLSv1.2
stats socket /run/haproxy/admin.sock mode 660 level admin
tune.bufsize 32768
tune.http.maxhdr 128
tune.ssl.default-dh-param 2048
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor
option redispatch
retries 3
timeout connect 5s
timeout client 60s
timeout server 60s
timeout http-request 10s
timeout http-keep-alive 30s
timeout queue 30s
log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
frontend http_in
bind *:80
http-request redirect scheme https unless { ssl_fc }
frontend https_in
bind *:443 ssl crt /etc/haproxy/certs/example.com.pem alpn h2,http/1.1
http-response set-header X-Frame-Options SAMEORIGIN
http-response set-header X-Content-Type-Options nosniff
http-response set-header X-XSS-Protection "1; mode=block"
http-response set-header Strict-Transport-Security "max-age=31536000"
stick-table type ip size 200k expire 30s store http_req_rate(10s),conn_cur
acl is_rate_limited sc_http_req_rate(0) gt 200
acl is_conn_limited sc_conn_cur(0) gt 50
http-request track-sc0 src
http-request deny deny_status 429 if is_rate_limited
http-request deny deny_status 429 if is_conn_limited
acl is_api path_beg /api/
acl is_admin path_beg /admin/
acl is_static path_end .css .js .png .jpg .jpeg .gif .ico .woff .woff2
acl admin_ip src 10.10.0.0/16
http-request deny if is_admin !admin_ip
use_backend api_backend if is_api
use_backend static_backend if is_static
default_backend web_backend
backend web_backend
balance roundrobin
cookie WEBID insert indirect nocache httponly secure
option httpchk GET /health HTTP/1.1\r\nHost:\ localhost
http-check expect status 200
http-reuse safe
server web01 10.10.1.11:8080 weight 100 cookie s1 check inter 3s fall 3 rise 2
server web02 10.10.1.12:8080 weight 100 cookie s2 check inter 3s fall 3 rise 2
server web03 10.10.1.13:8080 weight 100 cookie s3 check inter 3s fall 3 rise 2
backend api_backend
balance leastconn
option httpchk GET /api/health HTTP/1.1\r\nHost:\ localhost
http-check expect status 200
http-reuse aggressive
retry-on conn-failure empty-response response-timeout 502 503 504
server api01 10.10.2.11:3000 check inter 2s fall 2 rise 2 maxconn 2000
server api02 10.10.2.12:3000 check inter 2s fall 2 rise 2 maxconn 2000
backend static_backend
balance roundrobin
compression algo gzip
compression type text/css text/javascript application/javascript application/json
http-response set-header Cache-Control "public, max-age=604800"
server static01 10.10.3.11:80 check
server static02 10.10.3.12:80 check
frontend stats
bind *:8404
mode http
acl internal_net src 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
http-request deny unless internal_net
stats enable
stats uri /stats
stats refresh 5s
stats admin if TRUE
stats auth admin:Ecm@2025$Prod
http-request use-service prometheus-exporter if { path /metrics }
五、高级应用场景与故障排查
5.1 高级应用场景配置
灰度发布(10%流量导流)
backend web_backend
balance roundrobin
# 灰度发布:10% 流量到新版本
acl is_canary rand(100) lt 10
acl has_canary_cookie req.cook(canary) -m found
http-response set-header Set-Cookie "canary=1; Path=/; Max-Age=3600" if is_canary !has_canary_cookie
use-server canary01 if is_canary
use-server canary01 if has_canary_cookie
server web01 10.10.1.11:8080 check
server canary01 10.10.1.21:8080 check weight 0 # weight=0 不参与正常轮询
MySQL读写分离代理
# MySQL 代理配置
frontend mysql_front
bind *:3306
mode tcp
default_backend mysql_write
frontend mysql_read_front
bind *:3307
mode tcp
default_backend mysql_read
backend mysql_write
mode tcp
balance first # 写操作只发到第一个可用节点(主库)
option mysql-check user haproxy
server mysql_master 10.10.5.11:3306 check inter 3s fall 3 rise 2
backend mysql_read
mode tcp
balance leastconn
option mysql-check user haproxy
server mysql_slave1 10.10.5.12:3306 check inter 3s fall 3 rise 2 weight 100
server mysql_slave2 10.10.5.13:3306 check inter 3s fall 3 rise 2 weight 100
# 主库作为读的备用
server mysql_master 10.10.5.11:3306 check inter 3s fall 3 rise 2 weight 50 backup
5.2 运维最佳实践与故障排查
健康检查优化
别用简单的TCP检查,一定要用HTTP检查,而且要检查真实的业务逻辑。
# 好的健康检查
option httpchk GET /health HTTP/1.1\r\nHost:\ localhost
http-check expect status 200
# 更好的健康检查 - 检查关键依赖
http-check connect
http-check send meth GET uri /health/deep ver HTTP/1.1 hdr Host localhost
http-check expect rstatus ^2
优雅下线服务器
上线前先把服务器设置为drain模式,等连接清空再下线,这是保障服务平滑发布的运维 & 测试关键一步。
# 通过 Runtime API 设置
echo "set server web_backend/web01 state drain" | socat stdio /run/haproxy/admin.sock
# 等待连接数降为 0
echo "show stat" | socat stdio /run/haproxy/admin.sock | grep web01
# 确认后下线
echo "set server web_backend/web01 state maint" | socat stdio /run/haproxy/admin.sock
关键监控与日志
自定义日志格式方便后续分析:
log-format '{"time":"%t","client":"%ci","backend":"%b","server":"%s","status":%ST,"bytes":%B,"time_total":%Ta,"time_connect":%Tc,"time_response":%Tr,"retries":%rc,"request":"%r"}'
内置的Prometheus exporter提供了丰富的指标,关键监控项包括:
haproxy_frontend_current_sessions: 当前活跃会话数
haproxy_backend_active_servers: 活跃后端数量
haproxy_server_status: 服务器状态 (1=UP, 0=DOWN)
- 5xx错误率 > 1% 或平均响应时间 > 2s 需要告警。
常见故障排查表
| 错误现象 |
可能原因 |
解决方案 |
| 间歇性502 Bad Gateway |
后端响应超时 |
增加 timeout server,检查后端性能 |
| 所有请求返回503 |
所有后端健康检查失败 |
检查健康检查配置与后端服务状态 |
| 新请求被拒绝 |
maxconn 全局连接数耗尽 |
增加 maxconn 或优化后端处理速度 |
| 会话Cookie丢失 |
Cookie配置错误或属性冲突 |
检查cookie配置,注意secure、httponly属性 |
| CPU单核跑满 |
未启用多线程 |
配置 nbthread 参数(建议等于CPU核心数) |
有一次线上出现大量502错误,排查发现是后端处理大请求超过了默认的30秒超时。教训就是:超时时间必须根据业务实际情况设置。还有一次更坑,开了http-reuse aggressive后部分请求串数据了,原因是后端有个老服务不支持HTTP Keep-Alive。所以上线新配置前,一定要在测试环境充分验证。
六、总结与进阶
技术要点回顾:
- HAProxy 3.0的多线程模型已成熟,生产环境可放心使用。
- 健康检查务必做到HTTP应用层,TCP检查不足以反映真实状态。
- 所有超时参数 (
timeout server/client等) 必须根据实际业务调整,切忌使用默认值一刀切。
- Runtime API是运维利器,熟练掌握可实现动态、无损的服务管理。
- 自定义日志格式,为后续的监控分析和问题排查铺平道路。
进阶学习方向:
- Lua脚本扩展:实现复杂的流量控制、请求/响应改写逻辑。
- QUIC/HTTP3实战:探索下一代网络协议在负载均衡中的应用与调优。
- Kubernetes服务网格集成:了解HAProxy作为Ingress Controller或服务网格数据平面的角色。
- 安全加固:深入研究WAF规则集成与DDoS防护的高级配置。
掌握HAProxy的配置精髓,能让你在构建高可用、高性能的服务架构时游刃有余。如果在实践中遇到更复杂的问题,欢迎到 云栈社区 与更多的开发者和运维同行一起交流探讨。