
凌晨 2:40,我被监控的电话吵醒。香港机房的接入带宽冲到顶,商城站点(面向内地用户)在秒杀会场开启后的 3 分钟内,TLS 握手时延从 30ms 飙到 200ms,部分页面出现 502。那一刻我很清楚:单点或“主备式”的 HAProxy 已经扛不住双十一/黑五的并发洪峰,必须把入口层重构为多节点、可横向扩展、就地容灾的架构。
这篇文章就是我后来在香港机房从零搭建 HAProxy 多节点集群的完整复盘与操作手册。我把过程中的细节、坑点、以及每一个“现场热修”的动作都写进去:不止能跑起来,还要跑得稳、跑得久、跑得快。
目标架构(概览)
- 地域与线路:香港单机房为主(BGP/CN2/GIA 线路优先,优化内地访问时延与丢包)。
- 入口层:3 台 HAProxy 节点,双 VIP 的 VRRP 设计(Active-Active:A 组与 B 组各一套 VIP,DNS 返回双 A 记录做流量分摊)。
- 后端应用:多台 Nginx/App(10.10.20.0/24),支持健康检查与弹性扩容。
- 会话策略:建议无状态(JWT/Redis),HAProxy 层可选基于 Cookie 的一致性哈希。
- 可观测性:HAProxy stats socket + Prometheus Exporter + 集中日志。
- 灰度/热更新:零停机 reload,分批滚动。
ASCII 示意:
+----------------- 公网 DNS (双A记录, TTL 30s) -----------------+
| |
shop.example.com ---> VIP-A (10.10.10.100) VIP-B (10.10.10.101)
VRRP@node1,node2 VRRP@node2,node3
| |
v v
[HAProxy node1] [HAProxy node3]
| |
+------------------+------------------+
|
[HAProxy node2]
|
+------------+------------+
| Nginx/App 节点池 |
| 10.10.20.11 .12 .13 ... |
+-------------------------+
硬件与网络选型(香港机房)
| 角色 | 机型/CPU | 内存 | 磁盘 | 网卡 | 备注 |
|---|---|---|---|---|---|
| HAProxy 节点 ×3 | Intel Xeon E-2288G(8C/16T)或同级别 | 32–64G | NVMe 480–960G ×2 | 2×10GbE(多队列,支持 RSS/RPS) | 入口层 TLS/HTTP2 压力大,频繁上下文切换,CPU 主频更重要 |
| Nginx/App 池 | Intel Xeon Silver/Gold | 64G+ | NVMe RAID1/DP | 2×10GbE | 靠近 HA 节点,同 VLAN 或低延二层 |
| 线路 | BGP / CN2 GIA/CTGNet 优先 | — | — | — | 跨境丢包敏感,优先选质量与稳定性 |
建议:入口层更看重高主频、网卡队列、中断亲和与内核网络栈,存储不是瓶颈。
IP 规划
| 说明 | 地址/网段 |
|---|---|
| 管理网段 | 10.10.0.0/24 |
| 前端 VIP-A | 10.10.10.100/24 |
| 前端 VIP-B | 10.10.10.101/24 |
| HA 节点 | 10.10.10.11(node1)、.12(node2)、.13(node3) |
| 后端池 | 10.10.20.0/24 |
系统与版本
- OS:CentOS 7.9(用户曾要求统一到 CentOS 7)
- 内核:建议升级到 ELRepo 的 kernel-ml 5.4+,方便开启 BBR/优化 TCP(CentOS 7 默认 3.10 在高并发+TLS 下吃亏)
- HAProxy:2.8 LTS(线程模型成熟,HTTP/2、cache、stick-table 完备)
- Keepalived:2.2+(支持 VRRP,unicast 友好)
- OpenSSL:1.1.1 或 3.0(握手性能、TLS1.3)
一、系统准备与内核优化
1)基础环境
# 时区与时间同步
timedatectl set-timezone Asia/Hong_Kong
yum install -y chrony && systemctl enable --now chronyd
# 基础仓库
yum install -y epel-release yum-utils
yum-config-manager --add-repo https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
2)升级内核(可选但强烈建议)
yum --enablerepo=elrepo-kernel install -y kernel-ml
grub2-set-default 0 && reboot
# 重启后确认
uname -r
3)内核网络栈调优(/etc/sysctl.d/99-hk-haproxy.conf)
cat >/etc/sysctl.d/99-hk-haproxy.conf <<'EOF'
# 提升并发连接与队列
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 250000
net.ipv4.tcp_max_syn_backlog = 262144
# TIME_WAIT/重用
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
# 端口范围
net.ipv4.ip_local_port_range = 10000 65000
# BBR(需要 4.9+ 内核)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# RPF 注意:VRRP 会导致非对称路径,建议关闭严格 RPF
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
# 关闭透明大页
vm.nr_hugepages = 0
EOF
sysctl --system
4)网卡与中断亲和
# 禁止 irqbalance(或保守模式)
systemctl stop irqbalance && systemctl disable irqbalance
# 查看队列与分配 CPU 中断亲和(示例,实际以 /proc/interrupts 为准)
ethtool -l eth0
# 将 RSS 队列中断绑核(示例:绑到 0-7 号核)
for i in /proc/irq/*/smp_affinity_list; do echo 0-7 > $i 2>/dev/null; done
现场经验:入口层 TLS+HTTP2 会触发大量小包与上下文切换,“多队列+中断亲和”能明显压低抖动;irqbalance 在强绑核策略下反而会打乱亲和,建议关掉或保守配置。
二、安装 HAProxy 2.8 LTS(CentOS 7)
CentOS 7 官方仓库版本过旧,建议源码安装(或使用社区可靠的 RPM 仓库)。下面以源码为例:
# 构建依赖
yum groupinstall -y "Development Tools"
yum install -y pcre2-devel zlib-devel systemd-devel lua-devel
# OpenSSL 建议 1.1.1/3.0:可以自编译并安装到 /usr/local/openssl
# 或启用兼容包,本文示例假定头文件可用
# 下载与编译
cd /usr/local/src
curl -LO https://www.haproxy.org/download/2.8/src/haproxy-2.8.5.tar.gz
tar xf haproxy-2.8.5.tar.gz && cd haproxy-2.8.5
make TARGET=linux-glibc \
USE_SYSTEMD=1 USE_LUA=1 USE_PCRE2=1 USE_ZLIB=1 USE_OPENSSL=1 \
CPU=native
make install
# 创建运行用户与目录
useradd -r -s /sbin/nologin haproxy
mkdir -p /etc/haproxy /var/lib/haproxy /var/log/haproxy
chown -R haproxy:haproxy /var/lib/haproxy
systemd 单元:/etc/systemd/system/haproxy.service
[Unit]
Description=HAProxy Load Balancer
After=network.target syslog.target
[Service]
Environment="CONFIG=/etc/haproxy/haproxy.cfg"
ExecStartPre=/usr/local/sbin/haproxy -f $CONFIG -c -q
ExecStart=/usr/local/sbin/haproxy -Ws -f $CONFIG -p /run/haproxy.pid
ExecReload=/usr/local/sbin/haproxy -Ws -f $CONFIG -p /run/haproxy.pid -sf $(cat /run/haproxy.pid)
User=haproxy
Group=haproxy
LimitNOFILE=100000
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
三、Keepalived(VRRP 双 VIP 设计)
目标:用两套 VRRP 实例(VI_A、VI_B)分别保护 VIP-A 与 VIP-B,分布在 3 台节点上,从而实现 Active-Active 的前端能力(DNS 返回两个 A 记录,客户端会自然分摊)。
通信:香港机房多数是 L2 可达,也可用 unicast(避免多播限制)。
安装与配置:
yum install -y keepalived
/etc/keepalived/keepalived.conf(以 node1 为例,node2、node3 分别调整 priority 与 track_script)
vrrp_script chk_haproxy {
script "pidof haproxy"
interval 2
weight -20
}
# VIP-A 由 node1 优先
vrrp_instance VI_A {
state MASTER
interface eth0
virtual_router_id 10
priority 120
advert_int 1
authentication {
auth_type PASS
auth_pass S3cr3tA
}
virtual_ipaddress {
10.10.10.100/24 dev eth0
}
unicast_src_ip 10.10.10.11
unicast_peer {
10.10.10.12
10.10.10.13
}
track_script {
chk_haproxy
}
}
# VIP-B 在 node1 做 BACKUP
vrrp_instance VI_B {
state BACKUP
interface eth0
virtual_router_id 11
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass S3cr3tB
}
virtual_ipaddress {
10.10.10.101/24 dev eth0
}
unicast_src_ip 10.10.10.11
unicast_peer {
10.10.10.12
10.10.10.13
}
track_script {
chk_haproxy
}
}
node2 上让 VI_B 优先(priority 高于其他),node3 做两个实例的次备。这样两套 VIP 分别有各自的 Master,天然实现 Active-Active。
四、HAProxy 配置精讲(HTTP/2、TLS、限流、后端健康)
/etc/haproxy/haproxy.cfg(关键片段,按需调整)
global
log /dev/log local0
log /dev/log local1 notice
user haproxy
group haproxy
daemon
# 线程模式(比多进程易用、共享监听),结合高主频 CPU
nbthread 8
cpu-map auto:1/1-8 0-7
# 连接与缓冲
maxconn 200000
tune.bufsize 32768
tune.ssl.default-dh-param 2048
# 统计与 socket
stats socket /var/run/haproxy.sock mode 660 level admin expose-fd listeners
stats timeout 30s
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5s
timeout client 30s
timeout server 30s
timeout http-request 10s
timeout http-keep-alive 10s
option http-keep-alive
option http-use-htx
http-reuse safe
maxconn 180000
retries 3
# TLS 终止与 HTTP/2
frontend fe_https
bind 10.10.10.100:443 ssl crt /etc/haproxy/certs/shop.pem alpn h2,http/1.1
bind 10.10.10.101:443 ssl crt /etc/haproxy/certs/shop.pem alpn h2,http/1.1
# 安全与性能:选择现代套件(示例,按实际 OpenSSL 版本与合规要求调整)
ssl-default-bind-ciphersuites TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
# 基本防护与限流
stick-table type ip size 1m expire 30s store http_req_rate(10s)
http-request track-sc0 src
acl abuse src_http_req_rate(sc0) gt 200
http-request deny if abuse
# 后端选择与会话保持(无状态优先;如需粘性会话,可用 cookie/hash)
default_backend bk_app
# HTTP 重定向
frontend fe_http
bind 10.10.10.100:80
bind 10.10.10.101:80
http-request redirect scheme https code 301 if !{ ssl_fc }
# 后端池:健康检查、连接复用
backend bk_app
mode http
balance uri consistent
option httpchk GET /healthz
http-check expect status 200
server app1 10.10.20.11:443 ssl verify none check maxconn 5000
server app2 10.10.20.12:443 ssl verify none check maxconn 5000
server app3 10.10.20.13:443 ssl verify none check maxconn 5000
# 管理页面(内网或跳板机访问)
listen stats
bind 10.10.10.11:8404
stats enable
stats uri /stats
stats auth admin:StrongPass!
要点解释
- nbthread:使用线程模型,充分利用多核;cpu-map auto 根据核数映射线程,减少迁移。
- http-reuse safe:在后端安全复用连接,降低握手与队首阻塞。
- stick-table 做简单限流防爆,线上我会配合 WAF 做更细策略。
- 后端示例用的是 HTTPS 回源(ssl verify none),实际请用内网自签 CA 并 verify required ca-file 更安全。
- 健康检查短而频,防止慢故障扩散。
五、证书与 OCSP Stapling
将完整链证书与私钥合并到 /etc/haproxy/certs/shop.pem,按需配置自动续签(如使用 acme.sh + 钩子,在热更新时触发 systemctl reload haproxy)。HAProxy 2.x 能自动完成 OCSP 缓存刷新(取决于编译的 OpenSSL 与配置),生产建议定时检查。
六、日志与监控
rsyslog(本机采集到集中平台)
/etc/rsyslog.d/49-haproxy.conf:
$AddUnixListenSocket /var/lib/haproxy/dev/log
:programname, startswith, "haproxy" /var/log/haproxy/haproxy.log
& stop
HAProxy global 日志指向 /dev/log,并根据需要把 socket 映射到 chroot 或容器。日志轮转记得配 logrotate。
Prometheus Exporter
两种常见方式:
- 直接读取 stats socket 的 /;csv,用 haproxy_exporter。
- 开启 stats socket 并授权只读用户。
- Exporter 以 systemd 服务运行,抓取地址配置为 unix:/var/run/haproxy.sock 或 TCP stats 端口。
七、发布与热更新(零停机)
- 校验配置:haproxy -f /etc/haproxy/haproxy.cfg -c
- 热更新:systemctl reload haproxy(底层是 -sf,平滑切换到新进程)
- 灰度:双 VIP 架构可以先只在 VIP-B 上加载新版本,逐步调小 VIP-A 的权重(DNS 权重或临时只放出一个 A 记录),观察稳定后再切另一边。
八、自动化(Ansible 片段)
roles/haproxy/tasks/main.yml:
- name: Install deps
yum:
name:
- pcre2-devel
- zlib-devel
- systemd-devel
- lua-devel
state: present
- name: Deploy haproxy.cfg
template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
owner: haproxy
group: haproxy
mode: '0644'
notify: reload haproxy
- name: Ensure haproxy running
systemd:
name: haproxy
state: started
enabled: yes
handlers:
- name: reload haproxy
systemd:
name: haproxy
state: reloaded
九、压测与效果(实测数据)
工具:wrk(3 台并行)、h2load(验证 HTTP/2 多路复用效果)
场景:静态页面 + 动态接口混合(70/30),TLS 终止于 HAProxy;后端 Nginx/App 在同机房内网。
| 架构 | QPS(平均) | P50 | P95 | P99 | 失败率 |
|---|---|---|---|---|---|
| 单 HAProxy + 单 VIP | 62k | 18ms | 85ms | 160ms | 0.45% |
| 多 HAProxy(3 节点)+ 双 VIP(Active-Active) | 148k | 12ms | 48ms | 90ms | 0.08% |
| 多节点 + BBR + 中断亲和优化 | 163k | 10ms | 42ms | 78ms | 0.05% |
实测改观最大的是 排队时延与长尾(P99)。在跨境链路波动时,入口层的吞吐冗余和更稳的队列让“峰值期间的体验”不劣化。
十、常见坑与现场处置
VRRP + rp_filter
症状:VIP 偶发不通、抓包发现回包走另一节点。
处理:关闭严格 RPF(rp_filter=0),Keepalived 用 unicast,并尽量保障对称性;必要时收敛路由。
TLS 握手 CPU 冲高
症状:QPS 上去后 CPU sys 飙升,握手耗时变大。
处理:升级 OpenSSL 与 HAProxy,优先 ECDHE,开启 HTTP/2 多路复用、http-reuse;核对证书链;适度调大 tune.bufsize(默认 16k → 32k)。
TIME_WAIT 与端口耗尽
症状:cannot bind 或后端连接短期内失败。
处理:扩大 ip_local_port_range,tcp_fin_timeout=15,避免短连接风暴;后端尽量复用连接(http-reuse safe)。
健康检查“误杀”
症状:后端接口偶发慢,被踢出过久。
处理:retries 与 rise/fall(在 server 行使用),健康页 /healthz 与业务解耦;后端熔断策略不要相互叠加导致“雪崩”。
DNS TTL 过长
症状:VIP 迁移或权重调整后生效慢。
处理:入口域名 TTL 30s 左右即可,活动期更短;权重与双 A 记录动态调整要有 SOP。
中断亲和被打乱
症状:延迟抖动加大。
处理:禁止 irqbalance 或固定策略;确认 RSS 队列均衡,核对 /proc/interrupts。
跨境 MTU/丢包
症状:HTTP/2 长连接偶发重置。
处理:端到端检查 MTU(1500/1492),必要时在服务器侧启用 MSS clamping(防火墙)以规避路径 MTU 问题。
十一、安全基线
防火墙(CentOS 7):firewalld 或 iptables 明确放行 80/443/VRRP(协议 112)等;管理面(stats)仅内网访问。
最小权限:HAProxy 以非 root 运行,证书权限收紧。
合规加固:TLS1.2+/TLS1.3,淘汰旧套件;HSTS、OCSP;敏感头处理(X-Forwarded-For、X-Forwarded-Proto)。
十二、扩展与容灾
跨机房多活:在新加坡或东京再部署一组相同栈,用权重 DNS/GSLB 做就近与容灾。
BGP Anycast(进阶):如果机房支持自带 ASN/BGP,入口层用 FRR 广播同一 Anycast VIP,实现更平滑的全局就近与故障摘除(维护成本更高)。
十三、标准变更流程(SOP 摘要)
- 变更前 24h:降 TTL、预热缓存、压测回归。
- 变更窗口:先 VIP-B 灰度 → 指标稳定 → 切 VIP-A。
- 回滚锚点:保留旧进程 PID,-sf 回退;Keepalived 降级优先级触发回切。
- 复盘:导出 stats/日志,更新容量模型与阈值。
附:简化版完整配置清单(可落地)
- sysctl:见文中 /etc/sysctl.d/99-hk-haproxy.conf
- haproxy.service:见“安装 HAProxy”章节
- keepalived.conf:双 VIP 示例
- haproxy.cfg:前后端、限流、stats、HTTP/2/TLS 示例
再次“被叫醒”的夜里,我笑了
今年大促的零点,我照例守在监控前。流量像潮水一样涌入,Alerts 安静得有点不真实。P99 从 150ms 稳到 80ms 左右,握手抖动不再像过山车。凌晨 3 点,团队群里开始刷梗图,咖啡变成了奶茶。我把 VIP-B 的灰度权重调回,三台 HAProxy 的曲线像三条并排的心电图,稳定而有力。
那一刻我明白,这套在香港机房打磨出来的 HAProxy 多节点集群,不是只为这一晚——它足够简单、够硬核,也够“耐操”。下一个活动、下一个增长曲线,它都能继续扛着。
如果你也正准备把入口层从“能用”升级到“能战”,希望这份实操笔记能帮你少踩几个坑,多睡几个安稳觉。