5.7 HAProxy 负载均衡与高可用
预计阅读时间:14 分钟
📖 目录
学习目标
学完本章后,你将能够:
- 理解四层(L4)与七层(L7)负载均衡的区别及适用场景
- 搭建 HAProxy 并配置前端/后端模型实现 TCP 和 HTTP 负载均衡
- 使用 ACL 规则按域名、路径、Header 做精细流量路由
- 配置健康检查策略自动摘除故障后端节点
- 实现 SSL termination 卸载 HTTPS 解密压力
- 通过 Keepalived + VRRP 构建 HAProxy 主备高可用架构
核心知识
- 四层(L4)负载均衡——在 TCP/UDP 传输层按 IP+PORT 分发,性能极高,适合 MySQL、Redis、Kafka
- 七层(L7)负载均衡——在 HTTP/HTTPS 应用层按 URL、Header、Cookie 分发,适合 Web 应用与 API 网关
- 前端(frontend)——HAProxy 的流量入口,定义监听地址、ACL 规则,并指定后端目标
- 后端(backend)——真实服务器组,定义调度算法、权重和健康检查策略
- ACL(Access Control List)——规则引擎,根据请求特征(域名/路径/Header)匹配并路由
- 调度算法——roundrobin(轮询)、leastconn(最少连接)、source(源 IP 哈希)、uri(URI 哈希)
- 健康检查——定期探测后端可用性,自动隔离故障节点
- SSL Termination——在 HAProxy 终结 HTTPS 加密,后端使用明文 HTTP 通信
- VRRP(Virtual Router Redundancy Protocol)——通过虚拟 IP(VIP)漂移实现主备高可用
知识关联
- 前置知识:4.5:网络故障排查 网络故障排查、3.3:实战:搭建个人网站 搭建个人网站、3.4:Nginx Web服务器 Nginx Web 服务器
- 后续影响:负载均衡是 3.14:LAMP/LEMP 环境 LAMP/LEMP 环境、6.2:Kubernetes 入门 Kubernetes 集群的必备组件
- 深入阅读:3.11:SSL/TLS 证书管理 SSL/TLS 证书管理、6.15:HA 集群 HA 集群
原理讲解
为什么负载均衡要区分四层和七层
四层(L4)和七层(L7)负载均衡的区分源于 OSI 模型的层级差异。四层工作在传输层,只解析 IP 头和 TCP/UDP 头,不关心应用层内容——因此吞吐量极高(百万级连接/秒),适合 MySQL、Redis、Kafka 等对延迟敏感的 TCP 服务。七层工作在应用层,可以解析 HTTP Host、URL、Cookie、Header 等信息,实现基于内容的精细路由(如按域名分发、按路径分流),但需要完整的 TCP 连接终止和 HTTP 解析,CPU 开销更大。HAProxy 同时支持两种模式,通过 mode tcp 或 mode http 切换——这个设计让用户可以在同一个工具中处理不同层级的负载均衡需求。
HAProxy vs Nginx:为什么选 HAProxy 做负载均衡
Nginx 最初是 Web 服务器,后来扩展了负载均衡能力;HAProxy 从设计之初就是负载均衡器。这个区别导致了架构差异:Nginx 的负载均衡功能是"附加"的,配置语法偏向 Web 服务器习惯(location 块、upstream 块);HAProxy 的前端→后端模型、ACL 规则引擎、Runtime API 都是为大规模流量调度设计的。生产选型:Nginx 适合"Web 服务器 + 轻量负载均衡"的混合场景;HAProxy 适合纯负载均衡场景(如 MySQL 读写分离、大规模 HTTP 代理),其 Stats 页面、Runtime API、tcp-check 多步探测等能力远超 Nginx。最佳实践是"Nginx 前置处理静态文件和 SSL,HAProxy 后置做精细路由"——两者互补而非互斥。
Keepalived vs Pacemaker:简单主备 vs 复杂集群
Keepalived 基于 VRRP 协议实现 VIP 漂移,设计目标是"简单、可靠、秒级切换"——适合两节点主备场景(如 Web 负载均衡器高可用)。其局限是:只提供虚拟 IP 与故障转移,不管理资源依赖关系、无法处理复杂故障场景(VRRP 本身支持多 BACKUP 节点,但配置与维护复杂度会随之上升)。Pacemaker + Corosync 是完整的集群资源管理器,支持多节点、资源组、约束体系(共置/顺序/位置)、Fencing 隔离——适合数据库等有状态服务的高可用。选型原则:无状态服务用 Keepalived,有状态服务或多资源编排用 Pacemaker。
前端→后端模型
HAProxy 的核心架构是"前端→后端"两层模型。前端(frontend)负责接收客户端连接,后端(backend)定义一组真实服务器。客户端请求到达前端后,HAProxy 根据 ACL 规则选择对应的后端,再按调度算法从后端池中选一台服务器处理请求。
四层 vs 七层
四层负载均衡工作在传输层,只解析 IP 头和 TCP/UDP 头,不关心应用层内容,因此吞吐量极高。七层负载均衡解析 HTTP 请求中的 Host、URL、Cookie 等信息,可以做更精细的路由决策,但 CPU 开销更大。HAProxy 同时支持两种模式,通过 mode tcp 或 mode http 切换。
调度算法原理
roundrobin 将请求依次分配给每个后端,适合后端配置相同的场景。leastconn 检查当前活跃连接数,分发给连接最少的节点,适合长连接场景如 WebSocket。source 对源 IP 做哈希计算,保证同一客户端总是落到同一台后端,用于无 Cookie 的会话保持。uri 对 URI 做哈希,让相同 URI 的请求落到缓存预热过的服务器。
VRRP 高可用原理
两台 HAProxy 节点部署 Keepalived,通过 VRRP 协议共享一个虚拟 IP(VIP)。主节点(Master)定期发送 VRRP 广播声明自己在线。当备节点(Backup)在超时时间内未收到广播时,立即接管 VIP 开始服务。通过 track_script 监控 HAProxy 进程,若进程异常则主动降低本机优先级,触发 VIP 漂移。
会话保持(Sticky Session)原理
有状态应用(如购物车、WebSocket 握手后的推送通道)要求同一客户端的后续请求落在同一台后端。HAProxy 提供三种会话保持手段,按适用场景选择:
| 方式 | 原理 | 适用场景 | 缺点 |
|---|---|---|---|
| Cookie 插入 | HAProxy 在响应中注入 Set-Cookie: SERVERID=...;,后续请求按 Cookie 值路由 | HTTP 场景首选 | 客户端禁 Cookie 则失效 |
| 源 IP 哈希 | 对客户端 IP 做哈希选择后端(balance source) | 无 Cookie 的 TCP 场景(数据库) | NAT 后多用户同 IP,分布不均 |
| stick-table | HAProxy 内存表记录 客户端↔后端 映射,支持按 IP/Cookie/Header 关联 | 同时兼顾多种识别方式 | 占内存,主备间需同步表 |
注意:会话保持与负载均衡天然矛盾——保持得越久,后端负载越不均衡。生产上通常用 Cookie 保持(后端掉线时 HAProxy 会自动重新分配),并给 Cookie 设置合理的 maxage。
健康检查类型详解
健康检查是 HAProxy 的"眼睛",按协议分为三类:
- TCP 层:默认
check只做 TCP 三次握手;tcp-check可以发送自定义数据并匹配响应(如 MySQL 的SELECT 1、Redis 的PING),还能做多步骤协议对话 - HTTP 层:
option httpchk发送 HTTP 请求,配合http-check expect校验状态码、字符串或正则 - 应用层(agent-check):HAProxy 连接后端暴露的 agent 端口,按 agent 返回的文本(
up/down/ready等)决策——适用于无法探测的复杂业务
参数节奏:inter(正常间隔)、fastinter(连续失败后的加速间隔)、fall(失败几次判 DOWN)、rise(成功几次判 UP)。合理的组合如 inter 3s fastinter 1s fall 3 rise 2:故障时 1 秒一探,3 次失败即摘除,避免检查风暴。
示例代码
1. 安装与基础配置
apt update && apt install -y haproxy
haproxy -v
# 输出: HAProxy version 2.8.x
haproxy -c -f /etc/haproxy/haproxy.cfg
# 输出: Configuration file is valid
2. 四层 TCP 负载均衡——MySQL 集群
frontend mysql_front
bind *:3306
mode tcp
default_backend mysql_back
backend mysql_back
mode tcp
balance leastconn
option tcp-check
tcp-check send "SELECT 1\r\n"
server db1 10.0.0.1:3306 check inter 5s fall 3 rise 2
server db2 10.0.0.2:3306 check inter 5s fall 3 rise 2 backup
3. 七层 HTTP 负载均衡——ACL 路由
frontend http_front
bind *:80
bind *:443 ssl crt /etc/ssl/haproxy/
mode http
acl is_api hdr(Host) -i api.example.com
acl is_www hdr(Host) -i www.example.com
acl is_admin path_beg /admin
redirect scheme https code 301 if !{ ssl_fc }
use_backend api_back if is_api
use_backend admin_back if is_admin
default_backend web_back
backend web_back
balance roundrobin
option httpchk HEAD /health HTTP/1.1\r\nHost:\ www.example.com
http-check expect status 200
server web1 10.0.0.10:8080 weight 10 check inter 3s
server web2 10.0.0.11:8080 weight 10 check inter 3s
backend api_back
balance leastconn
option httpchk GET /api/health
http-check expect string "ok"
server api1 10.0.0.20:8080 check
server api2 10.0.0.21:8080 check
4. SSL Termination
cat example.com.crt example.com.key > /etc/ssl/haproxy/example.com.pem
chmod 600 /etc/ssl/haproxy/example.com.pem
frontend https_front
bind *:443 ssl crt /etc/ssl/haproxy/example.com.pem alpn h2,http/1.1
mode http
option forwardfor header X-Real-IP
rspadd Strict-Transport-Security:\ max-age=31536000;\ includeSubDomains
http-request set-header X-Forwarded-Proto https if { ssl_fc }
default_backend web_back
frontend http_redirect
bind *:80
mode http
redirect scheme https code 301 if !{ ssl_fc }
5. Stats 监控页面
listen stats
bind *:8080
mode http
stats enable
stats uri /haproxy-stats
stats realm HAProxy\ Statistics
stats auth admin:YourStrongPasswordHere!
stats refresh 5s
stats admin if TRUE
6. Keepalived VIP 高可用
# /etc/keepalived/keepalived.conf(主节点)
global_defs { router_id LVS_HA_Master }
vrrp_script check_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2; fall 2; rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 200
advert_int 1
authentication { auth_type PASS; auth_pass 42abcdef }
virtual_ipaddress { 192.168.1.200/24 dev eth0 }
track_script { check_haproxy }
}
# /etc/keepalived/keepalived.conf(备节点)
global_defs { router_id LVS_HA_Backup }
vrrp_script check_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2; fall 2; rise 2
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication { auth_type PASS; auth_pass 42abcdef }
virtual_ipaddress { 192.168.1.200/24 dev eth0 }
track_script { check_haproxy }
}
systemctl enable --now keepalived
# 查看 VIP 落在哪台
ip addr show eth0 | grep 192.168.1.200
# 输出: inet 192.168.1.200/24 scope global eth0
# 主动故障转移测试(主节点执行)
systemctl stop haproxy
# VIP 将自动漂移到备节点
7. 会话保持配置
# Cookie 插入方式(HTTP 场景首选)
backend web_back
balance roundrobin
cookie SERVERID insert indirect nocache maxage 3600
server web1 10.0.0.10:8080 cookie web1 check inter 3s
server web2 10.0.0.11:8080 cookie web2 check inter 3s
# 源 IP 哈希(TCP 场景,如 MySQL 主从读写分离)
backend mysql_back
balance source
hash-type consistent # 一致性哈希:后端增减时影响面最小
server db1 10.0.0.1:3306 check
server db2 10.0.0.2:3306 check
# stick-table 方式(按 IP + Cookie 双维度)
backend web_back
stick-table type ip size 50k expire 30m
stick on src
server web1 10.0.0.10:8080 check
server web2 10.0.0.11:8080 check
8. 高级健康检查
# MySQL 多步骤协议探测(握手 + 查询)
backend mysql_back
mode tcp
balance leastconn
option tcp-check
tcp-check connect
tcp-check send "SELECT 1\r\n"
tcp-check expect string "1"
server db1 10.0.0.1:3306 check inter 5s fall 3 rise 2
# Redis PING 探测
backend redis_back
mode tcp
option tcp-check
tcp-check connect
tcp-check send PING\r\n
tcp-check expect string +PONG
server redis1 10.0.0.30:6379 check inter 3s
# HTTP 返回体校验(不止看状态码,还看内容)
backend api_back
option httpchk GET /health
http-check expect string "{\"status\":\"ok\"}" error-status 200
server api1 10.0.0.20:8080 check inter 3s
# agent-check:后端业务自报状态(配合端口的 agent 脚本)
backend app_back
option httpchk GET /health
server app1 10.0.0.40:8080 check agent-check agent-addr 127.0.0.1 agent-port 9001 inter 5s
9. Runtime API 动态运维
# 开启 Runtime API
# 在 haproxy.cfg 全局段添加:
# global
# stats socket /run/haproxy/admin.sock mode 600 level admin
# 查看后端服务器状态
echo "show servers state web_back" | socat /run/haproxy/admin.sock stdio
# 输出: 1 web_back 1 web1 ... 10.0.0.10:8080 ... UP 1 1 0 ...
# 动态下线/上线某台后端(不 reload、不断连接)
echo "disable server web_back/web1" | socat /run/haproxy/admin.sock stdio
echo "enable server web_back/web1" | socat /run/haproxy/admin.sock stdio
# 动态调整权重(灰度分流:web1 拿 80% 流量)
echo "set weight web_back/web1 80" | socat /run/haproxy/admin.sock stdio
echo "set weight web_back/web2 20" | socat /run/haproxy/admin.sock stdio
# 动态调整健康检查(设置为维护模式)
echo "set server web_back/web1 state MAINT" | socat /run/haproxy/admin.sock stdio
常见错误
| 错误现象 | 原因 | 解决方法 |
|---|---|---|
| 配置重载后 HAProxy 拒绝启动 | 语法错误——缩进或空格问题 | 先运行 haproxy -c -f /etc/haproxy/haproxy.cfg 验证 |
| 健康检查总标记后端 DOWN | 检查路径或 expect 条件不符 | 用 curl 手动访问健康检查端点确认响应 |
| SSL 握手失败 | 证书非 PEM 格式或权限不足 | 确认 crt 指向 PEM 文件且 chmod 600 |
| ACL 路由未命中 | 规则顺序错误导致被前面规则拦截 | 具体规则放前面,default_backend 放最后 |
| VIP 不漂移 | VRRP 认证密码不一致或防火墙拦截 | 检查两端 auth_pass 一致,放行 VRRP 协议(112) |
| 大量 TIME_WAIT 连接 | 短连接场景未启用连接复用 | 添加 option http-keep-alive |
| Cookie 会话保持不生效 | 后端返回了同名 Cookie 或被 indirect 语义混淆 | 确认 cookie SERVERID insert indirect,检查浏览器是否禁用了 Cookie |
| tcp-check 把正常后端判 DOWN | 期望字符串与真实响应不完全匹配(如大小写、末尾换行) | 先用 nc 手工模拟探测命令,核对响应原文再写 expect |
| 后端权重调整后连接仍在旧节点 | 长连接(WebSocket/数据库连接池)不受权重重算影响 | 调整前先 disable server 排空旧连接,或用 redispatch 强制重发 |
| Runtime API 提示 permission denied | socket 权限或 level 不足 | mode 600 level admin,用 root 或 haproxy 组用户执行 socat |
最佳实践
| 实践 | 原理 | 示例 |
|---|---|---|
| 配置修改必验证 | 避免语法错误导致服务中断 | haproxy -c -f /etc/haproxy/haproxy.cfg |
| 健康检查间隔合理设定 | 配合 fastinter 在故障时加速探测,避免检查风暴 | inter 3s fastinter 1s fall 3 rise 2 |
| ACL 顺序:从具体到通用 | 最精确的规则排在最前,default_backend 作为兜底放最后 | 具体路径规则在前,default_backend web_back 在最后 |
| Stats 页面设置强密码 | 防止未授权访问管理界面 | stats auth admin:YourStrongPasswordHere! |
| 日志单独配置 | 将 HAProxy 日志与系统日志分离,便于故障排查 | log /dev/log local0 |
| 使用 Runtime API | 生产环境中动态调整后端而不中断服务 | echo "disable server web_back/web1" | socat /run/haproxy/admin.sock stdio |
| HAProxy 前放 Nginx | Nginx 处理静态文件 + SSL,HAProxy 做精细路由分流 | 发挥两者各自优势 |
| 会话保持要收敛 | 只在真正有状态的业务开启 Cookie/stick-table,且设置过期时间 | cookie SERVERID insert indirect nocache maxage 3600 |
| 摘除节点先排空 | 维护时避免流量中断 | disable server 等连接数归零再操作后端 |
| 保留备用节点(backup) | 主节点全部宕机时 backup 节点兜底 | option allbackups 让备用节点分担流量 |
练习题
- 在 3 台后端 Web 服务器上分别部署 Nginx,通过 HAProxy 做七层负载均衡,要求按路径
/api分发到 API 池、/static分发到静态池 - 为上述配置添加 SSL termination,使用自签名证书,并将 HTTP 请求 301 重定向到 HTTPS
- 启用 Stats 监控页面,配置认证为
admin:P@ssw0rd,刷新间隔 5 秒 - MySQL 后端 3 台,使用 leastconn 算法 + tcp-check 做主动健康检查,其中一台标记为 backup
- 在两台机器上部署 Keepalived,配置 VRRP 使 HAProxy 高可用,VIP 设为
10.0.0.100/24
点击查看答案
- 前端定义两个 ACL:
acl is_api path_beg /api和acl is_static path_beg /static,分别use_backend api_servers if is_api/use_backend static_servers if is_static。 - 用
openssl req -x509 -newkey rsa:2048 -keyout haproxy.key -out haproxy.crt -days 365 -nodes生成自签名证书,合并为 PEM。bind *:443 ssl crt /etc/haproxy/cert.pem,前端加redirect scheme https code 301 if !{ ssl_fc }。 stats enable / stats uri /stats / stats auth admin:P@ssw0rd / stats refresh 5s。- 后端用
balance leastconn,option tcp-check加探测命令,一台加backup标记。 - Keepalived 配置:
virtual_ipaddress { 10.0.0.100/24 },双机互设 priority 100/90,track_script 检测 haproxy 进程。
学习检查点
学完本章后,请检验自己是否掌握以下内容:
| 检查项 | 自测问题 | 验证方法 |
|---|---|---|
| 概念理解 | 能用自己的话解释 HAProxy 的前端、后端、监听器概念 | 尝试向他人讲解 |
| 命令操作 | 能不查文档完成 HAProxy 配置文件编写、负载均衡算法选择 | 在终端实际执行 |
| 原理掌握 | 能说出 HAProxy 的健康检查机制和故障转移流程 | 画出流程图 |
| 故障排查 | 能独立排查 HAProxy 后端服务器全部显示 DOWN 的问题 | 模拟故障并修复 |
| 最佳实践 | 能说明为什么生产环境需要配置 HAProxy 的 stats 页面和日志 | 对比不同方案 |
本章总结
HAProxy 是生产环境负载均衡的事实标准——稳定、高性能、配置灵活。核心架构是"前端→后端"模型,通过 ACL 规则实现精细流量路由。四层模式适合数据库和消息队列等 TCP 服务,七层模式适合 HTTP Web 应用。配合 Keepalived + VRRP 实现 VIP 漂移,消除 HAProxy 自身的单点故障。健康检查是负载均衡的"眼睛",合理配置可让故障自愈成为现实。
速查表
| 配置项 | 示例 | 用途 |
|---|---|---|
| frontend | frontend web *:80 | 定义监听入口 |
| backend | backend api_servers | 定义后端服务器池 |
| acl | acl is_api path_beg /api | 流量匹配规则 |
| use_backend | use_backend api_servers if is_api | ACL 路由到后端 |
| balance | balance leastconn | 负载均衡算法 |
| option httpchk | option httpchk GET /health | HTTP 健康检查 |
| stats | stats enable | 启用监控页 |
快速配置备忘:
- 前端监听:
bind *:80/bind *:443 ssl crt ... - ACL 路由:
acl ... hdr(Host)/path_beg+use_backend - 后端机组:
server name ip:port check inter 3s fall 3 rise 2 - 健康检查:
option httpchk+http-check expect status 200 - 高可用:Keepalived + VRRP 主备节点 +
track_script
延伸阅读
- 3.11:SSL/TLS 证书管理 SSL/TLS 证书管理——为 HAProxy SSL termination 准备正式证书
- 3.4:Nginx Web服务器 Nginx Web 服务器——Nginx + HAProxy 协同部署方案
- 6.15:HA 集群 Linux 高可用集群——更高阶的高可用集群方案
- 6.2:Kubernetes 入门 Kubernetes 容器编排入门——K8s Service 本质也是一种负载均衡
- 官方文档:HAProxy Configuration Manual