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)漂移实现主备高可用

知识关联

原理讲解

为什么负载均衡要区分四层和七层

四层(L4)和七层(L7)负载均衡的区分源于 OSI 模型的层级差异。四层工作在传输层,只解析 IP 头和 TCP/UDP 头,不关心应用层内容——因此吞吐量极高(百万级连接/秒),适合 MySQL、Redis、Kafka 等对延迟敏感的 TCP 服务。七层工作在应用层,可以解析 HTTP Host、URL、Cookie、Header 等信息,实现基于内容的精细路由(如按域名分发、按路径分流),但需要完整的 TCP 连接终止和 HTTP 解析,CPU 开销更大。HAProxy 同时支持两种模式,通过 mode tcpmode 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 tcpmode 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-tableHAProxy 内存表记录 客户端↔后端 映射,支持按 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 deniedsocket 权限或 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 前放 NginxNginx 处理静态文件 + SSL,HAProxy 做精细路由分流发挥两者各自优势
会话保持要收敛只在真正有状态的业务开启 Cookie/stick-table,且设置过期时间cookie SERVERID insert indirect nocache maxage 3600
摘除节点先排空维护时避免流量中断disable server 等连接数归零再操作后端
保留备用节点(backup)主节点全部宕机时 backup 节点兜底option allbackups 让备用节点分担流量

练习题

  1. 在 3 台后端 Web 服务器上分别部署 Nginx,通过 HAProxy 做七层负载均衡,要求按路径 /api 分发到 API 池、/static 分发到静态池
  2. 为上述配置添加 SSL termination,使用自签名证书,并将 HTTP 请求 301 重定向到 HTTPS
  3. 启用 Stats 监控页面,配置认证为 admin:P@ssw0rd,刷新间隔 5 秒
  4. MySQL 后端 3 台,使用 leastconn 算法 + tcp-check 做主动健康检查,其中一台标记为 backup
  5. 在两台机器上部署 Keepalived,配置 VRRP 使 HAProxy 高可用,VIP 设为 10.0.0.100/24
点击查看答案
  1. 前端定义两个 ACL:acl is_api path_beg /apiacl is_static path_beg /static,分别 use_backend api_servers if is_api / use_backend static_servers if is_static
  2. 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 }
  3. stats enable / stats uri /stats / stats auth admin:P@ssw0rd / stats refresh 5s
  4. 后端用 balance leastconnoption tcp-check 加探测命令,一台加 backup 标记。
  5. 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 自身的单点故障。健康检查是负载均衡的"眼睛",合理配置可让故障自愈成为现实。

速查表

配置项示例用途
frontendfrontend web *:80定义监听入口
backendbackend api_servers定义后端服务器池
aclacl is_api path_beg /api流量匹配规则
use_backenduse_backend api_servers if is_apiACL 路由到后端
balancebalance leastconn负载均衡算法
option httpchkoption httpchk GET /healthHTTP 健康检查
statsstats 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

延伸阅读

常见问题

HAProxy 和 Nginx 做负载均衡各有什么侧重?
HAProxy 是专业负载均衡器,四层(TCP)和七层(HTTP)性能卓越,自带精细的健康检查、ACL 路由、统计页面(Stats)、连接管理。Nginx 在七层负载均衡之外还能做 Web 服务器、反向代理、缓存。混合方案:HAProxy 做入口负载均衡 → Nginx 做反向代理和静态文件服务。
Keepalived VRRP 怎么防止脑裂?
脑裂指两台节点都认为自己是 Master。防止措施:① 配置更短的 advert_int(通告间隔,如 1 秒);② 设置较高的 nopreempt(非抢占模式);③ 使用 multicast 而非 unicast 确保 VRRP 通告可达;④ 添加外部仲裁机制(如 ping 网关、通过 etcd 在第三节点协调)。监控:定期检查各节点 VRRP 状态。
HAProxy 健康检查返回 503 怎么办?
503 意味着所有后端服务器都不可用。排查步骤:① haproxy -c -f /etc/haproxy/haproxy.cfg 检查配置语法;② 登录 HAProxy 管理页面(端口 8404/stats)看各后端状态;③ 直接 curl 后端服务器确认是否正常;④ 检查健康检查的策略:option httpchk GET /health 确保后端有对应健康检查端点。
↑ 回到顶部