高性能负载均衡软件haproxy
在负载均衡解决方案中,有基于硬件的负载均衡设备,如F5、Big-IP等,也有基于软件的负载均衡产品,如HAProxy、LVS、Nginx,基于软件的负载均衡产品中,又分为两种实现方式:一种基于操作系统的软负载实现方式,如LVS,还有一种是基于第三方应用的实现方式,如HAProxy
一、HAProxy简介:
HAProxy是一款开源的,高性能的,基于TCP(第四层)和HTTP(第七层)应用的负载均衡软件,HAProxy作为一款专业的负载均衡软件,显著特点如下:
- 可靠性和稳定性非常好,可以与硬件级别的F5负载均衡设备相媲美
- 最高可同时维护40000-50000个并发连接,单位时间内处理的最大请求数为20000个,最大数据处理能力可达10Gbit/s
- 支持多于8种负载均衡算法,同时支持会话保持
- 支持虚拟主机功能,实现web负载均衡更加灵活
- 从HAProxy1.3版本后,支持连接拒绝,全透明代理等功能,此功能其他负载均衡器不具备
- HAProxy拥有一个强大的服务器状态监控页面,通过此页面可以实时了解系统的运行情况
- HAProxy拥有强大的ACL支持,为使用带来很大方便
HAProxy是借助操作系统的技术特性来实现性能最大化的,因此在使用的时候,对操作系统的性能调优是十分重要的,业务系统方面,HAProxy非常适用于那些并发量特别大需要持久连接或7层处理机制的web系统,如门户网站或电商网站,也可以用于 MySQL数据库(读操作)的负载均衡
二、4层和7层负载均衡器的区别:
所谓4层就是ISO参考模型中的第4层,4层负载均衡器也称为4层交换机,它主要通过分析IP层及TCP/UDP层的流量实现基于IP加端口的负载均衡,基于4层的常见负载均衡器有LVS,F5等
以常见的TCP应用为例,负载均衡器在接收到一个来自客户端的SYN请求时,会通过设定的负载均衡算法选择一个最佳的后端服务器,同时将报文中的目标IP地址修改为后端服务器的IP,然后直接转发到后端服务器,这样一个负载均衡请求就完成了,从这个过程来看,一个TCP连接是客户端和服务器直接建立的,而负载均衡器只不过完成了一个类型路由器的转发动作,4层负载转发原理,如图:

在某些负载均衡策略中,为了保证后端服务器返回的报文可以正确传递给负载均衡器,在转发报文的同时可能还会对报文原来的源地址进行修改
7层负载均衡器也称为7层交换机,位于OSI最高层,即应用层,此时的负载均衡器支持多种协议,常见的有http、ftp、smtp等 ,7层负载均衡器可以根据报文内容,在配合负载均衡算法来选择后端服务器,因此也称为”内容交换器”,7层负载均衡器不但可以根据IP+端口的方式进行负载分流,还可以根据网站的URL、访问域名、浏览器类别、语言等决定负载均衡的策略,常见的7层负载均衡器有HAProxy、Nginx等。
以常见的TCP引用为例子,由于负载均衡器需要获取到报文的内容,因此只能先代替后端服务器和客户端建立连接,接着才能收到客户端发送过来的报文内容,然后根据该报文中的特定字段加上负载均衡器中设置的负载均衡算法来决定最终选择的后端服务器,此时,7层负载均衡器类似于一个代理服务器。

对比4层负载均衡器和7层负载均衡器运行的整个过程,可以看出,7层负载均衡器模式下,负载均衡器与客户端以及后端服务器会分别建立一个TCP连接,而4层负载均衡器模式下,仅仅建立一个TCP连接,由此可知,7层负载均衡器对负载设备的要求更高,但是处理能力明显低于4层负载均衡器
三、HAProxy与LVS的异同
- 两者都是负载均衡产品,LVS是基于Linux系统实现的软负载均衡,而HAProxy是基于第三方应用实现的软负载均衡
- LVS是基于4层的IP负载均衡技术,而HAProxy是基于4层和7层技术可提供TCP和HTTP应用的负载均衡解决方法
- LVS工作在ISO模型的第4层,因此其状态检测功能单一,而HAProxy在状态检测方面功能强大,可支持端口、URL、脚本等多种方式状态检测方式
- HAProxy虽然功能强大,但是整体性能低于LVS,LVS拥有接近硬件设备的网络吞吐和连接负载能力

四、部署:
| 操作系统 | haproxy版本 |
| ubuntu 20.04.6LTS | 3.2.2 |
1、首先下载haproxy软件包,上传到服务器,解压缩,如图:

2、安装依赖软件包,如下:
apt -y install gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel net-tools vim iotop bc zip unzip zlib-devel lrzsz tree screen lsof tcpdump wget ntpdate
3、进入解压目录,执行命令进行编译,如下:
cd haproxy-3.2.2
make TARGET=linux-glibc USE_OPENSSL=1 USE_PCRE=1 USE_ZLIB=1 PREFIX=/usr/local/haproxy
TARGET=linux-glibc:指定目标平台(64位 Linux + glibc)USE_OPENSSL=1:启用 SSL/TLS 支持USE_PCRE=1:启用正则表达式支持USE_ZLIB=1:启用数据压缩支持
4、再次执行命令进行安装,如下:
make install PREFIX=/usr/local/haproxy
5、创建haproxy软链接,如下:
ln -s /usr/local/haproxy/sbin/haproxy /usr/bin/haproxy
6、使用systemd托管,编辑/lib/systemd/system/haproxy.service,内容如下:
[Unit]
Description=HAProxy Load Balancer
After=network.target
[Service]
Environment="CONFIG=/usr/local/haproxy/conf/haproxy.cfg" "PIDFILE=/run/haproxy.pid"
ExecStartPre=/usr/bin/haproxy -f $CONFIG -c -q
ExecStart=/usr/bin/haproxy -Ws -f $CONFIG -p $PIDFILE
ExecReload=/bin/kill -USR2 $MAINPID
KillMode=mixed
Restart=always
Type=notify
[Install]
WantedBy=multi-user.target
检查haproxy配置文件是否有错误的语法是:
haproxy -c -f haproxy.cfg #只是检查语法错误,不会启动haproxy
五、使用
HAProxy 的配置文件主要由 global、defaults、frontend 和 backend 等部分组成,其中 global 和 defaults 是两种不同作用范围的配置段,区别如下:
| 特性 | global段 | defaults段 |
| 作用对象 | HAProxy 进程本身 | 代理配置(frontend/backend) |
| 配置级别 | 进程级 | 代理级 |
| 生效方式 | 需要重启 | 通常只需reload |
| 配置继承 | 不继承 | 被frontend/backend继承 |
| 可定义数量 | 只能有一个 | 可以有多个(后者覆盖前者) |
| 修改频率 | 低频 | 相对高频 |
global的常用配置如下:
global
# 进程和安全相关
daemon # 以守护进程方式运行
user haproxy # 运行用户
group haproxy # 运行组
pidfile /var/run/haproxy.pid # PID文件位置
maxconn 100000 # 每个进程最大连接数
# 性能调优
nbthread 2 # 每个haproxy进程的线程数(可设置为cpu核心数)
maxcompcpuusage 50 # 最大CPU压缩使用率
# SSL/TLS 全局设置
ssl-default-bind-ciphers HIGH:!aNULL:!MD5
ssl-default-server-ciphers HIGH:!aNULL:!MD5
# 日志设置
log 127.0.0.1 local0 # 日志服务器地址和设施
log-tag haproxy # 日志前缀
# 统计和监控
stats socket /var/run/haproxy.sock mode 600 level admin
#性能调优
tune.ssl.default-dh-param 2048
tune.maxrewrite 1024
tune.bufsize 16384
tune.http.maxhdr 100
defaults的常用配置项为:
defaults
# 默认代理模式
mode http/tcp # 或 tcp
# 超时设置
timeout connect 5s # 连接后端超时
timeout client 30s # 客户端空闲超时
timeout server 30s # 服务器响应超时
# 日志设置(可选)
option httplog/tcplog # 详细HTTP日志
option dontlognull # 不记录空连接
# 健康检查(可选)
option redispatch # 连接失败时重试其他服务器
option httpchk GET /health # HTTP健康检查端点
# 连接管理
retries 3 # 最大重试次数
maxconn 2000 # 前端最大连接数
# HTTP相关
option forwardfor # 添加X-Forwarded-For头
option http-keep-alive # 保持HTTP连接
1、下面配置一个简单的tcp代理,haproxy.cfg内容如下:

- defaults:定义一个tcp的默认配置
- frontend:可以理解为配置监听器,后面名字可自定义
- bind:监听端口为86
- default_backend:关联的后端服务为tcp_port,这个名字也可自定义
- backend:后端名字,要与default_backend中对应
- balance roundrobin:使用轮询负载均衡算法
- server:后端的服务,port1是服务名,可自定义,server可以写多个的
- check:检查端口io是否能建立连接(三次握手),检查失败就剔除此server
上面配置的含义是:请求haproxy本机的86端口将会代理到51.223的22端口,测试下:

- 通过本机ip:86端口+远程主机的用户名gong来登录远程主机
check的相关参数如下:
| 参数 | 示例 | 说明 |
| inter | inter 2000ms | 检查间隔(默认 2 秒) |
| rise | rise 2 | 成功几次标记为 UP(默认 2 次) |
| fall | fall 3 | 失败几次标记为 DOWN(默认 3 次) |
| port | port 8080 | 指定检查的端口(不同于服务端口时使用) |
| verifyhost | verifyhost example.com | SSL 检查时验证主机名 |

2、配置TCP模式代理443端口,代理443端口有两种模式:
- SSL/TLS透传(TCP模式):haproxy只负责转发到后面服务器,不解密SSL/TLS流量,证书配置在后端,全程加密,更安全,性能比终止模式略低
- SSL/TLS终止(HTTP模式):haproxy解密SSL/TLS流量,处理HTTP请求再转发到后端服务器,haproxy到后端之间是明文的(纯内网可以),客户端到haproxy之间是加密的,证书全部由haproxy管理,性能高
(1)、先看下透传模式(TCP模式)下的配置,defaults还是用上面默认的,如图:

第35行:检查 TCP 请求内容时的最大延迟时间,在 SSL/TLS 透传模式下,客户端的 SSL/TLS 握手请求可能需要一些时间才能完全到达 HAProxy。如果 HAProxy 没有足够的等待时间,可能会导致无法正确解析 SNI 字段,从而影响流量的正确分发,可以根据实际网络情况和需求进行调整- 第36行:检查客户端的 SSL/TLS 握手请求是否是
ClientHello类型。ClientHello是 SSL/TLS 握手过程中的第一个消息,客户端通过这个消息向服务器发起连接请求 - 第38行:定义acl规则,规则名字可以自定义,但是一般跟请求域名一样,方便识别,req_ssl_sni是条件检查,用于检查SSL/TLS请求中的SNI字段,指定目标服务器域名,-i是不区分大小写
- 第39行:if test.cnsignet.com的意思是如果上面的acl规则成立,也就是sni的的域名就是test.cnsignet.com那就发送给后端服务器,user_backend test指定后端服务,这里的test要跟后面的backend test中对应,才能找到后面的服务器,if 后面的这个域名就是前面的acl的规则名
- 第41行:针对不同域名要定义多个acl规则和多个backend
注:这里ssl证书此时是配置在51.223这台后端服务器上的
(2)、终止模式(HTTP模式)配置略有不同
先在global全局配置中增加如下内容:
#加密套件
ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
#禁用不安全的协议
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
# 启用 TLS 1.3(HAProxy 2.0+)
ssl-default-bind-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
defaults配置也不用改动,直接用最上面的就行,接下来看下监听配置和后端配置,如图:

第28行:指定证书的位置,可将pem和key都放在此路径下,key的前面还要加.pem,如图:

第31行:hdr(host) 是ACL的条件表达式,用于匹配HTTP 请求头中的 Host 字段它是实现 基于域名的流量路由 的核心功能之一,此处的acl规则语法如下:
acl <规则名称> hdr(host) -i <域名>
第38行:轮询负载,这个是针对多个server的
注意:acl可以配置多个,对应的backend就有多个,backend中的server也可以有多个
3、haproxy也可以配置根据不同的请求路径转到后面的服务,这个参数是path_beg,如果架构是haproxy–>nginx–>后端服务,那么就可以在nginx那里配置根据路径匹配到后端服务,haproxy这里只做一层域名请求的转发到nginx就行了


