跳转到内容

HAProxy 负载均衡

适用于 CentOS Stream 9 & 10 / AlmaLinux 9.x & 10.x / Rocky Linux 9.x & 10.x

HAProxy 是一款高性能的 TCP/HTTP 负载均衡器与反向代理。当一台后端服务器扛不住流量,或者你需要在升级、宕机时保持服务可用时,HAProxy 可以把请求分发到多台后端,实现横向扩展与高可用。本文带你在 EL 系统上从零搭起一套四层/七层负载均衡。

  • 安装 HAProxy 并理解配置文件的四个核心段
  • 配置 frontend 与 backend,把流量分发到多台后端服务器
  • 使用 roundrobin / leastconn 调度算法与健康检查
  • 启用统计页面观察后端状态
  • 处理 SELinux 与 firewalld 放行
  • 配置 TLS 终止与 HTTP→HTTPS 跳转
  • 了解如何配合 Keepalived 让 HAProxy 自身也高可用
  • 一台运行 EL 9.x 或 EL 10.x 的系统作为负载均衡器
  • 至少两台可访问的后端 Web 服务器(本文以 10.0.0.11 / 10.0.0.12 为例)
  • sudo 权限
版本数据实时来自 pkgseek.com

HAProxy 在 AppStream 仓库中提供,直接安装即可:

安装 HAProxy
$ sudo dnf install haproxy

确认版本:

查看版本
$ haproxy -v
HAProxy version 2.4.x ...

HAProxy 的主配置文件是 /etc/haproxy/haproxy.cfg,由四个核心段组成:

作用
global进程级全局设置:日志、运行用户、最大连接数、调优参数
defaults为后续的 frontend/backend 提供默认值,避免重复书写
frontend定义对外监听的地址、端口,以及把流量交给哪个 backend
backend定义后端服务器池、调度算法与健康检查

frontend 接收客户端请求,backend 承载真实的后端服务器,两者通过名字关联。

下面这份配置监听 80 端口,把 HTTP 请求轮询分发到两台后端 Web 服务器。编辑 /etc/haproxy/haproxy.cfg

/etc/haproxy/haproxy.cfg
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
stats socket /var/run/haproxy.sock mode 660 level admin
daemon
defaults
mode http
log global
option httplog
option dontlognull
retries 3
timeout connect 5s
timeout client 30s
timeout server 30s
timeout http-request 10s
frontend web_front
bind *:80
default_backend web_servers
backend web_servers
balance roundrobin
option httpchk GET /
server web1 10.0.0.11:80 check
server web2 10.0.0.12:80 check

几个要点:

  • mode http 表示工作在七层(HTTP),能解析 HTTP 头;改成 mode tcp 则是四层透传,适合数据库、SMTP 等非 HTTP 协议。
  • balance roundrobin 按顺序轮流分发请求。如果后端处理时长差异较大,改用 balance leastconn 更合适——它会把新连接交给当前连接数最少的后端。
  • server web1 10.0.0.11:80 check 中的 check 启用健康检查;HAProxy 会定期探测该后端,失败后自动摘除,恢复后再加回。
  • option httpchk GET / 把健康检查从默认的 TCP 探测升级为 HTTP 探测,向 / 发起 GET 请求,只有返回 2xx/3xx 才算健康。生产环境建议指向一个专门的健康检查路径(如 /healthz)。

HAProxy 自带一个实时统计页面,能看到每台后端的状态、流量和会话数。在配置中追加一个 listen 段(或写在某个 frontend 里):

追加到 /etc/haproxy/haproxy.cfg
listen stats
bind *:8404
stats enable
stats uri /haproxy?stats
stats auth admin:password
stats refresh 10s

保存后访问 http://<负载均衡器IP>:8404/haproxy?stats,输入用户名 admin、密码 password 即可查看。

每次修改后,先校验语法再重启,避免把服务改坏:

校验配置文件
$ sudo haproxy -c -f /etc/haproxy/haproxy.cfg
Configuration file is valid

如果有错误,输出会直接指出出错的行号和原因,按提示修正即可。

EL 系统默认启用 SELinux。HAProxy 运行在 haproxy_t 域下,默认只允许连接一组常见端口。如果你的后端使用非标准端口,连接会被 SELinux 拒绝,表现为后端始终 down 而网络本身却是通的。

打开布尔值,允许 HAProxy 连接任意端口:

允许 HAProxy 连接任意后端端口
$ sudo setsebool -P haproxy_connect_any on

放行 HTTP/HTTPS 端口,让客户端能访问到负载均衡器:

开放 80 与 443
$ sudo firewall-cmd --permanent --add-service=http
$ sudo firewall-cmd --permanent --add-service=https
$ sudo firewall-cmd --reload

如果统计页面用了 8404,再放行该端口:

放行统计页面端口
$ sudo firewall-cmd --permanent --add-port=8404/tcp
$ sudo firewall-cmd --reload
启动并设置开机自启
$ sudo systemctl enable --now haproxy

查看状态:

查看运行状态
$ sudo systemctl status haproxy

之后每次改完配置,先 haproxy -c -f 校验,再 sudo systemctl reload haproxy 平滑重载(reload 不会中断已有连接)。

让 HAProxy 直接终止 TLS(在负载均衡器上解密,再以明文转发给后端),客户端只与 HAProxy 建立加密连接。

  1. 准备证书。HAProxy 要求把完整证书链与私钥合并到同一个 .pem 文件里(顺序为证书 + 中间证书 + 私钥):

    合并 fullchain 与私钥
    $ sudo mkdir -p /etc/haproxy/certs
    $ sudo bash -c 'cat fullchain.pem privkey.pem > /etc/haproxy/certs/site.pem'
    $ sudo chmod 600 /etc/haproxy/certs/site.pem
  2. bind 上启用 TLS,并把 80 端口的请求跳转到 HTTPS:

    /etc/haproxy/haproxy.cfg
    frontend web_front
    bind *:80
    bind *:443 ssl crt /etc/haproxy/certs/site.pem
    # 非加密访问一律 301 跳转到 HTTPS
    redirect scheme https code 301 if !{ ssl_fc }
    default_backend web_servers

    ssl_fc 用来判断当前连接是否走了 TLS;!{ ssl_fc } 即”明文请求”,对其执行 redirect scheme https

  3. 校验并重载:

    校验后重载
    $ sudo haproxy -c -f /etc/haproxy/haproxy.cfg
    $ sudo systemctl reload haproxy

单台 HAProxy 仍然是单点故障。生产环境通常部署两台 HAProxy,用 Keepalived 在它们之间漂移一个虚拟 IP(VIP):客户端只访问 VIP,主节点宕机时 VIP 自动切换到备节点,实现负载均衡器自身的冗余。

具体的 Keepalived + VIP 配置、健康检查脚本与脑裂处理,参见 高可用基础

这是最常见的报错,几乎都意味着该 backend 没有可用的后端服务器:所有 server 都处于 down 状态,或健康检查全部失败。排查:

查看后端健康状态
$ echo "show servers state" | sudo socat stdio /var/run/haproxy.sock

这条命令依赖上面 global 段里配置的 stats socketsocat 来自 EPEL,用 sudo dnf install socat 安装。更直观的方式是打开统计页面,看哪几台是红色(DOWN)。常见原因:后端服务没起、防火墙挡了健康检查、option httpchk 指向的路径返回了非 2xx/3xx,或后端用非标准端口被 SELinux 拦截(见上文 haproxy_connect_any)。

  • 绑不上 443:先确认证书文件存在且包含私钥,haproxy -c -f 会报 unable to load SSL certificate。再确认权限可读。如日志显示权限被拒,多半是 SELinux 上下文问题,可用 sudo restorecon -Rv /etc/haproxy/ 修复。
  • 后端连接被拒:后端用非标准端口时务必执行 sudo setsebool -P haproxy_connect_any on,否则 SELinux 会静默拒绝连接。

依次检查:listen stats 段是否写了 stats enable;防火墙是否放行了对应端口(如 8404/tcp);访问的 URL 是否与 stats uri 完全一致(本文是 /haproxy?stats);以及用户名密码是否与 stats auth 匹配。

启动失败时第一时间运行:

校验并定位错误
$ sudo haproxy -c -f /etc/haproxy/haproxy.cfg

输出会标明出错的行号与原因。也可以查看 journal 获取启动失败的细节:

查看服务日志
$ sudo journalctl -u haproxy -n 50 --no-pager