一、负载均衡
1.1 概念
负载均衡: Load Balance ,简称 LB ,是一种服务或基于硬件设备等实现的高可用反向代理技术,负载均衡将特定的业务(web 服务、网络流量等 ) 分担给指定的一个或多个后端特定的服务器或设备,从而提高了 公司业务的并发处理能力、保证了业务的高可用性、方便了业务后期的水平动态扩展。
1.2 为什么用负载均衡
Web服务器的动态水平扩展-->对用户无感知
增加业务并发访问及处理能力-->解决单服务器瓶颈问题
节约公网IP地址-->降低IT支出成本
隐藏内部服务器IP-->提高内部服务器安全性
配置简单-->固定格式的配置文件
功能丰富-->支持四层和七层,支持动态下线主机
性能较强-->并发数万甚至数十万
1.3 四层负载均衡
1.通过ip+port决定负载均衡的去向。
2.对流量请求进行NAT处理,转发至后台服务器。
3.记录tcp、udp流量分别是由哪台服务器处理,后续该请求连接的流量都通过该服务器处理。
4.支持四层的软件
lvs:重量级四层负载均衡器。
Nginx:轻量级四层负载均衡器,可缓存。(nginx四层是通过upstream模块)
Haproxy:模拟四层转发。
![](https://i-blog.csdnimg.cn/direct/dab4aa70c27b4555aa3045bd1181248b.png)
1.4 七层负载均衡
1.通过虚拟 ur| 或主机 ip 进行流量识别,根据应用层信息进行解析,决定是否需要进行负载均衡。
2. 代理后台服务器与客户端建立连接,如 nginx 可代理前后端,与前端客户端 tcp 连接,与后端服务器建立tcp连接 。
3. 支持 7 层代理的软件:
Nginx:基于http协议(nginx七层是通过proxy_pass)
Haproxy:七层代理,会话保持、标记、路径转移等。
1.5 四层和七层的区别
所谓的四到七层负载均衡,就是在对后台的服务器进行负载均衡时, 依据四层的信息或七层的
信息来决定怎么样转发流量。
四层的负载均衡,就是通过发布三层的 IP 地址( VIP ),然后加四层的端口号,来决定哪些流量需要做负载均衡,对需要处理的流量进行NAT 处理,转发至后台服务器,并记录下这个 TCP 或者 UDP 的流量是由哪台服务器处理的,后续这个连接的所有流量都同样转发到同一台服务器处理。
七层的负载均衡,就是在四层的基础上(没有四层是绝对不可能有七层的),再考虑应用层的特征,比如同一个Web 服务器的负载均衡,除了根据 VIP 加 80 端口辨别是否需要处理的流量,还可根据七层的URL、浏览器类别、语言来决定是否要进行负载均衡。
1. 分层位置 : 四层负载均衡在传输层及以下,七层负载均衡在应用层及以下
2. 性能 : 四层负载均衡架构无需解析报文消息内容,在网络吞吐量与处理能力上较高 : 七层可支持解
析应用层报文消息内容,识别URL 、 Cookie 、 HTTP header 等信息。、
3. 原理 : 四层负载均衡是基于 ip+port; 七层是基于虚拟的 URL 或主机 IP 等。
4. 功能类比 : 四层负载均衡类似于路由器 ; 七层类似于代理服务器。
5.安全性 : 四层负载均衡无法识别 DDoS 攻击 ; 七层可防御 SYN Cookie/Flood 攻击
二、haproxy的基本配置信息
官方文档:http://cbonte.github.io/haproxy-dconv/
HAProxy 的配置文件haproxy.cfg由两大部分组成,分别是:
global:全局配置段
进程及安全配置相关的参数
性能调整相关参数
Debug参数
proxies:代理配置段
defaults:为frontend, backend, listen提供默认配置
frontend:前端,相当于nginx中的server {}
backend:后端,相当于nginx中的upstream {}
listen:同时拥有前端和后端配置,配置简单,生产推荐使用
2.1 通过实验了解haproxy
实验环境:
webserver1:
[root@webserver1 ~]# vmset.sh eth0 172.25.254.10 webserver1.org
[root@webserver1 ~]# yum install nginx -y
[root@webserver1 ~]# echo webserver1 - 172.25.254.10 > /usr/share/nginx/html/index.html
[root@webserver1 ~]# systemctl restart nginx.service
webserver2:
[root@webserver2 ~]# vmset.sh eth0 172.25.254.20 webserver2.oeg
[root@webserver2 ~]# yum install nginx -y
[root@webserver2 ~]# echo webserver2 - 172.25.254.20 > /usr/share/nginx/html/index.html
[root@webserver2 ~]# systemctl restart nginx.service
haproxy配置
[root@haproxy ~]# vmset.sh eth0 172.168.0.100 haproxy.zyq.org
[root@haproxy ~]# systemctl stop firewalld.service
[root@haproxy ~]# dnf install haproxy -y 安装haproxy
[root@haproxy ~]# rpm -qc haproxy 查看文件
/etc/haproxy/haproxy.cfg
/etc/logrotate.d/haproxy
/etc/sysconfig/haproxy
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg 修改配置文件
frontend webcluster
bind *:80
mode http
use_backend webcluster-host
backend webcluster-host
balance roundrobin
server web1 172.25.254.10:80
server web2 172.25.254.20:80
[root@haproxy ~]# systemctl restart haproxy.service 重启haproxy服务
2.2 多进程和线程
2.2.1 查看多线程信息
[root@haproxy ~]# pstree -p | grep haproxy
|-haproxy(33040)---haproxy(33043)-+-{haproxy}(33044)
| |-{haproxy}(33045)
| `-{haproxy}(33046)
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
2.2.2 启动多线程
[root@haproxy conf.d]# vim /etc/haproxy/haproxy.cfg
ssl-default-bind-ciphers PROFILESYSTEM
ssl-default-server-ciphers PROFILE-SYSTEM
nbproc 2
cpu-map 1 0
cpu-map 2 1
#nbthread 2
systemctl restart haproxy.service 重启
2.2.3 查看多线程信息
[root@haproxy ~]# pstree -p | grep haproxy
|-haproxy(33058)-+-haproxy(33060)
| `-haproxy(33061)
2.2.4 启动多线程
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
[root@haproxy ~]# systemctl restart haproxy.service 重启
[root@haproxy ~]# pstree -p | grep haproxy
|-haproxy(33073)---haproxy(33075)---{haproxy}(33076)
[root@haproxy ~]# pstree -p | grep haproxy
|-haproxy(33084)---haproxy(33086)-+-{haproxy}(33087)
| |-{haproxy}(33088)
| `-{haproxy}(33089)
[root@haproxy ~]# cat /proc/33084/status | grep -i thread
Threads: 1
Speculation_Store_Bypass: thread vulnerable
2.3 日志
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
2.4 proxies
2.4.1 proxies参数说明
2.4.2 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}i
# 后在 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 指定后端服务器默认设置
2.4.3 Proxies配置-frontend
bind :指定 HAProxy 的监听地址,可以是 IPV4 或 IPV6 ,可以同时监听多个 IP 或端口,可同时用于 listen 字段中
# 格式:
bind [<address>]:<port_range> [, ...] [param*]
# 注意:如果需要绑定在非本机的 IP ,需要开启内核参数: net.ipv4.ip_nonlocal_bind=1
backlog <backlog> # 针对所有 server 配置 , 当前端服务器的连接数达到上限后的后援队列长度,注意:不支持
frontend 配置示例
haproxy ~]# vim /etc/haproxy/haproxy.cfg
... 上面内容省略 ...
frontend lee-webserver-80
bind 172.25.254.100:80
mode http
use_backend lee-webserver-80-RS # 调用 backend 的名称
2.4.4 Proxies配置-backend
mode http|tcp #指定负载协议类型,和对应的frontend必须一致
option #配置选项
server #定义后端real server,必须指定IP和端口
注意: option 后面加 httpchk , smtpchk,mysql-check,pgsql-check , ssl-hello-chk 方法,可用于实现更 多应用层检测功能。
server 配置
# 针对一个 server 配置
check # 对指定 real 进行健康状态检查,如果不加此设置,默认不开启检查 , 只有 check 后面
没有其它配置也可以启用检查功能
# 默认对相应的后端服务器 IP 和端口 , 利用 TCP 连接进行周期性健康性检查 , 注意必须指定
端口才能实现健康性检查
addr <IP> # 可指定的健康状态监测 IP ,可以是专门的数据网段,减少业务网络的流量
port <num> # 指定的健康状态监测端口
inter <num> # 健康状态检查间隔时间,默认 2000 ms
fall <num> # 后端服务器从线上转为线下的检查的连续失效次数,默认为 3 代码示例:
rise <num> # 后端服务器从下线恢复上线的检查的连续有效次数,默认为 2
weight <weight> # 默认为 1 ,最大值为 256 , 0( 状态为蓝色 ) 表示不参与负载均衡,但仍接受持
久连接
backup # 将后端服务器标记为备份状态 , 只在所有非备份主机 down 机时提供服务,类似 Sorry
Server
disabled # 将后端服务器标记为不可用状态,即维护状态,除了持久模式
# 将不再接受连接 , 状态为深黄色 , 优雅下线 , 不再接受新用户的请求
redirect prefix http://www.baidu.com/ # 将请求临时 (302) 重定向至其它 URL ,只适用于 http 模
式
maxconn <maxconn> # 当前后端 server 的最大并发连接数
2.4.5 Proxies配置-listen 简化配置
使用 listen 替换 frontend 和 backend 的配置方式,可以简化设置,通常只用于 TCP 协议的应用
listen配置示例:
haproxy ~] # vim /etc/haproxy/haproxy.cfg
... 上面内容省略 ...
listen webserver_80
bind 172 .25.254.100:80
mode http
option forwardfor
server webserver1 192 .168.0.101:80 check inter 3s fall 3 rise 5
server webserver2 192 .168.0.102:80 check inter 3s fall 3 rise 5
... 上面内容省略.........
三、socat 工具
3.1 socat 工具简介
范例:利用工具 socat 对服务器动态权重调整
# 修改配置文件
[root@haproxy ~] # vim /etc/haproxy/haproxy.cfg
stats socket /var/lib/haproxy/stats mode 600 level admin
# 查看帮助
haproxy ~] # socat -h
haproxy ~] # echo "help" | socat stdio /var/lib/haproxy/stats
The following commands are valid at this level:
help : this message
prompt : toggle interactive mode with prompt
quit : disconnect
。。。省略 。。。
enable server : enable a disabled server (use 'set server' instead) # 启用服务器
set maxconn server : change a server 's maxconn setting
set server : change a server 's state, weight or address # 设置服务器
get weight : report a server 's current weight # 查看权重
set weight : change a server 's weight (deprecated) # 设置权重
# 查看 haproxy 状态
[root@haproxy ~]# echo "show info" | socat stdio /var/lib/haproxy/stats
# 查看集群状态
[root@haproxy ~]# echo "show servers state" | socat stdio /var/lib/haproxy/stats
# 查看集群权重
[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@haproxy ~]# echo "enable server webcluster/web1 " | socat stdio /var/lib/haproxy/stats
3.2 针对多进程处理方法
如果开启多进程那么我们在对进程的sock文件进行操作时其对进程的操作时随机的。
如果需要指定操作进程那么需要用多soct文件方式来完成,这样每个进程就会有单独的sock文件来进行单独管理
示例:
haproxy ~]# vim /etc/haproxy/haproxy.cfg
... 上面内容省略 ...
stats socket /var/lib/haproxy/stats1 mode 600 level admin process 1
stats socket /var/lib/haproxy/stats2 mode 600 level admin process 2
nbproc 2
cpu-map 1 0
cpu-map 2 1
... 上面内容省略
这样每个进程就会有单独的sock 文件来进行单独管理
[root@haproxy ~]# ll /var/lib/haproxy/
总用量 0
srw------- 1 root root 0 8 月 8 13:43 stats
srw------- 1 root root 0 8 月 8 13:46 stats1
srw------- 1 root root 0 8 月 8 13:46 stats2
3.3 实验部分
3.3.1 单进程
# 单进程
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# turn on stats unix socket
stats socket /var/lib/haproxy/stats mode 600 level admin
# 重启haporxy
[root@haproxy ~]# systemctl restart haproxy.service
# 下载socat工具
[root@haproxy ~]# dnf install socat-1.7.4.1-5.el9.x86_64 -y
[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 172.25.254.10 2 0 1 2 218 6 0 7 7 0 0 0 - 80 - 0 0 - - 0
2 webcluster 2 web2 172.25.254.20 2 0 1 1 103 6 0 7 7 0 0 0 - 80 - 0 0 - - 0
4 static 1 static 127.0.0.1 0 0 1 1 217 8 2 0 6 0 0 0 - 4331 - 0 0 - - 0
5 app 1 app1 127.0.0.1 0 0 1 1 217 8 2 0 6 0 0 0 - 5001 - 0 0 - - 0
5 app 2 app2 127.0.0.1 0 0 1 1 217 8 2 0 6 0 0 0 - 5002 - 0 0 - - 0
5 app 3 app3 127.0.0.1 0 0 1 1 217 8 2 0 6 0 0 0 - 5003 - 0 0 - - 0
5 app 4 app4 127.0.0.1 0 0 1 1 216 8 2 0 6 0 0 0 - 5004 - 0 0 - - 0
[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: 2634
Uptime: 0d 0h05m04s
Uptime_sec: 304
Memmax_MB: 0
PoolAlloc_MB: 0
测试
[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 ~]# curl 172.25.254.100
webserver - 172.25.254.10
[root@haproxy ~]# curl 172.25.254.100
webserver2 - 172.25.254.20
3.3.2 下线服务器
[root@haproxy ~]# echo "disable server webcluster/web1" | socat stdio /var/lib/haproxy/stats
[root@haproxy ~]# for i in {1..5}; do curl 172.25.254.100; done
webserver2 - 172.25.254.20
webserver2 - 172.25.254.20
webserver2 - 172.25.254.20
webserver2 - 172.25.254.20
webserver2 - 172.25.254.20
3.3.3 上线服务器
[root@haproxy ~]# echo "enable server webcluster/web1" | socat stdio /var/lib/haproxy/stats
[root@haproxy ~]# for i in {1..6}; do curl 172.25.254.100; done
webserver2 - 172.25.254.20
webserver1 - 172.25.254.10
webserver1 - 172.25.254.10
webserver2 - 172.25.254.20
webserver1 - 172.25.254.10
webserver1 - 172.25.254.10
3.3.4 多线程
[root@haproxy ~]#l /var/lib/haproxy/
total 0
srw-------1 rootroot 0 Aug 10 11:10 stats
[root@haproxy~]#vim /etc/haproxy/haproxy.cfg
[root@haproxy~]#systemctl restart rsyslog.service
[root@haproxy ~]#ll /var/lib/haproxy/
total 0
srw-------1 root root 0 Aug 10 11:10 stats
[root@haproxy~]#systemctl restart haproxy.service
[root@haproxy~]#ll /var/lib/haproxy/
total 0
srw---------------1 root root 0 Aug 10 11:10 stats
srw---------------1 root root 0 Aug 10 11:10 stats1
srw---------------1 root root 0 Aug 10 11:10 stats2
[root@haproxy ~#echo"show info" | socat stdio /var/lib/haproxy/stats
2024/08/09 11:33:30 socat[3084]E connect(5,AF=1 "/var/lib/haproxy/stats",24): connecion refused
四、haproxy的算法
HAProxy通过固定参数 balance 指明对后端服务器的调度算法
balance参数可以配置在listen或backend选项中。
HAProxy的调度算法分为静态和动态调度算法
有些算法可以根据参数在静态和动态算法中相互转换。
4.1 静态算法
4.1.1 static-rr:基于权重的轮询调度
1.不支持运行时利用socat进行权重的动态调整(只支持0和1,不支持其它值)
2.不支持端服务器慢启动
3.其后端主机数量没有限制,相当于LVS中的 wrr
4.1.2 first
1.根据服务器在列表中的位置,自上而下进行调度
2.其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务
3.其会忽略服务器的权重设置
4.不支持用socat进行动态修改权重,可以设置0和1,可以设置其它值但无效
4.2 动态算法
1.基于后端服务器状态进行调度适当调整,
2.新请求将优先调度至当前负载较低的服务器
3.权重可以在haproxy运行时动态调整无需重启
4.2.1 roundrobin
1. 基于权重的轮询动态调度算法,
2. 支持权重的运行时调整,不同于lvs中的rr轮训模式,
3. HAProxy中的roundrobin支持慢启动(新加的服务器会逐渐增加转发数),
4. 其每个后端backend中最多支持4095个real server,
5. 支持对real server权重动态调整,
6. roundrobin为默认调度算法,此算法使用广泛
示例:
示例:
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...
listen webserver_80
bind 172.25.254.100:80
mode http
balance roundrobin
server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5
server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5
...上面内容省略...
动态调整权重:
[root@haproxy ~]# echo "set weight webserver_80/webserver1 2" | socat stdio
/var/lib/haproxy/haproxy.sock
4.2.2 leastconn
示例:
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...
listen webserver_80
bind 172.25.254.100:80
mode http
balance roundrobin
server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5
server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5
...上面内容省略...
4.3 其他算法
4.3.1 source
源地址hash,基于用户源地址hash并将请求转发到后端服务器,后续同一个源地址请求将被转发至同一 个后端web服务器。此方式当后端服务器数据量发生变化时,会导致很多用户的请求转发至新的后端服务器,默认为静态方式,但是可以通过hash-type支持的选项更改这个算法一般是在不插入Cookie的TCP模式下使用,也可给拒绝会话cookie的客户提供最好的会话粘性,适用于session会话保持但不支持cookie和缓存的场景源地址有两种转发客户端请求到后端服务器的服务器选取计算方式,分别是取模法和一致性hash。
4.3.1.1 map-base 取模法
map-based:取模法,对source地址进行hash计算,再基于服务器总权重的取模,最终结果决定将此请求转发至对应的后端服务器。
此方法是静态的,即不支持在线调整权重,不支持慢启动,可实现对后端服务器均衡调度。缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因总权重发生变化而导致调度结果整体改变。
比如当源 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 被调度到的主机都发生变化,这样会导致会话丢失
取模法配置示例:
haproxy ~]# vim /etc/haproxy/haproxy.cfg
... 上面内容省略 ...
listen webserver_80
bind 172.25.254.100:80
mode http
balance source
server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5
server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5
... 上面内容省略 ...
# 不支持动态调整权重值
[root@haproxy ~]# echo "set weight webserver_80/webserver1 2" | socat stdio
/var/lib/haproxy/haproxy.sock
Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.
# 只能动态上线和下线
[root@haproxy ~]# echo "set weight webserver_80/webserver1 0" | socat stdio
/var/lib/haproxy/haproxy.sock
[root@haproxy ~]# echo "get weight webserver_80/webserver1" | socat stdio
/var/lib/haproxy/haproxy.sock
0 (initial 1)
4.3.1.2 一致性hash
1 、后端服务器哈希环点 keyA=hash( 后端服务器虚拟 ip)%(2^32)
2 、客户机哈希环点 key1=hash(client_ip)%(2^32) 得到的值在 [0---4294967295] 之间,
3 、将 keyA 和 key1 都放在 hash 环上,将用户请求调度到离 key1 最近的 keyA 对应的后端服务器
hash 环偏斜问题
增加虚拟服务器 IP 数量,比如:一个后端服务器根据权重为 1 生成 1000 个虚拟 IP ,再 hash 。而后端服务器权重为2 则生成 2000 的虚拟 IP ,再 bash, 最终在 hash 环上生成 3000 个节点,从而解决 hash 环偏斜问题。
Hash 对象到后端服务器的映射关系:
![](https://i-blog.csdnimg.cn/direct/cc0c7d9cdbb34be7a6d1a8a64cf79528.png)
4.3.2 uri
![](https://i-blog.csdnimg.cn/direct/ea5cb1e0417840609182f9c28ec91c55.png)
4.3.3 url_param
url_param对用户请求的url中的 params 部分中的一个参数key对应的value值作hash计算,并由服务器总权重相除以后派发至某挑出的服务器,后端搜索同一个数据会被调度到同一个服务器,多用与电商。通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个real server。如果无没key,将按roundrobin算法。
#假设:
url=http://www.timinglee.com/foo/bar/index.php?key=value
#则:
host="www.timinglee.com"url_param="key=value"
4.3.4 hdr
针对用户每个http头部(header)请求中的指定信息做hash,此处由 name 指定的http首部将会被取出并做hash计算,然后由服务器总权重取模以后派发至某挑出的服务器,如果无有效值,则会使用默认的轮询调度。
4.3.5 算法总结
#静态
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
4.3.6 各算法使用场景
first # 使用较少
static-rr # 做了 session 共享的 web 集群
roundrobin
leastconn # 数据库
source
# 基于客户端公网 IP 的会话保持
Uri--------------->http # 缓存服务器, CDN 服务商,蓝汛、百度、阿里云、腾讯
url_param--------->http # 可以实现 session 保持
hdr # 基于客户端请求报文头部做下一步处理
五、高级功能及配置
5.1 基于cookie的会话保持
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功能
cookie WEBCOOKIE insert nocache indirect
server web1 172.25.254.10:80 cookie lee1 check inter 2 fall 3 rise 5 weight 1
server web2 172.25.254.20:80 cookie lee2 check inter 2 fall 3 rise 5 weight 1
[root@haproxy ~]# systemctl restart haproxy.service
测试:
[root@haproxy ~]# curl -b WEBCOOKIE=lee1 172.25.254.100
webserver1 - 172.25.254.10
[root@haproxy ~]# curl -b WEBCOOKIE=lee2 172.25.254.100
webserver2 - 172.25.254.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 启用状态页
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...
listen stats:
mode http
bind 0.0.0.0:8888
stats enable
log global
stats uri /status #自定义stats page uri
stats auth lee:lee #认证,此行可以出现多次
...上面内容省略...
测试:
浏览器访问:172.25.254.100:8888/status
5.2.3 登录状态页
#pid为当前pid号,process为当前进程号,nbproc和nbthread为一共多少进程和每个进程多少个线程
pid = 27134 (process #1, nbproc = 1, nbthread = 1)
#启动了多长时间
uptime = 0d 0h00m04s
#系统资源限制:内存/最大打开文件数/
system limits: memmax = unlimited; ulimit-n = 200029
#最大socket连接数/单进程最大连接数/最大管道数maxpipes
maxsock = 200029; maxconn = 100000; maxpipes = 0
#当前连接数/当前管道数/当前连接速率
current conns = 2; current pipes = 0/0; conn rate = 2/sec; bit rate = 0.000 kbps
#运行的任务/当前空闲率
Running tasks: 1/14; idle = 100 %
active UP: #在线服务器
backup UP: #标记为backup的服务器
active UP, going down: #监测未通过正在进入down过程
backup UP, going down: #备份服务器正在进入down过程
active DOWN, going up: #down的服务器正在进入up过程
backup DOWN, going up: #备份服务器正在进入up过程
active or backup DOWN: #在线的服务器或者是backup的服务器已经转换成了down状态
not checked: #标记为不监测的服务器
#active或者backup服务器人为下线的
active or backup DOWN for maintenance (MAINT)
#active或者backup被人为软下线(人为将weight改成0)
active or backup SOFT STOPPED for maintenance
# 进入配置文件
root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen stats
mode http
bind *:9999
stats enable
stats refresh 3
stats uri /status
stats auth fb:fb
[root@haproxy ~]# systemctl restart haproxy.service
测试
5.3 IP透传
5.3.1 四层IP透传
#未开启透传的四层代理
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...
listen webserver_80
bind 172.25.254.100:80
mode tcp
balance roundrobin
server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5
...上面内容省略...
#正常的nginx配置
[root@rs1 ~]# vim /etc/nginx/nginx.conf
。。。内容省略。。。
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request"'
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
。。。内容省略。。。
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
。。。内容省略。。。
}
}
#在访问haproxy后查看nginx日志
[root@rs1 ~]# tail -n 3 /var/log/nginx/access.log
192.168.0.10 - - [10/Jul/2024:15:21:00 +0800] "GET / HTTP/1.1"200 18 "-"
"curl/7.29.0" "-"192.168.0.10 - - [10/Jul/2024:15:26:11 +0800] "GET /
HTTP/1.1"200 18 "-" "curl/7.29.0" "-"
在此日志中是无法看到真实访问源地址的
实验
[root@webserver1 ~]# vim /etc/nginx/nginx.conf
[root@webserver1 ~]# systemctl restart nginx.service
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
[root@haproxy ~]# systemctl restart haproxy.service
5.3.2 七层IP透传
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
[root@haproxy ~]# systemctl restart haproxy.service
测试:
5.4 ACL
# 示例
frontend test_acl
bind *:80
mode http
#acl bad_browers hdr_beg(User-Agent) -i curl
#http-request deny if bad_browers
#acl test hdr_dom(host) -i www.timinglee.org
#acl test hdr_end(host) -i .org
#acl test base_sub -m sub org
#acl test path_sub -m sub /a
#acl test path_end -m sub /a
#acl test path_reg -i ^/t
acl test url_sub -m sub lee
acl test path_dir -m sub a
use_backend test_web if test
default_backend default_webserver
backend default_webserver
mode http
server web1 172.25.254.20:80 check inter 3 fall 3 rise 5
backend test_web
mode http
server web2 172.25.254.30:80 check inter 3 fall 3 rise 5
5.4.1 ACL配置选项
#用acl来定义或声明一个acl
acl <aclname> <criterion> [flags] [operator] [<value>]
acl 名称 匹配规范 匹配模式 具体操作符 操作对象类型
5.4.1.1 ACL-Name 名称
acl test path_end -m sub /a
#ACL名称,可以使用大字母A-Z、小写字母a-z、数字0-9、冒号:、点.、中横线和下划线,并且严格区分大
小写,比如:my_acl和My_Acl就是两个完全不同的acl5.8.1.2 ACL-criterion
5.4.1.2 ACL-criterion 匹配规范
hdr string,提取在一个HTTP请求报文的首部
hdr([<name> [,<occ>]]):完全匹配字符串,header的指定信息,<occ> 表示在多值中使用的值的出
现次数
hdr_beg([<name> [,<occ>]]):前缀匹配,header中指定匹配内容的begin
hdr_end([<name> [,<occ>]]):后缀匹配,header中指定匹配内容end
hdr_dom([<name> [,<occ>]]):域匹配,header中的dom(host)
hdr_dir([<name> [,<occ>]]):路径匹配,header的uri路径
hdr_len([<name> [,<occ>]]):长度匹配,header的长度匹配
hdr_reg([<name> [,<occ>]]):正则表达式匹配,自定义表达式(regex)模糊匹配
hdr_sub([<name> [,<occ>]]):子串匹配,header中的uri模糊匹配 模糊匹配c 报文中a/b/c也会匹
配
#示例:
hdr(<string>) 用于测试请求头部首部指定内容
hdr_dom(host) 请求的host名称,如 www.timinglee.org
hdr_beg(host) 请求的host开头,如 www. img. video. download. ftp.
hdr_end(host) 请求的host结尾,如 .com .net .cn
#示例:
acl bad_agent hdr_sub(User-Agent) -i curl wget
http-request deny if bad_agent
#有些功能是类似的,比如以下几个都是匹配用户请求报文中host的开头是不是www
acl short_form hdr_beg(host) www.
acl alternate1 hdr_beg(host) -m beg www.
acl alternate2 hdr_dom(host) -m beg www.
acl alternate3 hdr(host) -m beg www.
base : string
#返回第一个主机头和请求的路径部分的连接,该请求从主机名开始,并在问号之前结束,对虚拟主机有用
<scheme>://<user>:<password>@#<host>:<port>/<path>;<params>#?<query>#<frag>
base : exact string match
base_beg : prefix match
base_dir : subdir match
base_dom : domain match
base_end : suffix match
base_len : length match
base_reg : regex match
base_sub : substring match
path : string
#提取请求的URL路径,该路径从第一个斜杠开始,并在问号之前结束(无主机部分)
<scheme>://<user>:<password>@<host>:<port>#/<path>;<params>#?<query>#<frag>
path : exact string match
path_beg : prefix match #请求的URL开头,如/static、/images、/img、/css
path_end : suffix match #请求的URL中资源的结尾,如 .gif .png .css .js .jpg .jpeg
path_dom : domain match
path_dir : subdir match
path_len : length match
5.4.1.3 ACL-flags 匹配模式
ACL匹配模式
path_reg : regex match
path_sub : substring match
#示例:
path_beg -i /haproxy-status/
path_end .jpg .jpeg .png .gif
path_reg ^/images.*\.jpeg$
path_sub image
path_dir jpegs
path_dom timinglee
url : string
#提取请求中的整个URL。
url :exact string match
url_beg : prefix match
url_dir : subdir match
url_dom : domain match
url_end : suffix match
url_len : length match
url_reg : regex match
url_sub : substring match
dst #目标IP
dst_port #目标PORT
src #源IP
src_port #源PORT
#示例:
acl invalid_src src 10.0.0.7 192.168.1.0/24
acl invalid_src src 172.16.0.0/24
acl invalid_port src_port 0:1023
status : integer #返回在响应报文中的状态码
#七层协议
acl valid_method method GET HEAD
http-request deny if ! valid_method
5.4.1.3 ACL-flags 匹配模式
-i 不区分大小写
-m 使用指定的正则表达式匹配方法
-n 不做DNS解析
-u 禁止acl重名,否则多个同名ACL匹配或关系
5.4.1.4 ACL-operator 具体操作符
整数比较:eq、ge、gt、le、lt
字符比较:
- exact match (-m str) :字符串必须完全匹配模式
- substring match (-m sub) :在提取的字符串中查找模式,如果其中任何一个被发现,ACL将匹配
- prefix match (-m beg) :在提取的字符串首部中查找模式,如果其中任何一个被发现,ACL将匹配
- suffix match (-m end) :将模式与提取字符串的尾部进行比较,如果其中任何一个匹配,则ACL进行
匹配
- subdir match (-m dir) :查看提取出来的用斜线分隔(“/")的字符串,如其中任一个匹配,则ACL
进行匹配
- domain match (-m dom) :查找提取的用点(“.")分隔字符串,如果其中任何一个匹配,则ACL进行
匹配
5.4.1.5 ACL-value 操作对象
The ACL engine can match these types against patterns of the following types :
- Boolean #布尔值
- integer or integer range #整数或整数范围,比如用于匹配端口范围
- IP address / network #IP地址或IP范围, 192.168.0.1 ,192.168.0.1/24
- string--> www.timinglee.org
exact #精确比较
substring #子串
suffix #后缀比较
prefix #前缀比较
subdir #路径, /wp-includes/js/jquery/jquery.js
domain #域名,www.timinglee.org
- regular expression #正则表达式
- hex block #16进制
5.4.2 多个ACL的组合调用方式
与:隐式(默认)使用
或:使用“or" 或 “||"表示
否定:使用 "!" 表示
#示例:
if valid_src valid_port #与关系,ACL中A和B都要满足为true,默认为与
if invalid_src || invalid_port #或,ACL中A或者B满足一个为true
if ! invalid_src #非,取反,不满足ACL才为true
5.4.3 ACL-域名匹配
haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend testacl
bind :80
mode http
########### ACL settings #######################
acl web_host hdr_dom(host) www.timinglee.org
########### host ###########################
use_backend timinglee_host if web_host
########### default server ###################
default_backend default_webserver
backend timinglee_host
mode http
server web1 192.168.0.101:80 check weight 1 inter 3s fall 3 rise 5
server web2 192.168.0.102:80 check weight 1 inter 3s fall 3 rise 5
backend default_webserver
mode http
server web1 172.25.254.10:80 check weight 1 inter 3s fall 3 rise 5
#在浏览器所在主机中做地址解析
[root@node10 html]# vim /etc/hosts
172.25.254.100 www.timinglee.org
#测试结果
[root@node10 html]# curl www.timinglee.org
RS1 192.168.0.101
[root@node10 html]# curl www.timinglee.org
RS2 server - 192.168.0.102
[root@node10 html]# curl 172.25.254.100
default web server node10
5.5 自定义HAProxy 错误界面
#haproxy默认使用的错误错误页面
[root@haproxy ~]# rpm -ql haproxy24z-2.4.27-1.el7.zenetys.x86_64 | grep -E http$
/usr/share/haproxy/400.http
/usr/share/haproxy/403.http
/usr/share/haproxy/408.http
/usr/share/haproxy/500.http
/usr/share/haproxy/502.http
/usr/share/haproxy/503.http
/usr/share/haproxy/504.http
5.5.1 基于自定义页面的错误文件
#自定义错误页
errorfile <code> <file>
<code> #HTTP status code.支持200, 400, 403, 405, 408, 425, 429, 500, 502,503,504
<file> #包含完整HTTP响应头的错误页文件的绝对路径。 建议后缀".http",以和一般的html文件相区分
#示例:
errorfile 503 /haproxy/errorpages/503page.http
实验
haproxy ~]# vim /etc/haproxy/haproxy.cfg
defaults
mode http
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 1000000
errorfile 503 /haproxy/errorpages/503page.http
[root@haproxy ~]# mkdir /haproxy/errorpages/ -p
[root@haproxy ~]# cp /usr/share/haproxy/503.http /haproxy/errorpages/503page.http
[root@haproxy ~]# vim /haproxy/errorpages/503page.http
HTTP/1.0 503 Service Unavailable^M
Cache-Control: no-cache^M
Connection: close^M
Content-Type: text/html;charset=UTF-8^M
^M
<html><body><h1>什么动物生气最安静</h1>
大猩猩!!
</body></html>
测试
5.5.2 基于http重定向错误页面
#错误页面重定向
errorloc <code> <url>
#相当于errorloc302 <code> <url>,利用302重定向至指URL
#示例:
errorloc 503 https://www.baidu.com
haproxy ~]# vim /etc/haproxy/haproxy.cfg
defaults
mode http
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 1000000
errorloc 503 https://www.baidu.com
测试
5.6 HAProxy 四层负载
MySQL
Redis
Memcache
RabbitMQ
5.6.1 实现四层负载
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
[root@haproxy ~]# systemctl restart haproxy.service
测试
5.7 HAProxy https 实现
#配置HAProxy支持https协议,支持ssl会话;
bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE
#指令 crt 后证书文件为PEM格式,需要同时包含证书和所有私钥
cat demo.key demo.crt > demo.pem
#把80端口的请求重向定443
bind *:80
redirect scheme https if !{ ssl_fc }
5.7.1 证书制作
haproxy ~]# mkdir /etc/haproxy/certs/
haproxy ~]# openssl req -newkey rsa:2048 \
-nodes -sha256 –keyout /etc/haproxy/certs/timinglee.org.key \
-x509 -days 365 -out /etc/haproxy/certs/timinglee.org.crt
5.7.2 https实验
证书制作
# 证书制作
[root@haproxy ~]# mkdir -p /etc/haproxy/certs
[root@haproxy ~]# openssl req -newkey rsa:2048 -nodes -sha256 -keyout /etc/haproxy/certs/timinglee.org.key -x509 -days 365 -out /etc/haproxy/certs/timinglee.org.crt
# 将证书添加进去
[root@haproxy ~]# ls /etc/haproxy/certs/ timinglee.org.crt timinglee.org.key
[root@haproxy ~]# cat /etc/haproxy/certs/timinglee.org.key /etc/haproxy/certs/timinglee.org.crt > /etc/haproxy/certs/timinglee.pem
[root@haproxy ~]# cat /etc/haproxy/certs/timinglee.pem
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
[root@haproxy ~]# systemctl restart haproxy.service
测试
综上所述,就是本期的所有内容,感谢大家的观看。