文章目录
- [HAProxy 负载均衡全解析](#HAProxy 负载均衡全解析)
-
- [HAProxy 介绍](#HAProxy 介绍)
- [HAProxy 调度算法](#HAProxy 调度算法)
- [HAProxy 实践](#HAProxy 实践)
- [HAProxy 配置说明](#HAProxy 配置说明)
- [HAProxy 使用总结](#HAProxy 使用总结)
HAProxy 负载均衡全解析
HAProxy 介绍
HAProxy 是一款提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,支持虚拟主机。它是免费、快速并且可靠的一种解决方案。 HAProxy 特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy 运行在时下的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。

HAProxy 实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。 多进程或多线程模型受内存限制 、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户端(User-Space) 实现所有这些任务。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以 使每个CPU时间片(Cycle)做更多的工作。
性能
HAProxy借助于OS上几种常见的技术来实现性能的最大化。
1,单进程、事件驱动模型显著降低了上下文切换的开销及内存占用。
2,O(1)事件检查器(event checker)允许其在高并发连接中对任何连接的任何事件实现即时探测。
3,在任何可用的情况下,单缓冲(single buffering)机制能以不复制任何数据的方式完成读写操作,这会节约大量的CPU时钟周期及内存带宽;
4,借助于Linux 2.6 (>= 2.6.27.19)上的splice()系统调用,HAProxy可以实现零复制转发(Zero-copy forwarding),在Linux 3.5及以上的OS中还可以实现零复制启动(zero-starting);
5,内存分配器在固定大小的内存池中可实现即时内存分配,能够显著减少创建一个会话的时长;
6,树型存储:侧重于使用作者多年前开发的弹性二叉树,实现了以O(log(N))的低开销来保持计时器命令、保持运行队列命令及管理轮询及最少连接队列;
7,优化的HTTP首部分析:优化的首部分析功能避免了在HTTP首部分析过程中重读任何内存区域;
8,精心地降低了昂贵的系统调用,大部分工作都在用户空间完成,如时间读取、缓冲聚合及文件描述符的启用和禁用等;
所有的这些细微之处的优化实现了在中等规模负载之上依然有着相当低的CPU负载,甚至于在非常高的负载场景中,5%的用户空间占用率和95%的系统空间占用率也是非常普遍的现象,这意味着HAProxy进程消耗比系统空间消耗低20倍以上。因此,对OS进行性能调优是非常重要的。即使用户空间的占用率提高一倍,其CPU占用率也仅为10%,这也解释了为何7层处理对性能影响有限这一现象。由此,在高端系统上HAProxy的7层性能可轻易超过硬件负载均衡设备。
在生产环境中,在7层处理上使用HAProxy作为昂贵的高端硬件负载均衡设备故障故障时的紧急解决方案也时长可见。硬件负载均衡设备在"报文"级别处理请求,这在支持跨报文请求(request across multiple packets)有着较高的难度,并且它们不缓冲任何数据,因此有着较长的响应时间。对应地,软件负载均衡设备使用TCP缓冲,可建立极长的请求,且有着较大的响应时间。
HAProxy 调度算法
Haproxy有8种负载均衡算法(balance),分别如下:
-
roundrobin(rr),动态加权轮询,支持权重,
-
static-rr,静态轮询 不支持权重。
-
leastconn,最小连接优先处理。
-
source,源地址哈希算法。
-
uri,根据URI做哈希算法。
-
url_param,根据请求的URl参数'balance url_param' requires an URL parameter name做哈希。
-
hdr(name) ,根据HTTP请求头来锁定每一次HTTP请求。
-
rdp-cookie(name) ,根据据cookie(name)来锁定并哈希每一次TCP请求。
HAProxy 实践
通过HAProxy实现4层和7层负载均衡。
基础配置
网络拓扑

主机名 | IP地址 | 服务器角色 |
---|---|---|
client2.laoma.cloud | 10.1.1.21 | 客户端 |
client1.laoma.cloud | 10.1.8.21 | 客户端 |
router.laoma.cloud | 10.1.8.20 10.1.1.20 | 路由器 |
haproxy.laoma.cloud | 10.1.8.10 10.1.1.10 | 代理服务器 |
web1.laoma.cloud | 10.1.8.11 | Web 和 SSH 服务器 |
web2.laoma.cloud | 10.1.8.12 | Web 和 SSH 服务器 |
web3.laoma.cloud | 10.1.8.13 | Web 和 SSH 服务器 |
网络说明:
- 假设所有主机:第一块网卡名为 ens33,第二块网卡名为 ens192
- 默认第一块网卡模式为nat,第二块网卡模式为hostonly
- 网关设置:10.1.1.0/24 网段网关为10.1.1.20,10.1.8.0/24 网段网关为10.1.8.20
基础配置
-
主机名
-
IP 地址
-
网关
bash# 网关配置命令参考 # 10.1.1.0/24 网段网关为10.1.1.20 nmcli connection modify ens33 ipv4.gateway 10.1.1.20 nmcli connection up ens33 # 10.1.8.0/24 网段网关为10.1.8.20(可以不改) nmcli connection modify ens33 ipv4.gateway 10.1.8.20 nmcli connection up ens33
配置 router
bash
# 开启路由
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p
# 设置防火墙
systemctl enable firewalld.service --now
firewall-cmd --set-default-zone=trusted
firewall-cmd --add-masquerade --permanent
http 模式
配置 web
bash
[root@web1-3 ~]#
# 部署 web
yum install -y nginx
echo Welcome to $(hostname) > /usr/share/nginx/html/index.html
systemctl enable nginx.service --now
# 访问后端 nginx
[root@client1 ~]# curl 10.1.8.11
Welcome to web1.laoma.cloud
[root@client1 ~]# curl 10.1.8.12
Welcome to web2.laoma.cloud
[root@client1 ~]# curl 10.1.8.13
Welcome to web3.laoma.cloud
# 准备虚拟主机
[root@web1-3 ~]# cat > /etc/nginx/conf.d/vhost-test.conf <<'EOF'
server {
listen 81;
root /test;
}
EOF
[root@web1-3 ~]# systemctl restart nginx
# 准备测试文件
[root@web1-3 ~]# mkdir /test
[root@web1-3 ~]# echo hello txt from $(hostname -s) > /test/index.txt
[root@web1-3 ~]# echo hello html from $(hostname -s) > /test/index.html
# 测试
[root@client1 ~]# curl http://web1:81/
hello html from web1
[root@client1 ~]# curl http://web2:81/
hello html from web2
[root@client1 ~]# curl http://web3:81/
hello html from web3
配置 haproxy
bash
[root@haproxy ~]#
# 安装 haproxy
yum install -y haproxy
# 备份 haproxy 配置文件
cp /etc/haproxy/haproxy.cfg{,.ori}
# 修改 haproxy 配置文件,最后添加以下内容
echo '
######### web 代理 ###########
frontend front_web
bind *:80
default_backend back_web
acl test url_reg -i \.txt$
# acl 是固定的关键字
# test 规则名,可自定义
# url_reg 匹配方式
# -i 忽略大小写
# \.txt$ 匹配.txt结尾
# 如果ac规则 test匹配,则使用后端 back_test
use_backend back_test if test
backend back_web
# 采用轮询方式负载
balance roundrobin
server web1 10.1.8.11:80 check
# server 是关键字,代表后端主机
# web1 是后端主机名,可自定义,建议与主机名保持一致
# 10.1.8.11:80 是后端服务实际地址和端口
# check haproxy检查后端服务是否正常
server web2 10.1.8.12:80 check
server web3 10.1.8.13:80 check
backend back_test
balance roundrobin
server test1 10.1.8.11:81 check
server test2 10.1.8.12:81 check
server test3 10.1.8.13:81 check
' >> /etc/haproxy/haproxy.cfg
# 启用并启动服务
systemctl enable haproxy.service --now
测试
bash
[root@client1 ~]# for n in {1..90}; do curl http://10.1.8.10 -s; done | sort |uniq -c
30 Welcome to web1.laoma.cloud
30 Welcome to web2.laoma.cloud
30 Welcome to web3.laoma.cloud
[root@client2 ~]# for n in {1..90}; do curl http://10.1.1.10 -s; done | sort |uniq -c
30 Welcome to web1.laoma.cloud
30 Welcome to web2.laoma.cloud
30 Welcome to web3.laoma.cloud
# 测试 txt结尾的acl规则
[root@client1 ~]# for n in {1..90}; do curl http://10.1.8.10/index.txt -s; done | sort |uniq -c
tcp 模式
配置 ssh
bash
[root@web1-3 ~]#
yum install -y openssh-server
systemctl enable sshd --now
配置 haproxy
bash
# 备份 haproxy 配置文件
cp /etc/haproxy/haproxy.cfg{,.ori}
# 修改 haproxy 配置文件,最后添加以下内容
echo '
######### ssh 代理 ###########
listen ssh
mode tcp
bind *:1022
balance roundrobin
server web1 10.1.8.11:22 check
server web2 10.1.8.12:22 check
server web3 10.1.8.13:22 check
' >> /etc/haproxy/haproxy.cfg
# 重启服务
systemctl restart haproxy.service
测试
bash
[root@client1 ~]# for n in {1..90}; do ssh root@haproxy -p 1022 hostname 2>/dev/null; done| sort |uniq -c
30 web1.laoma.cloud
30 web2.laoma.cloud
30 web3.laoma.cloud
HAProxy 配置说明
haproxy 的配置文件由两部分组成:全局设定(global settings)和对代理的设定(proxies)
- global settings:主要用于定义haproxy进程管理安全及性能相关的参数
- proxies 共分为4段:
- defaults:为其它配置段提供默认参数,默认配置参数可由下一个"defaults"重新设定。
- frontend:定义一系列监听的套接字,这些套接字可接受客户端请求并与之建立连接。
- backend:定义"后端"服务器,前端代理服务器将会把客户端的请求调度至这些服务器。
- listen:定义监听的套接字和后端的服务器。类似于将frontend和backend段放在一起,通常配置TCP流量,也就是4层代理。
所有代理的名称只能使用大写字母、小写字母、数字、-(中线)、_(下划线)、.(点号)和:(冒号)。此外,ACL名称会区分字母大小写。
全局部分
进程管理及安全相关的参数
bash
# log <address> <facility> [max level [min level]]:定义全局的syslog服务器,最多可以定义两个;
log 127.0.0.1 local2
#log-send-hostname [<string>]:在syslog信息的首部添加当前主机名,可以为"string"指定的名称,也可以缺省使用当前主机名;
log-send-hostname haproxy.laoma.cloud
# 变更haproxy工作目录至指定的目录并在放弃权限之前执行chroot()操作,可以提升haproxy的安全级别,不过需要注意的是要确保指定的目录为空目录且任何用户均不能有写权限;
chroot /var/lib/haproxy
# 让haproxy以守护进程方式在后台运行
daemon
# 指定进程pid保存到哪个文件;
pidfile /var/run/haproxy.pid
# 以指定的UID或者user身份运行haproxy进程
uid 188
user haproxy
# 以指定的gID或者group身份运行haproxy进程
gid 188
group haproxy
# 启用unix socket,用于访问统计数据
stats socket /var/lib/haproxy/stats
# 定义当前节点的名称,用于HA场景中多haproxy进程共享同一个IP地址时;
node ha1.laoma.cloud
# 当前实例的描述信息;
description haproxy server 1
性能调整相关的参数
bash
# nbproc <number>:指定启动的haproxy进程的个数,只能用于守护进程模式的haproxy;默认只启动一个进程,鉴于调试困难等多方面的原因,一般只在单进程仅能打开少数文件描述符的场景中才使用多进程模式;
nbproc 2
# ulimit-n:设定每进程所能够打开的最大文件描述符数目,默认情况下其会自动进行计算,因此不推荐修改此选项;Linux默认单进程打开文件数为1024个
# maxconn <number>:设定每个haproxy进程所接受的最大并发连接数,其等同于命令行选项"-n";"ulimit -n"自动计算的结果正是参照此参数设定的;
maxconn 4000
# tune.bufsize <number>:设定buffer的大小,同样的内存条件小,较小的值可以让haproxy有能力接受更多的并发连接,较大的值可以让某些应用程序使用较大的cookie信息;默认为16384,其可以在编译时修改,不过强烈建议使用默认值;
# tune.chksize <number>:设定检查缓冲区的大小,单位为字节;更大的值有助于在较大的页面中完成基于字符串或模式的文本查找,但也会占用更多的系统资源;不建议修改;
# tune.maxaccept <number>:设定haproxy进程内核调度运行时一次性可以接受的连接的个数,较大的值可以带来较大的吞吐率,默认在单进程模式下为100,多进程模式下为8,设定为-1可以禁止此限制;一般不建议修改;
# tune.maxpollevents <number>:设定一次系统调用可以处理的事件最大数,默认值取决于OS;其值小于200时可节约带宽,但会略微增大网络延迟,而大于200时会降低延迟,但会稍稍增加网络带宽的占用量;
# tune.maxrewrite <number>:设定为首部重写或追加而预留的缓冲空间,建议使用1024左右的大小;在需要使用更大的空间时,haproxy会自动增加其值;
# tune.rcvbuf.server <number>:设定内核套接字中服务端或客户端接收缓冲的大小,单位为字节;强烈推荐使用默认值;
代理部分
bash
# 设置haproxy默认工作模式,支持tcp和http
# tcp,工作在4层,HAProxy分只是简单地转发流量
# http,工作在7层,HAProxy分析协议,并可以随意处理请求和响应内容,例如allowing, blocking, switching, adding,modifying, removing。
mode http
# 日志格式与global配置一致
log global
# 日志发送给本地,facility是local0,level是notice
log 127.0.0.1:514 local0 notice
# 日志类别http日志格式,也可指定为tcplog
option httplog
# 不记录没有数据的心跳检测包
option dontlognull
# 允许server端关闭http连接
option http-server-close
# 在转发的包头前加入except 127.0.0.0/8
option forwardfor except 127.0.0.0/8
# 连接失败后,重新分发连接
option redispatch
# 3次连接失败就认为服务不可用
retries 3
# 客户端建立连接但不请求数据时,关闭客户端连接
timeout http-request 10s
# 队列存在最大时长
timeout queue 1m
# haproxy将客户端请求转发至后端服务器所等待的超时时长
timeout connect 10s
# 客户端非活动状态的超时时长
timeout client 1m
# 客户端与服务端建立连接后,等待服务器端的超时时长
timeout server 1m
# 定义保持连接的超时时长
time http-keep-alive 1m
# 健康状态监测超时时长,过短会误判,过长会消耗更多资源
timeout check 10s
HAProxy 使用总结
HAProxy 是高性能开源负载均衡器,支持 TCP 四层与 HTTP 七层代理,核心功能含负载策略(轮询、加权、IP 哈希等)、后端服务器健康检查(主动 / 被动)及会话保持。通过 frontend/backend/listen 配置块定义转发规则,可实现 SSL 终止、请求过滤与流量控制。轻量且高并发,常用于 Web 服务、数据库等场景的高可用架构,搭配日志监控与故障转移配置,能有效提升服务稳定性与资源利用率。