1、系统优化准备

调整系统参数,避免高并发时会出现性能问题

# /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

修改limits

# /etc/security/limits.d/99-haproxy.conf
haproxy soft nofile 1048576
haproxy hard nofile 1048576
haproxy soft nproc 65535
haproxy hard nproc 65535

2、核心配置详解

global:主要是配置相关进程及安全配置相关的参数 ,性能调整相关参数,Debug参数

proxies:代理配置段

  • defaults:为frontend, backend, listen提供默认配置。为前端和后端提供默认的配置参数,这些参数可以被后续级别的配置覆盖

  • frontend:前端,相当于nginx中的server {}。定义了客户端请求的接收方式以及如何将请求转发至后端服务器组

  • backend:后端,相当于nginx中的upstream {}。指定了实际服务器的相关配置,如服务器列表、负载均衡策略等

  • listen:同时拥有前端和后端配置,配置简单,生产推荐使用

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

defaults默认配置

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

frontend:前端配置

# 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 端口
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

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

状态监控页面

# 统计页面 - 生产环境建议限制访问 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 }

启动与验证

# 检查配置语法
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

# 查看后端状态
echo "show stat" | socat stdio /run/haproxy/admin.sock

实际生产环境配置

# /etc/haproxy/haproxy.cfg
# 电商平台负载均衡配置 - HAProxy 3.0.5
# 最后更新: 2025-01-07

global
    log /dev/log local0 info
    user haproxy
    group haproxy
    daemon

    # 8核服务器配置
    nbthread 8
    cpu-map auto:1/1-8 0-7
    maxconn 200000

    # SSL 加固
    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"

# HTTP 入口
frontend http_in
    bind *:80

    # 强制跳转 HTTPS
    http-request redirect scheme https unless { ssl_fc }

# HTTPS 入口
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

    # 限流规则:单 IP 每 10 秒最多 200 请求,最多 50 并发
    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 定义
    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 is_search path_beg /search/

    # 管理后台限制 IP
    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
    use_backend search_backend if is_search
    default_backend web_backend

# Web 后端 - 主站页面
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
    server web04 10.10.1.14:8080 weight 100 cookie s4 check inter 3s fall 3 rise 2

# API 后端 - 接口服务
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
    server api03 10.10.2.13:3000 check inter 2s fall 2 rise 2 maxconn 2000
    server api04 10.10.2.14: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

# 搜索服务后端
backend search_backend
    balance roundrobin

    option httpchk GET /search/health HTTP/1.1\r\nHost:\ localhost
    http-check expect status 200

    timeout server 30s  # 搜索服务响应可能较慢

    server search01 10.10.4.11:9200 check inter 5s fall 3 rise 2
    server search02 10.10.4.12:9200 check inter 5s fall 3 rise 2

# 监控页面
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 }

案例配置

灰度发布

我们做 AB 测试时,需要把 10% 的流量导到新版本:

backend web_backend
    balance roundrobin

    # 灰度发布:10% 流量到新版本
    # 使用 ACL 基于 cookie 或随机数分流
    acl is_canary rand(100) lt 10
    acl has_canary_cookie req.cook(canary) -m found

    # 设置灰度 cookie
    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 web02 10.10.1.12:8080 check
    server canary01 10.10.1.21:80

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

基于请求头的A/B测试

frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/

    # 检测 A/B 测试标识
    acl ab_test_v2 hdr(X-AB-Test) -i v2
    acl ab_test_v2 req.cook(ab_version) v2

    use_backend web_v2 if ab_test_v2
    default_backend web_v1

backend web_v1
    balance roundrobin
    server v1_01 10.10.1.11:8080 check
    server v1_02 10.10.1.12:8080 check

backend web_v2
    balance roundrobin
    server v2_01 10.10.2.11:8080 check
    server v2_02 10.10.2.12:8080 check

最佳实践和注意事项

最佳实践

1. 健康检查优化

别用简单的 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

2. 连接复用策略

# 安全模式 - 只复用空闲连接
http-reuse safe

# 激进模式 - 复用所有连接(要确保后端支持)
http-reuse aggressive

# 对于 HTTP/2 后端
http-reuse always

3. 优雅下线

上线前先把服务器设置为 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

4. 日志优化

默认日志太简单,建议用自定义格式:

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"}'

注意事项

错误类型

现象

原因

解决方案

502 Bad Gateway

间歇性出现

后端响应超时

增加 timeout server,检查后端性能

503 Service Unavailable

所有请求失败

所有后端都 down 了

检查健康检查配置,确认后端服务状态

连接数耗尽

新请求被拒绝

maxconn 设置太小

增加 maxconn,优化后端处理速度

Cookie 丢失

会话不保持

Cookie 配置错误

检查 cookie 配置,注意 secure 属性

SSL 握手失败

HTTPS 无法访问

证书链不完整

检查证书链,确保包含中间证书

内存持续增长

进程内存越来越大

长连接泄露

检查 timeout tunnel,升级到最新版本

CPU 单核跑满

性能不理想

没开多线程

配置 nbthread 参数

踩坑经历分享:

有一次线上出现大量 502 错误,排查了半天发现是后端服务在处理某些大请求时超过了 30 秒的默认超时。改了 timeout server 后问题解决。教训就是:超时时间要根据业务实际情况设置,不能一刀切。

还有一次更坑的,开了 http-reuse aggressive 后,部分请求串数据了。后来发现是后端有个老服务不支持 HTTP Keep-Alive 连接复用。所以上线新配置前,一定要在测试环境充分验证。

故障排查和监控

故障排查

查看实时日志:

# 配置 rsyslog
cat > /etc/rsyslog.d/haproxy.conf << 'EOF'
$AddUnixListenSocket /dev/log

# HAProxy 日志单独存放
if $programname startswith 'haproxy' then /var/log/haproxy/haproxy.log
& stop
EOF

systemctl restart rsyslog

# 实时查看
tail -f /var/log/haproxy/haproxy.log

使用 Runtime API 排查:

# 查看所有后端状态
echo "show stat" | socat stdio /run/haproxy/admin.sock

# 查看当前会话
echo "show sess" | socat stdio /run/haproxy/admin.sock

# 查看错误统计
echo "show errors" | socat stdio /run/haproxy/admin.sock

# 查看后端队列
echo "show pools" | socat stdio /run/haproxy/admin.sock

# 查看服务器详细信息
echo "show servers state" | socat stdio /run/haproxy/admin.sock

常用排查命令:

# 检查端口监听
ss -tlnp | grep haproxy

# 检查连接数
ss -s

# 检查 TIME_WAIT 连接
ss -ant | grep TIME-WAIT | wc -l

# 抓包分析
tcpdump -i any port 80 -nn -w haproxy.pcap

性能监控

Prometheus 集成:

HAProxy 3.0 内置了 Prometheus exporter,直接访问 /metrics 端口就能获取指标:

# haproxy.cfg 中配置
frontend stats
    bind *:8404
    http-request use-service prometheus-exporter if { path /metrics }

关键监控指标:

# 必须监控的指标
haproxy_frontend_current_sessions: 当前活跃会话数
haproxy_frontend_http_requests_total: 请求总数
haproxy_backend_active_servers: 活跃后端数量
haproxy_backend_http_responses_total: 后端响应统计(按状态码)
haproxy_backend_response_time_average_seconds: 平均响应时间
haproxy_server_status: 服务器状态(1=UP, 0=DOWN)
haproxy_server_current_queue: 服务器当前队列长度

# 报警阈值建议
活跃会话数 > maxconn * 0.8: 警告
后端服务器状态变化: 立即报警
5xx 错误率 > 1%: 警告
平均响应时间 > 2s: 警告

Grafana Dashboard:

推荐使用官方 Dashboard ID: 12693,包含了 HAProxy 的核心指标可视化。

备份与恢复

配置备份:

#!/bin/bash
# /usr/local/bin/haproxy-backup.sh

BACKUP_DIR="/backup/haproxy"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p ${BACKUP_DIR}

# 备份配置
tar czf ${BACKUP_DIR}/haproxy_config_${DATE}.tar.gz \
    /etc/haproxy/ \
    /etc/sysctl.d/99-haproxy.conf \
    /etc/security/limits.d/99-haproxy.conf

# 备份证书
tar czf ${BACKUP_DIR}/haproxy_certs_${DATE}.tar.gz \
    /etc/haproxy/certs/

# 保留最近 30 天的备份
find ${BACKUP_DIR} -type f -mtime +30 -delete

快速恢复流程:

# 1. 安装 HAProxy(同版本)
# 2. 恢复配置
tar xzf haproxy_config_${DATE}.tar.gz -C /
tar xzf haproxy_certs_${DATE}.tar.gz -C /

# 3. 验证配置
haproxy -c -f /etc/haproxy/haproxy.cfg

# 4. 启动服务
systemctl start haproxy

附录

A. 命令速查表

命令

说明

haproxy -c -f /etc/haproxy/haproxy.cfg

检查配置语法

haproxy -vv

查看编译选项和版本

systemctl reload haproxy

平滑重载配置

echo "show stat" | socat stdio /run/haproxy/admin.sock

查看统计信息

echo "show info" | socat stdio /run/haproxy/admin.sock

查看进程信息

echo "set server backend/server state drain" | socat stdio /run/haproxy/admin.sock

设置服务器为 drain 模式

echo "set server backend/server state maint" | socat stdio /run/haproxy/admin.sock

设置服务器为维护模式

echo "set server backend/server state ready" | socat stdio /run/haproxy/admin.sock

恢复服务器

echo "disable server backend/server" | socat stdio /run/haproxy/admin.sock

禁用服务器

echo "enable server backend/server" | socat stdio /run/haproxy/admin.sock

启用服务器

B. 配置参数详解

参数

默认值

推荐值

说明

maxconn

2000

根据内存调整

全局最大连接数,每连接约 32KB

nbthread

1

CPU 核心数

工作线程数,不超过 64

timeout connect

5s

5s

连接后端超时

timeout client

50s

60s

客户端超时

timeout server

50s

60s

服务端超时

timeout http-request

10s

10s

HTTP 请求超时

timeout http-keep-alive

1s

10-30s

Keep-Alive 超时

tune.bufsize

16384

32768

缓冲区大小

tune.maxrewrite

1024

1024

最大重写空间

tune.http.maxhdr

101

128

最大 HTTP 头数量

C. 术语表

术语

解释

Frontend

前端,接收客户端请求的入口

Backend

后端,处理请求的服务器组

ACL

Access Control List,访问控制列表,用于定义匹配规则

Server

后端服务器节点

Sticky Session

会话保持,确保同一用户请求发到同一后端

Health Check

健康检查,定期检测后端服务器状态

Runtime API

运行时 API,用于动态管理 HAProxy

Drain

排空模式,停止接收新连接但处理完现有连接

Maintenance

维护模式,完全停止服务

Weight

权重,用于加权负载均衡

参考资料:
  • HAProxy 官方文档: https://docs.haproxy.org/

  • HAProxy 3.0 配置手册: https://www.haproxy.org/download/3.0/doc/configuration.txt

  • HAProxy Enterprise Blog: https://www.haproxy.com/blog/

  • HAProxy GitHub: https://github.com/haproxy/haproxy

转载:https://mp.weixin.qq.com/s/PqkaS1u5cIgNaRMsKcjepw