目录
1 haproxy概述
1.1 haproxy简介
haproxy是法国开发者 威利塔罗(Willy Tarreau) 在2000年使用C语言开发的一个开源软件,是一款具备高并发(万级以上)、高性能的TCP和HTTP负载均衡器,专为TCP和HTTP应用而设计。它可以将客户端的请求分发到多台后端服务器,从而提高应用的可用性和性能。HAProxy支持多种负载均衡算法和健康检查机制,是构建高可用性系统的理想选择。
企业版网站:https://www.haproxy.com
社区版网站:http://www.haproxy.org
(图中为社区版网站)
1.2 haproxy主要特性
- 高性能负载均衡: HAProxy通过优化的事件驱动引擎,能够以最小的系统资源开销处理大量并发请求。它支持多种负载均衡算法,如轮询、最少连接、源IP哈希等,可根据实际业务需求灵活配置
- 健康检查与故障恢复: HAProxy具备完善的后端服务器健康检查机制,可以根据响应时间、错误率等因素自动剔除不健康的后端节点,并在节点恢复时重新将其加入到服务池中,确保服务连续性
- 会话保持与亲和性: 为了保证用户的会话一致性,HAProxy支持基于cookie或源IP地址的会话保持功能,确保同一客户端的请求被转发到同一台后端服务器进行处理
- 安全性与SSL卸载: HAProxy支持SSL/TLS加密传输,可对HTTPS流量进行解密并透明地分发至后端服务器,同时也能终止SSL连接以减轻服务器的加密计算压力
- 高级路由与策略: 根据HTTP请求头、URL路径、内容类型等条件,HAProxy可以执行复杂的路由规则和ACL策略,使得负载均衡更加智能化和精准化
- 日志记录与监控: HAProxy提供丰富的日志记录选项,可通过syslog、CSV格式输出等方式收集统计数据,便于运维人员实时监控系统状态和性能指标
1.3 haproxy的优点与缺点
优点:
- 高性能:Haproxy是专门为高性能设计的,具有低延迟和并发处理能力。
- 灵活:Haproxy具有丰富的配置选项,可以满足各种复杂的负载均衡需求。
- 可扩展性:Haproxy支持插件扩展,可以轻松地集成到现有的系统中。
- 安全性:Haproxy提供了SSL/TLS加密、访问控制列表(ACL)等安全功能。
缺点:
- 配置复杂:Haproxy的配置可能比其他一些负载均衡器更复杂,需要一定的学习和经验。
- 成本较高:Haproxy是一款商业软件,需要购买许可证才能使用。
2 负载均衡介绍
2.1什么是负载均衡
负载均衡:Load Balance,简称LB,是一种服务或基于硬件设备等实现的高可用反向代理技术,负载均衡将特定的业务(web服务、网络流量等)分担给指定的一个或多个后端特定的服务器或设备,从而提高了公司业务的并发处理能力、保证了业务的高可用性、方便了业务后期的水平动态扩展
2.2 为什么使用负载均衡
- Web服务器的动态水平扩展-->对用户无感知
- 增加业务并发访问及处理能力-->解决单服务器瓶颈问题
- 节约公网IP地址-->降低IT支出成本
- 隐藏内部服务器IP-->提高内部服务器安全性
- 配置简单-->固定格式的配置文件
- 功能丰富-->支持四层和七层,支持动态下线主机
- 性能较强-->并发数万甚至数十万
2.3 负载均衡类型
2.3.1 四层负载均衡
- 通过ip+port决定负载均衡的去向。
- 对流量请求进行NAT处理,转发至后台服务器。
- 记录tcp、udp流量分别是由哪台服务器处理,后续该请求连接的流量都通过该服务器处理。
- 支持四层的软件
- lvs:重量级四层负载均衡器。
- Nginx:轻量级四层负载均衡器,可缓存。(nginx四层是通过upstream模块
- Haproxy:模拟四层转发。
2.3.2 七层负载均衡
- 通过虚拟ur|或主机ip进行流量识别,根据应用层信息进行解析,决定是否需要进行负载均衡。
- 代理后台服务器与客户端建立连接,如nginx可代理前后端,与前端客户端tcp连接,与后端服务器建立tcp连接,
- 支持7层代理的软件:
- Nginx:基于http协议(nginx七层是通过proxy_pass)
- Haproxy:七层代理,会话保持、标记、路径转移等。
2.3.3 四层和七层的区别
- 七层负载均衡:基本都是基于http协议,适用于web服务器的负载均衡
- 四层负载均衡:基于TCP协议,可以做任何基于tcp/ip协议的负载均衡(haproxy, LVS)
- 二者主要区别在于利用的报文所在的层面是不同的,各有各的好处。
- 七层负载均衡的好处,是使得整个网络更“智能化”。例如访问一个网站的用户流量,可以通过七层的方式,将对图片类的请求转发到特定的图片服务器,并可以利用缓存技术;将对文字类的请求转发到特定的文字服务器,并可以利用压缩技术。
从技术原理上,七层负载可以对客户端的请求和服务器的响应进行任何意义上的修改,极大的提升了应用系统在网络层的灵活性。例如nginx或apache上部署的功能可以迁移到负载均衡器上,例如客户请求中的Header重写,服务器响应中的关键字过滤或内容插入等功能。- 四层负载均衡的优点是较为灵活,可以作为多种软件的负载均衡器。
举个例子形象的说明:四层负载均衡就像银行的自助排号机,每一个到银行的客户,根据排号机的顺序,选择对应的窗口接受服务;而七层负载均衡像银行大堂经理,先确认客户需要办理的业务,再安排排号。这样办理理财、存取款等业务的客户,会去不同的地方排队,加快了业务办理流程。
3 haproxy的安装及服务
3.1 实验环境
角色 | IP |
client(测试机,非必须) | nat-eth0:172.25.254.10 |
haproxy | nat-eth0:172.25.254.100 仅主机-eth1:192.168.0.100 |
webserver1 | 仅主机-eth0:192.168.0.10 GW:192.168.0.100 |
webserver2 | 仅主机-eth0:192.168.0.20 GW:192.168.0.100 |
(1)所有主机关闭防火墙和selinux
systemctl stop firewalld # 临时关闭防火墙
systemctl disable firewalld # 永久关闭防火墙
setenforce 0 # 临时关闭selinux
(2)两台webserver安装nginx
#webserver1
[root@webserver1 ~]# yum install nginx -y
[root@webserver1 ~]# echo webserver1 - 192.168.0.10 > /usr/share/nginx/html/index.html
[root@webserver1 ~]# systemctl enable --now nginx
#webserver2
[root@webserver2 ~]# yum install nginx -y
[root@webserver2 ~]# echo webserver2 - 192.168.0.20 > /usr/share/nginx/html/index.html
[root@webserver2 ~]# systemctl enable --now nginx
client访问测试:
3.2 haproxy的基本配置
3.2.1 haproxy的基本配置信息
HAProxy 的配置文件haproxy.cfg由两大部分组成,分别是:
global:全局配置段
进程及安全配置相关的参数
性能调整相关参数
Debug参数
proxies:代理配置段
defaults:为frontend, backend, listen提供默认配置
frontend:前端,相当于nginx中的server {}
backend:后端,相当于nginx中的upstream {}
listen:同时拥有前端和后端配置,配置简单,生产推荐使用官方文档: http://cbonte.github.io/haproxy-dconv/
3.2.2 haproxy的基本部署
# 安装haproxy
[root@haproxy ~]# yum install haproxy -y
# 编辑配置文件
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
#上面内容忽略
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend webcluster # 设定前端
bind *:80
mode http
use_backend webcluster-host
backend webcluster-host # 设定后端
balance roundrobin
server web1 192.168.0.10:80
server web2 192.168.0.20:80
[root@haproxy ~]# systemctl restart haproxy.service
[root@haproxy ~]# systemctl enable haproxy.service
# 另一种方法,将前后端合并,如果用了第一种别忘把之前写的注释掉
listen webcluster
bind *:80
mode http
balance roundrobin
server web1 192.168.0.10:80
server web2 192.168.0.20:80
[root@haproxy ~]# systemctl restart haproxy.service
在client访问测试(两种方法测试结果一样):
3.2.3 global配置
3.2.3.1global参数说明
参数 | 类型 | 作用 |
chroot | 全局 | 锁定运行目录 |
deamon | 全局 | 以守护进程运行 |
user, group, uid, gid | 全局 | 运行 haproxy 的用户身份 |
stats socket | 全局 | 套接字文件 |
nbproc N | 全局 | 开启的 haproxy worker 进程数,默认进程数是一个 |
nbthread 1 (和 nbproc 互斥) | 全局 | 指定每个 haproxy 进程开启的线程数,默认为每个进程一个线程 |
cpu-map 1 0 | 全局 | 绑定 haproxy worker 进程至指定 CPU ,将第 1 个 work 进程绑定至0 号 CPU |
cpu-map 2 1 | 全局 | 绑定 haproxy worker 进程至指定 CPU ,将第 2 个 work 进程绑定至1 号 CPU |
maxconn N | 全局 | 每个 haproxy 进程的最大并发连接数 |
maxsslconn N | 全局 | 每个 haproxy 进程 ssl 最大连接数 , 用于 haproxy 配置了证书的场景下 |
maxconnrate N | 全局 | 每个进程每秒创建的最大连接数量 |
spread-checks N | 全局 | 后端 server 状态 check 随机提前或延迟百分比时间,建议 2- 5(20%-50%)之间,默认值 0 |
pidfile | 全局 | 指定 pid 文件路径 |
log 127.0.0.1 local2 info | 全局 | 定义全局的 syslog 服务器;日志服务器需要开启 UDP 协议,最多可以定义两个 |
3.2.3.2 haproxy的全局配置参数
[root@haproxy ~]# pstree -p | grep haproxy
|-haproxy(1919)---haproxy(1921)---{haproxy}(1922) # 只有一个进程
nbproc 设置多进程
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
...........
# utilize system-wide crypto-policies
ssl-default-bind-ciphers PROFILE=SYSTEM
ssl-default-server-ciphers PROFILE=SYSTEM
nbproc 2 # 启用多进程
cpu-map 1 0 # 表示第一个线程用第一个CPU核心
cpu-map 2 1 # 表示第二个线程用第二个CPU核心
.............
[root@haproxy ~]# systemctl restart haproxy.service
[root@haproxy ~]# pstree -p | grep haproxy
|-haproxy(2012)-+-haproxy(2014)
| `-haproxy(2015)
# 查看多线程数量
[root@haproxy ~]# cat /proc/2015/status | grep -i thread
Threads: 1 # 现在线程数量为1
Speculation_Store_Bypass: thread vulnerable
-------------------------------------------------------------
nbthread 设定多线程
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
...........
# utilize system-wide crypto-policies
ssl-default-bind-ciphers PROFILE=SYSTEM
ssl-default-server-ciphers PROFILE=SYSTEM
#nbproc 2
#cpu-map 1 0
#cpu-map 2 1
nbthread 2
...........
[root@haproxy ~]# systemctl restart haproxy.service
[root@haproxy ~]# pstree -p | grep haproxy
|-haproxy(2048)---haproxy(2050)---{haproxy}(2051)
[root@haproxy ~]# cat /proc/2050/status | grep -i thread
Threads: 2 # 现在线程数量为2
Speculation_Store_Bypass: thread vulnerable
注意:多线程与多进程互斥,多进程与多线程同时设定重启服务的时候会报错(下图是错误示范)
3.2.3.3 定向haproxy日志
[root@haproxy ~]# vim /etc/rsyslog.conf
编辑图中两处地方:
删掉图中最后两行的注释符
添加这一行信息
[root@haproxy ~]# systemctl restart rsyslog.service
3.2.4 proxies配置
参数 | 类型 | 作用 |
defaults [ ] | proxies | 默认配置项,针对以下的 frontend 、 backend 和 listen 生效,可以多个name也可以没有 name |
frontend | proxies | 前端 servername ,类似于 Nginx 的一个虚拟主机 server 和 LVS 服务集群。 |
backend | proxies | # 后端服务器组,等于 nginx 的 upstream 和 LVS 中的 RS 服务器 |
listen | proxies | # 将 frontend 和 backend 合并在一起配置,相对于 frontend 和 backend配置更简洁,生产常用 |
proxies配置-defaults
mode http
# HAProxy 实例使用的连接协议
log global
# 指定日志地址和记录日志条目的
syslog/rsyslog 日志设备
#此处的 global 表示使用 global 配置段中设定的log 值。
option httplog
# 日志记录选项, httplog 表示记录与 HTTP会话相关的各种属性值
# 包括 HTTP 请求、会话状态、连接数、源地 址以及连接时间等
option dontlognull
#dontlognull 表示不记录空会话连接日志
option http-server-close
# 等待客户端完整 HTTP 请求的时间,此处为等待10s 。
option forwardfor except 127 .0.0.0/8
# 透传客户端真实 IP 至后端 web 服务器
# 在 apache 配置文件中加入 :<br>%{XForwarded-For}
# 后在 webserer 中看日志即可看到地址透传信息
option redispatch
# 当 server Id 对应的服务器挂掉后,强制定向到其他健康的服务器,重新派发
option http-keep-alive
# 开启与客户端的会话保持
retries 3
# 连接后端服务器失败次数
timeout http-request 1000s
# 等待客户端请求完全被接收和处理的最长时间
timeout queue 60s
# 设置删除连接和客户端收到 503 或服务不可用等提示信息前的等待时间
timeout connect 120s
# 设置等待服务器连接成功的时间
timeout client 600s
# 设置允许客户端处于非活动状态,即既不发送数据也不接收数据的时间
timeout server 600s
# 设置服务器超时时间,即允许服务器处于既不接收也不发送数据的非活动时间
timeout http-keep-alive 60s
#session 会话保持超时时间,此时间段内会转发到相同的后端服务器
timeout check 10s
# 指定后端服务器健康检查的超时时间
maxconn 3000
default-server inter 1000 weight 3 指定后端服务器默认设置
proxies配置-frontend
frontend 配置参数:
bind :指定 HAProxy 的监听地址,可以是 IPV4 或 IPV6 ,可以同时监听多个 IP 或端口,可同时用于 listen 字段中
# 格式:
bind [<address>]:<port_range> [, ...] [param*]
# 注意:如果需要绑定在非本机的 IP ,需要开启内核参数: net.ipv4.ip_nonlocal_bind=1
backlog <backlog> # 针对所有 server 配置 , 当前端服务器的连接数达到上限后的后援队列长度,注意:不支持backend
proxies配置-backend
- 定义一组后端服务器, backend 服务器将被 frontend 进行调用。
- 注意 : backend 的名称必须唯一 , 并且必须在 listen 或 frontend 中事先定义才可以使用 , 否则服务无法启动
mode http|tcp # 指定负载协议类型 , 和对应的 frontend 必须一致
option # 配置选项
server # 定义后端 real server, 必须指定 IP 和端口
server配置
# 针对一个 server 配置check #对指定 real 进行健康状态检查,如果不加此设置,默认不开启检查 , 只有 check 后面没有其它配置也可以启用检查功能#默认对相应的后端服务器IP和端口 , 利用 TCP 连接进行周期性健康性检查 , 注意必须指定端口才能实现健康性检查addr <IP> #可指定的健康状态监测IP ,可以是专门的数据网段,减少业务网络的流量port <num> #指定的健康状态监测端口inter <num> #健康状态检查间隔时间,默认 2000 msfall <num> #后端服务器从线上转为线下的检查的连续失效次数,默认为 3rise <num> # 后端服务器从下线恢复上线的检查的连续有效次数,默认为 2weight <weight> # 默认为 1 ,最大值为 256 , 0( 状态为蓝色 ) 表示不参与负载均衡,但仍接受持久连接backup #将后端服务器标记为备份状态, 只在所有非备份主机 down 机时提供服务,类似 Sorry Serverdisabled #将后端服务器标记为不可用状态,即维护状态,除了持久模式#将不再接受连接,状态为深黄色, 优雅下线 , 不再接受新用户的请求redirect prefix http://www.baidu.com/ #将请求临时 (302) 重定向至其它 URL ,只适用于 http 模式maxconn <maxconn> #当前后端server的最大并发连接数
利用check、inter、fall、rise、weight进行后端健康检测
vim /etc/haproxy/haproxy.cfg
server web1 192.168.0.10:80 check inter 2 fall 3 rise 5 weight 2
服务器 web1 的地址为 192.168.0.10:80,检查间隔为2,故障阈值为3,恢复阈值为5,权重为2
server web2 192.168.0.20:80 check inter 2 fall 3 rise 5 weight 1服务器 web2 的地址为 192.168.0.20:80,检查间隔为2,故障阈值为3,恢复阈值为5,权重为1
[root@haproxy ~]# systemctl reload haproxy
root@haproxy ~]# systemctl restart haproxy.service
测试
[root@haproxy ~]# curl 172.25.254.100
webserver - 172.25.254.10
[root@haproxy ~]# curl 172.25.254.100
webserver2 - 172.25.254.20
网页重定向
修改配置文件
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
[root@haproxy ~]# systemctl restart haproxy.service
测试
在浏览器输入haproxy的IP:
回车后跳转到该页面:
3.3 haproxy热处理
socat工具
对服务器动态权重和其它状态可以利用 socat工具进行调整,Socat 是 Linux 下的一个多功能的网络工具,名字来由是Socket CAT,相当于netCAT的增强版.Socat 的主要特点就是在两个数据流之间建立双向通道,且支持众多协议和链接方式。如 IP、TCP、 UDP、IPv6、Socket文件等
单线程
# mode调整scoket的参数设置
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
..........
# turn on stats unix socket
stats socket /var/lib/haproxy/stats mode 600 level admin
[root@haproxy ~]# systemctl restart haproxy.service
[root@haproxy ~]# ll /var/lib/haproxy/stats
srw------- 1 root root 0 Aug 14 23:19 /var/lib/haproxy/stats
# 下载scoat包
[root@haproxy ~]# yum install socat -y
# 查看haproxy状态
[root@haproxy ~]# echo "show info" | socat stdio /var/lib/haproxy/stats
Name: HAProxy
Version: 2.4.17-9f97155
Release_date: 2022/05/13
Nbthread: 2
Nbproc: 1
Process_num: 1
Pid: 2916
Uptime: 0d 0h30m15s
Uptime_sec: 1815
Memmax_MB: 0
PoolAlloc_MB: 0
PoolUsed_MB: 0
PoolFailed: 0
Ulimit-n: 8037
· · · · · ·
# 查看集群状态
[root@haproxy ~]# echo "show servers state" | socat stdio /var/lib/haproxy/stats
1
# be_id be_name srv_id srv_name srv_addr srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_result srv_check_health srv_check_state srv_agent_state bk_f_forced_id srv_f_forced_id srv_fqdn srv_port srvrecord srv_use_ssl srv_check_port srv_check_addr srv_agent_addr srv_agent_port
2 webcluster 1 web1 192.168.0.10 2 0 2 2 2252 6 3 7 6 0 0 0 - 80 - 0 0 - - 0
2 webcluster 2 web2 192.168.0.20 2 0 1 1 2252 6 3 7 6 0 0 0 - 80 - 0 0 - - 0
4 static 1 static 127.0.0.1 0 0 1 1 2251 8 2 0 6 0 0 0 - 4331 - 0 0 - - 0
5 app 1 app1 127.0.0.1 0 0 1 1 2251 8 2 0 6 0 0 0 - 5001 - 0 0 - - 0
5 app 2 app2 127.0.0.1 0 0 1 1 2251 8 2 0 6 0 0 0 - 5002 - 0 0 - - 0
5 app 3 app3 127.0.0.1 0 0 1 1 2250 8 2 0 6 0 0 0 - 5003 - 0 0 - - 0
5 app 4 app4 127.0.0.1 0 0 1 1 2250 8 2 0 6 0 0 0 - 5004 - 0 0 - - 0
# 查看集群权重
[root@haproxy ~]# echo get weight webcluster/web1 | socat stdio /var/lib/haproxy/stats
2 (initial 2)
[root@haproxy ~]# echo get weight webcluster/web2 | socat stdio /var/lib/haproxy/stats
1 (initial 1)
# 设置权重
[root@haproxy ~]# echo "set weight webcluster/web1 1 " | socat stdio /var/lib/haproxy/stats
[root@haproxy ~]# echo "set weight webcluster/web1 2 " | socat stdio /var/lib/haproxy/stats
# 下线后端服务器
[root@haproxy ~]# echo "disable server webcluster/web1 " | socat stdio /var/lib/haproxy/stats
[root@client ~]# for i in {1..10}; do curl 172.25.254.100;done
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
# 上线后端服务器
[root@haproxy ~]# echo "enable server webcluster/web1 " | socat stdio /var/lib/haproxy/stats
[root@client ~]# for i in {1..10}; do curl 172.25.254.100;done
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
...........
# turn on stats unix socket
stats socket /var/lib/haproxy/stats1 mode 600 level admin process 1
stats socket /var/lib/haproxy/stats2 mode 600 level admin process 2
# utilize system-wide crypto-policies
ssl-default-bind-ciphers PROFILE=SYSTEM
ssl-default-server-ciphers PROFILE=SYSTEM
nbproc 2
cpu-map 1 0
cpu-map 2 1
...........
# 这样重启haproxy后,每个进程就会有单独的sock文件来进行单独管理
[root@haproxy ~]# systemctl restart haproxy.service
[root@haproxy ~]# ll /var/lib/haproxy/
total 0
srw------- 1 root root 0 Aug 15 00:18 stats
srw------- 1 root root 0 Aug 15 00:29 stats1
srw------- 1 root root 0 Aug 15 00:29 stats2
4 haproxy算法
HAProxy 通过固定参数 balance 指明对后端服务器的调度算法
balance 参数可以配置在 listen 或 backend 选项中。
HAProxy 的调度算法分为静态和动态调度算法
有些算法可以根据参数在静态和动态算法中相互转换。
4.1 静态算法
静态算法:按照事先定义好的规则轮询公平调度,不关心后端服务器的当前负载、连接数和响应速度等,且无法实时修改权重( 只能为 0 和 1, 不支持其它值 ) ,只能靠重启 HAProxy 生效。
4.1.1 static-rr:基于权重的轮询调度
- 不支持运行时利用socat进行权重的动态调整(只支持0和1,不支持其它值)
- 不支持端服务器慢启动
- 其后端主机数量没有限制,相当于LVS中的 wrr
慢启动是指在服务器刚刚启动上不会把他所应该承担的访问压力全部给它,而是先给一部分,当没问题后在给一部分
例子:
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
.......
listen webcluster
bind *:80
mode http
balance static-rr
server web1 192.168.0.10:80 check inter 2 fall 3 rise 5 weight 2
server web2 192.168.0.20:80 check inter 2 fall 3 rise 5 weight 1
.......
[root@haproxy ~]# systemctl restart haproxy.service
# client测试
[root@client ~]# for i in {1..10}; do curl 172.25.254.100;done
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
4.1.2 first
- 根据服务器在列表中的位置,自上而下进行调度
- 其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务
- 其会忽略服务器的权重设置
- 不支持用socat进行动态修改权重,可以设置0和1,可以设置其它值但无效
例子:
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
.......
listen webcluster
bind *:80
mode http
balance first
server web1 192.168.0.10:80 check inter 2 fall 3 rise 5 weight 2
server web2 192.168.0.20:80 check inter 2 fall 3 rise 5 weight 1
.......
[root@haproxy ~]# systemctl restart haproxy.service
[root@client ~]# for i in {1..10}; do curl 172.25.254.100;done
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
4.2 动态算法
- 基于后端服务器状态进行调度适当调整,
- 新请求将优先调度至当前负载较低的服务器
- 权重可以在haproxy运行时动态调整无需重启
4.2.1 roundrobin
- 基于权重的轮询动态调度算法,
- 支持权重的运行时调整,不同于 lvs 中的 rr 轮训模式,
- HAProxy 中的 roundrobin 支持慢启动 ( 新加的服务器会逐渐增加转发数 ) ,
- 其每个后端 backend 中最多支持 4095 个 real server ,
- 支持对 real server 权重动态调整,
- roundrobin 为默认调度算法 , 此算法使用广泛
优先把流量给权重高且负载小的主机,以负载为主
4.2.2 leastconn
- leastconn加权的最少连接的动态
- 支持权重的运行时调整和慢启动(相当于LVS的wlc),即:根据当前连接最少的后端服务器而非权重进行优先调度(新客户端连接)【当两个主机的连接数都差不多的时候给权重高的,权重是次考虑的】
- 比较适合长连接的场景使用,比如:MySQL等场景。
4.3 其他算法
其它算法即可作为静态算法,又可以通过选项成为动态算法
4.3.1 source
源地址 hash ,基于用户源地址 hash 并将请求转发到后端服务器,后续同一个源地址请求将被转发至同一 个后端web 服务器。此方式当后端服务器数据量发生变化时,会导致很多用户的请求转发至新的后端服务器,默认为静态方式,但是可以通过hash-type 支持的选项更改这个算法一般是在不插入 Cookie 的 TCP模式下使用,也可给拒绝会话cookie 的客户提供最好的会话粘性,适用于 session 会话保持但不支持 cookie和缓存的场景源地址有两种转发客户端请求到后端服务器的服务器选取计算方式,分别是取模法和一致性hash
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
.......
listen webcluster
bind *:80
mode http
balance source
server web1 192.168.0.10:80 check inter 2 fall 3 rise 5 weight 2
server web2 192.168.0.20:80 check inter 2 fall 3 rise 5 weight 1
.......
[root@haproxy ~]# systemctl restart haproxy.service
[root@client ~]# for i in {1..10}; do curl 172.25.254.100;done
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
4.3.1.1 map-base 取模法
map-based :取模法,对 source 地址进行 hash 计算,再基于服务器总权重的取模,最终结果决定将此请求转发至对应的后端服务器。
此方法是静态的,即不支持在线调整权重,不支持慢启动,可实现对后端服务器均衡调度
缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因总权重发生变化而导致调度结果 整体改变 , hash-type 指定的默值为此算法
所谓取模运算,就是计算两个数相除之后的余数, 10%7=3, 7%4=3
map-based 算法:基于权重取模, hash(source_ip)% 所有后端服务器相加的总权重
比如当源hash值时1111,1112,1113,三台服务器a b c的权重均为1,
即abc的调度标签分别会被设定为 0 1 2(1111%3=1,1112%3=2,1113%3=0)
1111 ----- > nodeb
1112 ------> nodec
1113 ------> nodea
如果a下线后,权重数量发生变化
1111%2=1,1112%2=0,1113%2=1
1112和1113被调度到的主机都发生变化,这样会导致会话丢失
4.3.1.2 一致性hash
一致性哈希,当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动hash (o) mod n
该hash算法是动态的,支持使用socat等工具进行在线权重调整,支持慢启动
算法
- key1=hash(source_ip)%(2^32)
- keyA=hash(后端服务器虚拟ip)%(2^32) [0—4294967295]
- 将key1和keyA都放在hash环上,将用户请求调度到离key1最近的keyA对应的后端服务器
hash 环偏斜问题
增加虚拟服务器 IP 数量,比如:一个后端服务器根据权重为 1 生成 1000 个虚拟 IP ,再 hash 。而后端服务器权 重为2 则生成 2000 的虚拟 IP ,再 bash, 最终在 hash 环上生成 3000 个节点,从而解决 hash 环偏斜问题
hash对象
Hash对象到后端服务器的映射关系
![](https://i-blog.csdnimg.cn/direct/22fc85f5936c46df8ddf11e2da483204.jpeg)
4.3.2 uri
基于对用户请求的 URI 的左半部分或整个 uri 做 hash ,再将 hash 结果对总权重进行取模后
根据最终结果将请求转发到后端指定服务器
适用于后端是缓存服务器场景
默认是静态算法,也可以通过 hash-type 指定 map-based 和 consistent ,来定义使用取模法还是一致性hash
注意:此算法基于应用层,所以只支持 mode http ,不支持 mode tcp
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
左半部分: /<path>;<params>
整个 uri : /<path>;<params>?<query>#<frag>
4.3.3 url_param
url_param 对用户请求的 url 中的 params 部分中的一个参数 key 对应的 value 值作 hash 计算,并由服务器总权重相除以后派发至某挑出的服务器, 后端搜索同一个数据会被调度到同一个服务器,多用与电商
通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个real server
如果无没 key ,将按 roundrobin 算法
4.3.4 hdr
针对用户每个 http 头部 (header) 请求中的指定信息做 hash ,
此处由 name 指定的 http 首部将会被取出并做 hash 计算,
然后由服务器总权重取模以后派发至某挑出的服务器,如果无有效值,则会使用默认的轮询调度。
4.4 算法总结
# 静态
static-rr--------->tcp/http
first------------->tcp/http
# 动态
roundrobin-------->tcp/http
leastconn--------->tcp/http
# 以下静态和动态取决于 hash_type 是否 consistent
source------------>tcp/http
Uri--------------->http
url_param--------->http
hdr--------------->http
各算法使用场景
first #使用较少
static-rr #做了 session 共享的 web 集群
roundrobin #做了 session 共享的 web 集群
leastconn #数据库
source #基于客户端公网IP的会话保持
Uri--->http #缓存服务器, CDN 服务商,蓝汛、百度、阿里云、腾讯
url_param--->http # 可以实现 session 保持
hdr #基于客户端请求报文头部做下一步处理
5 高级功能及配置
5.1 基于cookie的会话保持
cookie value :为当前 server 指定 cookie 值,实现基于 cookie 的会话黏性,相对于基于 source 地址 hash调度算法对客户端的粒度更精准,但同时也加大了haproxy 负载,目前此模式使用较少, 已经被 session共享服务器代替
注意:不支持 tcp mode ,使用 http mode
5.1.1 配置选项
cookie name [ rewrite | insert | prefix ][ indirect ] [ nocache ][ postonly ] [
preserve ][ httponly ] [ secure ][ domain ]* [ maxidle <idle> ][ maxlife ]
name : #cookie 的 key 名称,用于实现持久连接
insert : # 插入新的 cookie, 默认不插入 cookie
indirect : # 如果客户端已经有 cookie, 则不会再发送 cookie 信息
nocache: # 当 client 和 hapoxy 之间有缓存服务器(如: CDN )时,不允许中间缓存器缓存 cookie: #因为这会导致很多经过同一个 CDN 的请求都发送到同一台后端服务器
例子:
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
.......
listen webcluster
bind *:80
mode http
balance roundrobin
cookie WEBCOOKIE insert nocache indirect
server web1 192.168.0.10:80 cookie web1 check inter 2 fall 3 rise 5 weight 2
server web2 192.168.0.20:80 cookie web2 check inter 2 fall 3 rise 5 weight 1
.......
[root@haproxy ~]# systemctl restart haproxy.service
# client测试:
[root@client ~]# curl -b WEBCOOKIE=web1 192.168.0.100
webserver1 - 192.168.0.10
[root@client ~]# curl -b WEBCOOKIE=web2 192.168.0.100
webserver2 - 192.168.0.20
5.2 HAProxy状态页
5.2.1 状态页配置项
stats enable # 基于默认的参数启用 stats page
stats hide-version # 将状态页中 haproxy 版本隐藏
stats refresh <delay> # 设定自动刷新时间间隔,默认不自动刷新
stats uri <prefix> # 自定义 stats page uri ,默认值: /haproxy?stats
stats auth <user>:<passwd> # 认证时的账号和密码,可定义多个用户 , 每行指定一个用户
# 默认: no authentication
stats admin { if | unless } <cond> # 启用 stats page 中的管理功能
5.2.2 启用状态页
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
.....
listen stats
mode http
bind *:9999
stats enable
stats refresh 1
stats uri /status
stats auth redhat:123
.......
[root@haproxy ~]# systemctl restart haproxy.service
在浏览器测试:
5.3 IP透传
IP 透传(IP Transparency)指的是在代理服务器处理请求和响应的过程中,能够将客户端的真实 IP 地址传递到后端服务器,使得后端服务器能够获取到客户端的原始 IP 而不是代理服务器的 IP 地址。
web服务器中需要记录客户端的真实 IP 地址,用于做访问统计、安全防护、行为分析、区域排行等场景。
5.3.1 七层IP透传
webserver1改为使用apache,webserver2用nginx
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
......
listen webcluster
bind *:80
mode http
balance roundrobin
server web1 192.168.0.10:80 check inter 2 fall 3 rise 5 weight 1
server web2 192.168.0.20:80 check inter 2 fall 3 rise 5 weight 1
[root@haproxy ~]# systemctl restart haproxy.service
#webserver关闭nginx,安装httpd
[root@webserver1 ~]# systemctl stop nginx.service
[root@webserver1 ~]# systemctl disable nginx.service
[root@webserver1 ~]# yum install httpd -y
[root@webserver1 ~]# echo web1 - 192.168.0.10 > /var/www/html/index.html~
[root@webserver1 ~]# systemctl restart httpd
[root@webserver1 ~]# systemctl enable --now httpd
[root@webserver1 ~]# vim /etc/httpd/conf/httpd.conf
[root@webserver1 ~]# systemctl restart httpd
[root@client ~]# curl 172.25.254.100
web1 - 192.168.0.10
[root@client ~]# curl 172.25.254.100
webserver2 - 192.168.0.20
[root@client ~]# curl 172.25.254.100
web1 - 192.168.0.10
# 加上参数之后就可以在日志中查看客户端访问的真实IP
[root@webserver1 ~]# tail -n 5 /etc/httpd/logs/access_log
172.25.254.10 192.168.0.100 - - [15/Aug/2024:02:02:38 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/7.76.1"
172.25.254.10 192.168.0.100 - - [15/Aug/2024:02:03:31 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/7.76.1"
172.25.254.10 192.168.0.100 - - [15/Aug/2024:02:03:32 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/7.76.1"
172.25.254.10 192.168.0.100 - - [15/Aug/2024:02:03:33 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/7.76.1"
172.25.254.10 192.168.0.100 - - [15/Aug/2024:02:04:52 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/7.76.1"
5.3.2 四层IP透传
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
......
listen webcluster
bind *:80
mode tcp
balance roundrobin
server web1 192.168.0.10:80 check inter 2 fall 3 rise 5 weight 1
server web2 192.168.0.20:80 check inter 2 fall 3 rise 5 weight 1
......
[root@haproxy ~]# systemctl restart haproxy.service
[root@client ~]# curl 172.25.254.100
web1 - 192.168.0.10
[root@client ~]# curl 172.25.254.100
webserver2 - 192.168.0.20
# 此时看日志是看不到访问者的真实IP
[root@webserver1 ~]# tail -n 3 /etc/httpd/logs/access_log
- 192.168.0.100 - - [15/Aug/2024:02:09:40 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/7.76.1"
- 192.168.0.100 - - [15/Aug/2024:02:09:41 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/7.76.1"
- 192.168.0.100 - - [15/Aug/2024:02:09:42 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/7.76.1"
[root@webserver2 ~]# vim /etc/nginx/nginx.conf
# 查看日志内容
[root@webserver2 ~]# tail -n 5 /var/log/nginx/access.log
192.168.0.100 - - [15/Aug/2024:02:17:08 +0800] "PROXY TCP4 192.168.0.100 192.168.0.20 47088 80" 400 0 "-" "-""-" "-"
192.168.0.100 - - [15/Aug/2024:02:17:08 +0800] "PROXY TCP4 192.168.0.100 192.168.0.20 47094 80" 400 0 "-" "-""-" "-"
192.168.0.100 - - [15/Aug/2024:02:17:08 +0800] "PROXY TCP4 192.168.0.100 192.168.0.20 47104 80" 400 0 "-" "-""-" "-"
192.168.0.100 - - [15/Aug/2024:02:17:08 +0800] "PROXY TCP4 192.168.0.100 192.168.0.20 47106 80" 400 0 "-" "-""-" "-"
192.168.0.100 - - [15/Aug/2024:02:17:08 +0800] "PROXY TCP4 192.168.0.100 192.168.0.20 47122 80" 400 0 "-" "-""-" "-"
5.4 ACL
访问控制列表 ACL , Access Control Lists )
是一种基于包过滤的访问控制技术
它可以根据设定的条件对经过服务器传输的数据包进行过滤 ( 条件匹配 ) 即对接收到的报文进行匹配和过滤,基于请求报文头部中的源地址、源端口、目标地址、目标端口、请求方法、URL 、文件后缀等信息内容进行匹配并执行进一步操作,比如允许其通过或丢弃
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl test hdr_dom(host) -i www.haha.org
use_backend webcluster-host if test
default_backend default-host
backend webcluster-host
mode http
server web1 192.168.0.10:80 check inter 2 fall 2 rise 5
backend default-host
mode http
server web2 192.168.0.20:80 check inter 2 fall 2 rise 5
[root@haproxy ~]# systemctl restart haproxy.service
# 满足条件的时候访问webcluster-host,不满足条件默认访问default-host。在做这个之前记得把之前在webserver2上做的IP透传的代码给注释掉,不然访问的时候会报502的错误。在Windows上面也要做本地解析。
[root@client ~]# curl www.haha.org
webserver1 - 192.168.0.10
[root@client ~]# curl 192.168.0.100
webserver2 - 192.168.0.20
ACL做动静分离等访问控制
# 基于域名的访问控制
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl domain hdr_dom(host) -i www.haha.org
use_backend webcluster-host if domain
default_backend default-host
backend webcluster-host
mode http
server web1 192.168.0.10:80 check inter 2 fall 2 rise 5
backend default-host
mode http
server web2 192.168.0.20:80 check inter 2 fall 2 rise 5
[root@haproxy ~]# systemctl restart haproxy.service
# 只有访问www.abc.org域名的时候才会去访问webserver1,否则访问webserver2
[root@client ~]# curl www.haha.org
webserver1 - 192.168.0.10
[root@client ~]# curl www.haha
webserver1 - 192.168.0.20
# 基于IP的访问控制
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl ctrl_ip src 192.168.0.1 192.168.0.20 192.168.0.0/24
use_backend webcluster-host if ctrl_ip
default_backend default-host
backend webcluster-host
mode http
server web1 192.168.0.10:80 check inter 2 fall 2 rise 5
backend default-host
mode http
server web2 192.168.0.20:80 check inter 2 fall 2 rise 5
[root@haproxy ~]# systemctl restart haproxy.service
# 符合条件的访问webserver1,不符合的访问webserver2
[root@client ~]# curl 192.168.0.100 #本机ip 172.25.254.10
webserver1 - 192.168.0.10
[root@webserver2 ~]# curl 192.168.0.100 #本机ip 192.168.0.20
webserver1 - 192.168.0.10