HAProxy 是什么
HAProxy(High Availability Proxy) 是一个 高性能、高可用的 TCP 和 HTTP 负载均衡器与代理服务器。
HAProxy 的特点
特性 | 说明 |
---|---|
支持协议 | HTTP、HTTPS、TCP |
高性能 | 使用 C 语言编写,性能极高 |
高可用 | 与 Keepalived 配合可实现主备 |
健康检查 | 实时检查后端服务器是否存活 |
连接控制 | 支持并发限制、超时设置、连接数控制等 |
日志与监控 | 提供详细日志,便于排错和监控 |
HAProxy vs Nginx 区别
对比项 | HAProxy | Nginx |
---|---|---|
核心定位 | 专业负载均衡器 | Web服务器 + 反向代理 |
支持协议 | TCP、HTTP、HTTPS(L4 + L7) | HTTP、HTTPS、邮件协议(L7) |
处理静态内容 | 不支持 | 支持(可直接做 Web Server) |
性能表现 | 高并发、大连接场景更强 | 中等并发性能良好 |
健康检查能力 | 强,支持高级健康检查 | 支持基本健康检查 |
配置复杂度 | 专注负载均衡,配置清晰 | 功能丰富,配置复杂多变 |
状态监控界面 | 内置强大状态统计页 | 有但功能简单 |
模块机制 | 无法动态加载模块 | 支持动态模块 |
主流应用 | 金融、电商、大型高可用架构 | Web服务、CDN、轻量负载均衡 |
HAProxy vs Nginx 使用场景
使用场景 | 推荐方案 | 原因说明 |
---|---|---|
Web 网站负载均衡 + 静态资源服务 | Nginx | 能代理、缓存、压缩、处理静态资源,适合前端站点 |
仅 TCP(如 MySQL、Redis)负载均衡 | HAProxy | 支持四层负载均衡,Nginx 无法代理纯 TCP 连接 |
高并发反向代理(如 API 网关) | HAProxy | 并发能力更强,适合海量 API 请求分发 |
高可用集群 + 主备 VIP 浮动 | HAProxy + Keepalived | 主从切换快,专用于高可用负载均衡 |
Kubernetes Ingress 网关 | Nginx | 社区插件多,原生支持 Ingress Controller |
企业 Web 服务 + 页面缓存优化 | Nginx | 支持 gzip、缓存、rewrite,适合前端 |
纯粹做 Layer 7 负载均衡器(无文件处理) | HAProxy | 更稳定、日志更清晰、健康检查更强 |
小型应用或快速上线部署 | Nginx | 简单易部署,配置灵活 |
带状态的健康检查需求(如根据返回内容判活) | HAProxy | 可配置返回码、内容、脚本等高级判活规则 |
安装 HAProxy
sudo apt-get update
sudo apt-get install -y haproxy
HAProxy 常用命令
查看 HAProxy 版本:haproxy -v
启动 HAProxy:sudo systemctl start haproxy
停止 HAProxy:sudo systemctl stop haproxy
重启 HAProxy:sudo systemctl restart haproxy
重新加载配置(不中断连接):sudo systemctl reload haproxy
查看状态:sudo systemctl status haproxy
开启开机自启动:sudo systemctl enable haproxy
禁用开机自启动:sudo systemctl disable haproxy
检查配置文件是否有语法错误:haproxy -c -f /etc/haproxy/haproxy.cfg
查看系统日志(包含 haproxy 日志):journalctl -u haproxy
查看所有运行状态(需配置 stats socket):echo "show stat" | socat stdio /var/run/haproxy.sock
查看当前连接:echo "show info" | socat stdio /var/run/haproxy.sock
查看所有后端状态:echo "show backend" | socat stdio /var/run/haproxy.sock
暂停某个后端服务器(server_name 为配置中的名称):echo "disable server backend_name/server_name" | socat stdio /var/run/haproxy.sock
启用某个后端服务器(server_name 为配置中的名称):echo "enable server backend_name/server_name" | socat stdio /var/run/haproxy.sock
HAProxy 配置文件详解
默认文件位置
sudo vim /etc/haproxy/haproxy.cfg
global:全局配置,影响整个 HAProxy 实例
global
# 日志输出地址,可设为 UNIX socket 或 IP:port
log /dev/log local0
# 设置日志到远程服务器
# log 192.168.1.100:514 local0
# 更改根目录,提高安全性(只允许访问该目录)
chroot /var/lib/haproxy
# 指定 PID 文件路径
pidfile /var/run/haproxy.pid
# 全局最大连接数(上限),限制资源使用
maxconn 4096
# 指定运行用户
user haproxy
# 指定运行用户组
group haproxy
# 让 HAProxy 以守护进程方式运行(后台)
daemon
# 启用 stats socket 用于控制台管理
stats socket /var/run/haproxy.sock mode 600 level admin
# 启动进程数,一般为 1,(多核 CPU 可用,但需小心状态同步)
nbproc 1
# 每个进程的线程数(多线程支持,需 HAProxy 2.0+),需结合 thread 关键字使用。
nbthread 4
# 当前节点的名称(用于 peers 同步)
node haproxy-node-1
注意:
- nbproc 的值大于 1 且不配置 peers:多进程不共享内存,stick-table 不同步,容易出错
- 不配置 stats socket:运行时不便调试和状态查看
- 不配置 log:失去调试能力,难以追踪问题
defaults:默认配置,会被 frontend/backend/listen 使用
# 这些参数会被所有 frontend、backend 和 listen 块自动继承(除非这些块中显式覆盖)
defaults
# 工作模式:http、tcp
mode http
# 使用 global 中的日志设置
log global
# 使用专为 HTTP 设计的日志格式,tcplog: TCP 日志格式
option httplog
# 不记录无数据连接日志
option dontlognull
# 连接后端超时时间
timeout connect 5s
# 客户端空闲超时
timeout client 50s
# 服务端响应超时时间
timeout server 50s
# 请求头超时 10 秒
timeout http-request 10s
# keep-alive 超时
timeout http-keep-alive 10s
# 最大并发连接数
maxconn 2000
# 自动重试其他服务器
option redispatch
# 重试次数
retries 3
# default-server [参数1] [参数n],为所有 backend server 统一指定默认属性
# inter 3s:每 3 秒进行一次健康检查;rise 2:连续 2 次检查通过视为“恢复”;fall 3:连续 3 次检查失败视为“宕机”;maxconn 100:单个服务器最多接受 100 个连接
default-server inter 3s rise 2 fall 3 maxconn 100
# default-bind [参数1] [参数n],指令为所有 frontend 或 listen 块中未显式定义 bind 的地方,统一设置绑定行为的默认参数
# ssl:开启 SSL 支持; crt /path/to/cert.pem:指定默认证书路径; alpn h2,http/1.1:支持 HTTP/2 和 HTTP/1.1; ipv4 / ipv6:限定只绑定 IPv4 或 IPv6; transparent:用于 TPROXY 透明代理场景; defer-accept:延迟连接处理直到数据可读,提高效率。
default-bind ssl crt /etc/ssl/private/haproxy.pem alpn h2,http/1.1
注意:
- 忘写 mode:容易导致行为异常(默认是 TCP)
- 忽略超时参数:会导致连接悬挂或资源被耗尽
- 使用 HTTP 却没有 option httplog:日志中缺失请求详情
- 不加 timeout http-request:防止慢速 HTTP 攻击时不生效
- 不了解继承机制:容易在 frontend 或 backend 中重复配置
frontend:前端,接收客户端请求
frontend 块用于定义 接收客户端请求的入口,可以指定监听的 IP、端口、协议,并将请求转发到某个后端(backend)或做更复杂的路由处理,匹配请求(基于 URL、Host、IP、Header、方法等)。frontend = “入口”,backend = “出口(服务端池)”
# http_front:是 frontend 的自定义名称
frontend http_front
## 监听所有 IP 上的端口/地址,如 *:80
bind *:80
## 监听 443 端口,使用 SSL 证书 /etc/ssl/private/haproxy.pem
# bind *:443 ssl crt /etc/ssl/private/haproxy.pem
## 指定工作模式为 HTTP,选项有 HTTP|TCP
mode http
## 默认转发到后端名为 http_back 的服务器池
default_backend http_back
## 访问控制规则,支持多种判断(如路径、头部、IP)
acl is_static path_end .jpg .png .css .js
## 根据 ACL 条件使用不同后端
use_backend static_back if is_static
注意:
- 忘写 mode http:会使 HTTP 规则无法生效,表现异常
- 多个 bind 不同端口未区分流量:建议使用 ACL 区分请求类型
- 忽略 http-request 控制:限流、重定向、拒绝请求功能缺失
- 日志无记录的话:确保配置了 log global 和 option httplog
backend:后端,定义服务器组和转发策略
backend 是用来定义 后端服务器池 的模块,负责处理前端 (frontend) 或中间路由转发过来的请求。你可以在 backend 中指定多个真实服务节点(server),并配置负载均衡方式、健康检查等参数。
# http_back:是 backend 的自定义名称
backend http_back
## 负载均衡策略,选项如下:
# roundrobin:轮询,默认方式,平均分配请求。适用于大多数场景。
# leastconn:优先分配给当前连接数最少的服务器。适合长连接(如数据库、API)场景。
# source:根据客户端 IP 哈希,保持同一客户端请求固定落到一台服务器(会话保持)。
# uri [option]:根据请求 URI 哈希,常用于静态资源缓存场景。
# url_param <param>:根据 URL 中指定的参数值做哈希。例如 ?id=123 中的 id。
# hdr(<name>):根据指定 HTTP 头做哈希,如:hdr(User-Agent)。
# rdp-cookie <cookie_name>:仅用于 TCP 模式 + RDP 协议,根据 RDP cookie 实现持久会话。
# random [draws N]:随机选择一台服务器(可选多次抽样,选最优)
# first(仅限 backup 服务器):优先选择第一台健康的服务器
balance roundrobin
## 健康检查路径
option httpchk GET /health
## 健康检查响应状态码要求
http-check expect status 200
## 给所有 server 设置默认参数
# default-server [参数1] [参数n]
## 定义服务器,格式:<name> <IP>:<port> [check] [backup]
# check:开启健康检查
# backup:作为备用服务器
# weight:权重
# resolvers:使用 DNS 解析器,mydns:解析器的名字
server web1 192.168.1.10:80 weight 3 check
server web2 192.168.1.11:80 weight 1 check backup resolvers mydns
## 修改请求头、添加路由规则等。
# http-request
# tcp-request
## 配合 frontend 实现会话保持(IP、cookie等)
# stick-table
## 会话保持策略
# cookie
## 连接超时时间
# timeout connect
## 服务响应超时时间
# timeout server
注意:
- 会话丢失的话:使用 cookie 或 stick-table 保持 session
- 后端负载不均:优化 balance 策略(如 leastconn)
- 连接超时:设置合理的 timeout server 和 timeout connect
- 后端节点不健康:检查 option httpchk 是否配置正确
- 不支持 HTTPS 后端的话:加上 ssl verify none 让 HAProxy 与后端走 TLS
listen:同时定义 frontend 和 backend 的组合配置(简写方式)
listen 是一个组合块,将 frontend(接收请求)和 backend(转发处理)合并在一起,适合简单场景或 TCP 代理场景,比如 MySQL、Redis、FTP、SMTP 等服务的负载均衡。
# admin_stats:是 listen 的自定义名称
listen admin_stats
# 监听端口或地址,如 *:80
bind *:8080
# 工作模式:http、tcp
mode http
## 最大连接数
maxconn 1000
## 启用日志记录(需配置 syslog)
log global
## 启用的日志格式,httplog|tcplog
option tcplog
## 负载均衡算法
balance roundrobin
## 启用基于 Cookie 的会话保持
cookie SRV insert indirect
## 粘性表(用于限流、IP 绑定)
stick-table
## 根据某字段粘性会话
stick on src
## 启用状态页面
stats enable
## 设置访问路径
stats uri /haproxy?stats
## 设定登录提示标题
stats realm Haproxy\ Stats
## 设置访问认证
stats auth admin:admin
## 刷新频率
stats refresh 10s
注意:
- 复杂路由逻辑:用 frontend + backend 更清晰
- 日志无输出:添加 log global 和 option httplog
- 会话粘性失败:检查 cookie 名称、参数一致性
- 无监控界面:添加 stats 相关配置
peers:多节点之间的同步(如 stick-table)
peers 是 HAProxy 中用于配置多实例之间的状态同步的模块,常用于多个 HAProxy 节点之间同步 stick-table(会话表) 数据,从而实现集群中“共享状态”。如:源 IP 的请求频率(防护 DDOS、限流),用户会话保持,自定义统计(登录失败次数等)。
stick-table 是 HAProxy 用来在运行时追踪客户端状态的数据结构(例如追踪 IP 的连接数、请求数、失败数等)。这对于防止 DDoS、暴力破解、限流、会话保持非常有用。
# group_name 同步组名(多个节点使用相同组名以便互相同步)
peers <group_name>
# <本机名> 必须与当前 HAProxy 启动时的 -L <name> 参数一致(或 global 中的 node <name>)
peer <本机名> <本机IP>:<端口>
peer <其他节点名> <其他IP>:<端口>
注意:
- 所有节点都必须有相同的 peers 配置(节点名字可不同)
- peer 名称必须唯一且不能是当前机器的名称
- 每台机器的 bind 地址和 peer 中配置的 IP 要匹配
- peers 同步是双向的,每台都要监听端口
- 用于高可用部署(主-主同步),不适用于主-备场景
- stick-table 配置中的 peers <name> 不能漏掉
resolvers:自定义 DNS 解析器
resolvers 用于配置 DNS 解析器,使 HAProxy 能动态解析和刷新服务器的 IP 地址。默认情况下,HAProxy 启动时只解析一次 DNS,如果没有配置 resolvers,域名解析不会动态更新。
这对于以下场景尤其重要:
- 后端服务器 IP 可能变动(比如后端是 Kubernetes Pod、云主机、容器)
- 使用主机名作为后端地址(如 server web1 app.example.com:80)
# 自定义一个resolvers 名称,名称可在 server 行中引用
resolvers mydns
# 设置 DNS 服务器
nameserver dns1 8.8.8.8:53
nameserver dns2 8.8.4.4:53
# 解析重试次数
resolve_retries 3
# 重试超时时间
timeout retry 1s
# 超时时间
timeout resolve 1s
# 解析结果缓存多久
hold valid 10s
## 对 NXDOMAIN 响应的缓存时间
hold nx 30s
## 其它响应(如 SERVFAIL)的缓存时间
hold other 30s
## 拒绝响应的缓存时间
hold refused 30s
## 超时响应的缓存时间
hold timeout 30s
## DNS 响应最大数据包(默认 512)
accepted_payload_size 8192
## 使用 /etc/resolv.conf 中的配置(仅 Linux)
parse-resolv-conf
注意:
- 必须指定 resolvers 才能解析主机名(否则启动报错)
- 建议设置合理的 hold valid,避免频繁解析
- 使用多个 nameserver 做冗余,提升稳定性
- 支持 SRV 和 A/AAAA 查询(需设置 init-addr 参数)
userlist:用户认证列表
userlist 用于定义用户名和密码列表,它相当于一个“认证数据库”,本地内置用户名+密码信息,HAProxy 直接验证请求。主要用于:
- HTTP Basic 认证(常见于管理页面、监控接口保护)
- 配合 acl 使用,实现访问控制
- 可用于结合 stats 页面进行访问限制
userlist <名称>
user <用户名1> password <明文密码>
user <用户名2> insecure-password <明文密码>
user <用户名3> encrypted-password <加密后的密码(推荐使用 bcrypt)>
注意:
- 不支持动态用户加载,必须在启动时写死
- 密码推荐使用加密格式(SHA-256/512 或 bcrypt)
- userlist 只在 HAProxy 本地生效,不能对接 LDAP 或外部认证
- 支持多个 userlist,可按需引用