1. Haproxy 介绍
HAProxy是法国开发者 威利塔罗(Willy Tarreau) 使用C语言编写的自由及开放源代码软件,是一款具备高并发(万级以上)、高性能的TCP和HTTP应用程序代理.
HAProxy运行在当前的硬件上,可以支持数以万计的并发连接,并且它的运行模式使得它可以很简单安全地整合进用户当前的架构中,同时可以保护用户的web服务器不被暴露到网络上.
截止目前GitHub、Bitbucket、Reddit、Twitter等在内的知名网站,都使用了HAProxy.
2. Haproxy 配置
2.1 技术术语
名称 | 说明 |
---|---|
慢启动 | 刚启动的服务器,不会被分配到所有的服务请求,而是先分配一部分,服务器状态良好后,再分配一部分,直到逼近服务器可承受范围内极限 |
2.2 基本配置
文章末尾的 Haproxy实战 基于此配置环境
2.2.1 Haproxy
vim /etc/NetworkManager/system-connections/eth0.nmconnection
[connection]
id=eth0
type=ethernet
interface-name=eth0
[ipv4]
address1=172.25.254.100/24,172.25.254.2
method=manual
nmcli connection reload
nmcli connection up eth0
dnf install haproxy-2.4.22-3.el9_3.x86_64 -y
vim /etc/haproxy/haproxy.cfg
# 前后端分开配置
67 frontend Webcluster
68 bind *:80
69 mode http
70 use_backend Webculuster-host
71
72 backend Webculuster-host
73 balance roundrobin
74 server Web1 172.25.254.10:80
75 server Web2 172.25.254.20:80
# 同时配置前后端 两种方法 二选一即可
listen Webcluster
bind *:80
mode http
balance roundrobin
server Web1 172.25.254.10:80
server Web2 172.25.254.20:80
systemctl restart haproxy.service
Server1
vim /etc/NetworkManager/system-connections/eth0.nmconnection
[connection]
id=eth0
type=ethernet
interface-name=eth0
[ipv4]
address1=172.25.254.10/24,172.25.254.2
method=manual
nmcli connection reload
nmcli connection up eth0
dnf install nginx -y
echo Web-Server - 172.25.254.10 > /usr/share/nginx/html/index.html
systemctl enable --now nginx.service
2.2.2 Server2
vim /etc/NetworkManager/system-connections/eth0.nmconnection
[connection]
id=eth0
type=ethernet
interface-name=eth0
[ipv4]
address1=172.25.254.20/24,172.25.254.2
method=manual
nmcli connection reload
nmcli connection up eth0
dnf install nginx -y
echo Web-Server - 172.25.254.20 > /usr/share/nginx/html/index.html
systemctl enable --now nginx.service
2.2.3 测试(Windows终端)
# 正常访问
curl 172.25.254.100
Web-Server - 172.25.254.10
curl 172.25.254.100
Web-Server - 172.25.254.20
curl 172.25.254.100
Web-Server - 172.25.254.10
curl 172.25.254.100
Web-Server - 172.25.254.20
# 自动后端检测
[root@Server2 ~]# systemctl stop nginx.service
curl 172.25.254.100
Web-Server - 172.25.254.10
curl 172.25.254.100
Web-Server - 172.25.254.10
curl 172.25.254.100
Web-Server - 172.25.254.10
# 故障或下线服务器 将不再被分配客户端请求
2.3 配置文件
/etc/haproxy/haproxy.cfg 配置文件路径
由两大部分共同构成,分别为
-
global:全局配置段
- 进程及安全配置相关参数
- 性能调整相关参数
- Debug参数
-
proxies:代理配置段
- defaults:为frontend, backend,listen提供默认配置
- frontend:前端,相当于nginx中的server {}
- backend:后端,相当于nginx中的upstream {}
- listen:同时配置前后端,配置简单,推荐使用
2.3.1 global配置
参数 | 说明 |
---|---|
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协议, 最多可以定义两个 |
2.3.2 proxies 配置
参数 | 说明 |
---|---|
defaults | 默认配置项,针对以下的frontend、backend和listen生效 |
frontend | 前端ServerName,类似于LVS服务集群 |
backend | 后端服务器组,类似于LVS中的RS服务器 |
listen | 将frontend和backend合并在一起配置 |
- name字段只能使用大小写字母,数字,短杠 - ,下划线 _ ,点 . 和冒号 : ,并且严格区分大小写
defaults 配置分析
行数(46 defaults) | 参数 | 说明 |
---|---|---|
47 | mode http | HAProxy实例使用的连接协议 |
48 | log global | 指定日志地址和记录日志条目的 global表示使用 global 配置段中设定的log值 |
49 | option httplog | 日志记录选项,httplog表示记录与 HTTP 会话相关的各种属性值 包括 HTTP请求、会话状态、连接数、源地址以及连接时间等 |
50 | option dontlognull | dontlognull表示不记录空会话连接日志 |
51 | option http-server-close | 等待客户端完整HTTP请求的时间 |
52 | option forwardfor except 127.0.0.0/8 | 透传客户端真实IP至后端web服务器**(IP透传)** 在Apache配置文件中加入:<br>%{X-Forwarded-For}i 后在Webserver中看日志即可看到地址透传信息 |
53 | option redispatch | 当server id对应的服务器挂掉后,强制定向到其他健康的服务器,重新派发 |
54 | retries 3 | 连接后端服务器失败次数 |
55 | timeout http-request 10s | 等待客户端请求完全被接收和处理的最长时间 |
56 | timeout queue 1m | 设置删除连接和客户端收到503或服务不可用等提示信息前的等待时间 |
57 | timeout connect 10s | 设置等待服务器连接成功的时间 |
58 | timeout client 1m | 设置允许客户端处于非活动状态,即客户端既不发送数据也不接收数据的时间 |
59 | timeout server 1m | 设置服务器超时时间,即服务器处于既不接收也不发送数据的非活动时间 |
60 | timeout http-keep-alive 10s | session 会话保持超时时间,此时间段内会转发到相同的后端服务器 |
61 | timeout check 10s | 指定后端服务器健康检查的超时时间 |
62 | maxconn 3000 | 最大并发连接数 |
option http-keep-alive | 开启与客户端的会话保持 |
frontend 配置分析
67 # frontend Webcluster
68 # bind *:80
69 # mode http
70 # use_backend Webculuster-host 调用backend的名称
# bind:指定HAProxy的监听地址,可以是IPV4或IPV6,可以同时监听多个IP或端口,可同时用于listen字段中
# 格式:bind <address>:<port_range> , ...<address>:<port_range>, ...
# 如果需要绑定在非本机的IP,需要开启内核参数:net.ipv4.ip_nonlocal_bind=1
# backlog <backlog> #针对所有server配置,当前端服务器的连接数达到上限后的后援队列长度,注意:不支持backend
backend 配置分析
- 定义一组后端服务器
- backend 的名称必须唯一,并且必须在listen或frontend中事先定义才可以使用,否则服务无法启动
# frontend Your-Name
# bind 172.25.254.100:80
# mode http
# use_backend backend-name #调用backend的名称
mode http|tcp # 指定负载协议类型,必须和对应的frontend保持一致
option # 配置选项
server # 定义后端real server,必须指定IP和端口
Server 配置
# server web1 192.168.0.101:80 check inter 3s fall 3 rise 5
# server web2 192.168.0.102:80 check inter 3s fall 3 rise 5
参数 | 说明 |
---|---|
check | 对指定RS进行健康状态检查,如果不加此参数,默认不开启检查 默认对相应的 RS 的IP和端口,利用TCP连接进行周期性健康性检查,注意必须指定端口才能实现健康性检查 |
addr <IP> | 可指定的健康状态监测IP,可以是专门的数据网段 |
port <num> | 指定的健康状态监测端口 |
inter <num> | 健康状态检查间隔时间,默认2000 ms |
fall <num> | 后端服务器从线上转为线下的检查的连续失效次数,默认为3 |
rise <num> | 后端服务器从下线恢复上线的检查的连续有效次数,默认为2 |
weight <weight> | 权重值默认为1,最大值为256,0 表示不参与负载均衡,但仍接受持久连接 |
backup | 将后端服务器标记为备份状态,只在所有非备份主机Down机时提供服务 |
disabled | 将后端服务器标记为不可用状态,即维护状态,除了持久模式 将不再接受连接,状态为深黄色,不再接受新用户的请求 |
redirect prefix | 将请求临时重定向至其它URL,只适用于http模式 |
maxconn | 当前 RS 的最大并发连接数 |
listen 配置分析
替代 frontend 和 backend 从而简化设置,通常只用于TCP协议的应用
# 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
2.4 Socat 工具
2.4.1 Socat 介绍
对 服务器权重 或 其它状态 进行动态调整 可以利用 socat 工具进行调整
Socat 是 Linux 下的一个多功能的网络工具,名字来由是Socket CAT,相当于NetCAT的增强版
Socat 的主要特点就是在两个数据流之间建立双向通道,且支持众多协议和链接方式
2.4.2 Socat 使用
# 首先修改 Haproxy 的配置文件,才能正常使用
vim /etc/haproxy/haproxy.cfg
35 # turn on stats unix socket
36 stats socket /var/lib/haproxy/stats # 默认情况下只能进行查看,不能进行更改
--> stats socket /var/lib/haproxy/stats mode 600 level admin
# 安装Socat
dnf install socat -y
# 查看帮助
echo "help" | socat stdio /var/lib/haproxy/stats
......
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 状态
echo "show info" | socat stdio /var/lib/haproxy/stats
# 查看集群状态
echo "show servers state" | socat stdio /var/lib/haproxy/stats
# 查看集群权重
echo get weight webcluster/web1 | socat stdio
echo get weight webcluster/web2 | socat stdio
# 设置权重
echo "set weight webcluster/web1" | socat stdio
# 下线后端服务器
echo "disable server webcluster/web1" | socat stdio
# 上线后端服务器
echo "enable server webcluster/web1" | socat stdio
2.4.3 Socat的多线程管理
如果Haproxy 开启多进程,那么对进程的 Sock 文件进行操作时,会导致操作是随机,不够准确
指定操作进程,需要用多 Sock 文件方式解决
35 # turn on stats unix socket
36 stats socket /var/lib/haproxy/stats1 mode 600 level admin process 1
37 stats socket /var/lib/haproxy/stats2 mode 600 level admin process 2
38 nbproc 2
39 cpu-map 1 0
40 cpu-map 2 1
则每个进程都有对应的 Sock 文件进行操作
[root@Haproxy ~]# ll /var/lib/haproxy/
srw------- 1 root root 0 8月 11 22:43 stats
srw------- 1 root root 0 8月 11 22:46 stats1
srw------- 1 root root 0 8月 11 22:46 stats2
3. Haproxy 算法
- HAProxy 通过固定参数 balance 指明对后端服务器的调度算法
- 固定参数 balance 可以配置在 listen 或 backend 选项中
3.1 静态算法
静态算法:按照事先定义好的规则轮询公平调度,不关心后端服务器的当前负载、连接数和响应速度等,且无法实时修改权重(只能设置成 0 或 1)只能靠重启HAProxy生效
3.1.1 Rr:基于权重的轮询调度
- 不支持权重动态调整
- 不支持服务器慢启动
- 后端服务器没有数量限制,相当于LVS中的Wrr算法
3.1.2 First
-
不支持权重动态调整
-
根据后端服务器在列表中的位置,自上而下进行调度
-
当前面的服务器的连接数达到上限时,才会把新的请求分配给下一个服务器
-
忽略服务器权重
3.2 动态算法
- 基于后端服务器状态可以进行适当调整
- 最新请求将优先分配给当前负载较低的服务器
- 权重可以在Haproxy运行时,进行动态调整,无需重启
3.2.1 Roundrobin
- 基于权重的轮询动态调度算法
- 支持权重动态调整
- 支持服务器慢启动
- 每个后端 Backend 存在上限,最多支持 4095 个 RS
- Haproxy的默认调度算法
3.2.2 Leastconn
-
根据当前连接数最少的后端服务器分配请求,而不是权重
-
当服务器连接数相同,以权重为主
-
支持权重动态调整
-
支持服务器慢启动
-
适合长连接的场景(MySQL等)
3.3 其他算法
此类算法可以根据参数在静态或动态算法中进行转换
3.3.1 Source
基于用户源地址Hash将请求转发到后端服务器,后续同一个源地址请求将被转发至同一个后端服务器,但当后端服务器数量发生变化时,会导致很多用户的请求转发至新的后端服务器。
默认是静态算法,可以通过Hash-Type选项更改运行模式
Source对后端服务器的选择有两种方法
- 取模法(Map-Base)
- 一致性Hash
3.3.2 Map-Base : 取模法
先对Source地址进行Hash计算,再基于服务器总权重的取模(取相除后的余数),最终结果会决定客户端请求被分配到哪个后端服务器上
- 静态方法,不支持动态调整权重,不支持慢启动
- 可以实现后端服务器均衡调度
- 是Source Hash-Type选项 默认使用的算法
缺点:当服务器总权重发生变化时,导致调度结果整体变化
3.3.3 一致性Hash
一致性哈希,当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动
- 动态算法
- 支持利用 socat 等工具进行动态权重调整
- 支持服务器慢启动
1、后端服务器哈希环点keyA=hash(后端服务器虚拟ip)%(2^32)
2、客户机哈希环点key1=hash(client_ip)%(2^32) 得到的值在[0—4294967295]之间
3、将keyA和key1都放在hash环上,将用户请求调度到离key1最近的keyA对应的后端服务器
Hash环偏斜
当多个服务器IP经过Hash运算后,彼此的值相差不大,在环上呈现紧靠的现象
此时最小Hash值对应的服务器需要处理大部分的服务请求,这种现象称为 一致性Hash环倾斜
解决方案
增加虚拟服务器IP数量
比如:一个后端服务器根据权重为1,则生成1000个虚拟IP,再Hash
另一个后端服务器权重为2,则生成2000的虚拟IP,再Hash
最终在Hash环上生成3000个节点,从而解决Hash环偏斜问题
3.3.4 URL
基于对用户请求的URI的左半部分或整个URL做Hash,再将Hash结果对总权重进行取模后,根据结果将请求转发到后端指定服务器上
- 适用于后端是缓存服务器场景
- 静态算法
- 也可以通过Hash-Type指定Map-Based和一致性Hash
URL算法基于应用层,因此只支持 mode HTTP , 不支持 mode TCP
3.3.5 URL_Param
对用户请求的 URL 中的 Params 部分中的一个参数 Key 对应的 Value 值作 Hash 计算,并由 服务器总权重 相除,根据结果将客户端请求转发到后端指定服务器上
- 适用于电商网络
用于追踪用户,以确保来自同一个用户的请求始终发往同一个后端服务器
如果没有key,则会使用默认轮询调度算法(Roundrobin)
3.3.6 HDR
针对用户每个HTTP头部(Header)请求中的指定信息做Hash
由 Name 指定的HTTP首部将会被取出并做Hash计算,然后由服务器总权重取模后,根据结果将客户端请求转发到后端指定服务器上
如果没有有效值,则会使用默认轮询调度算法(Roundrobin)
4. Haproxy 实战
4.1 Haproxy 基于Cookie的会话保持
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
67 listen Webcluster
68 bind *:80
69 mode http
70 balance roundrobin
71 cookie WEBCOOKIE insert nocache indirect
72 server Web1 172.25.254.10:80 cookie est1 check inter 2 fall 3 rise 5 weight 1
73 server Web2 172.25.254.20:80 cookie est2 check inter 2 fall 3 rise 5 weight 1
systemctl restart haproxy.service
测试
[C:\~]$ curl -b WEBCOOKIE=est1 172.25.254.100
Web-Server - 172.25.254.10
[C:\~]$ curl -b WEBCOOKIE=est2 172.25.254.100
Web-Server - 172.25.254.20
4.2 Haproxy 状态页
Haproxy 自带一个状态,方便我们观察服务器的健康状态
4.2.1 状态页配置
参数 | 名称 |
---|---|
stats enable | 基于默认的参数启用stats page |
stats hide-version | 将状态页中haproxy版本隐藏 |
stats refresh <delay> | 设定自动刷新时间间隔,默认不自动刷新,过快耗费性能 |
stats uri <prefix> | 自定义stats page uri,默认值:/haproxy/status |
stats auth : <user>:<passwd> | 认证时的账号和密码,可定义多个用户,每行指定一个用户 默认:no authentication |
stats admin { if | unless } <cond> | 启用stats page中的管理功能 |
4.2.2 启用状态页
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
75 listen status
76 mode http
77 bind *:1314
78 stats enable
79 stats uri /status
80 stats auth haproxy:1314
[root@Haproxy ~]# systemctl restart haproxy.service
可以根据需求将不需要的信息过滤掉
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
82 #frontend main
......
......
105 # server app4 127.0.0.1:5004 check
# 将 82-105 行注释掉
[root@Haproxy ~]# systemctl restart haproxy.service
4.2.3 Haproxy 状态页信息
参数(左上角) | 说明 |
---|---|
pid = 1200 (process #1, nbproc = 1, nbthread = 4) | 当前PID号;当前进程号;一共多少进程和每个进程多少个线程 |
uptime = 0d 0h00m09s | 启动了多长时间 |
system limits: memmax = unlimited; ulimit-n = 8038 | 系统资源限制:内存;最大打开文件数 |
maxsock = 8038; maxconn = 4000; maxpipes = 0 | 最大socket=连接数;单进程最大连接数;最大管道数 |
current conns = 1; current pipes = 0/0; conn rate = 1/sec; bit rate = 0.000 kbps | 当前连接数;当前管道数;当前连接速率 |
Running tasks: 0/18; idle = 94 % | 运行的任务/当前空闲率 |
参数(正上方) | |||
---|---|---|---|
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 or backup DOWN for maintenance (MAINT) | active或者backup服务器人为下线的 | ||
active or backup SOFT STOPPED for maintenance | active或者backup被人为软下线(人为将weight改成0) |
Server 参数 | ||
---|---|---|
Session rate(每秒的连接会话信息) | Cur | 每秒的当前会话数量 |
Max | 每秒新的最大会话数量 | |
Limit | 每秒新的会话限制量 | |
Sessions(会话信息) | Cur | 当前会话量 |
Max | 最大会话量 | |
Limit | 限制会话量 | |
Total | 总共会话量 | |
LbTot | 选中一台服务器所用的总时间 | |
Last | 和服务器的持续连接时间 | |
Bytes | In | 网络的字节输入总量 |
Out | 网络的字节输出总量 | |
Denied(拒绝统计信息) | Req | 拒绝请求量 |
Resp | 拒绝回复量 | |
Errors(错误统计信息) | Req | 错误请求量 |
Conn | 错误链接量 | |
Resp | 错误响应量 | |
Warnings(警告统计信息) | Retr | 重新尝试次数 |
Redis | 再次发送次数 | |
Server(RS 信息) | Status | 后端机的状态,包括UP和DOWN |
LastChk | 持续检查后端服务器的时间 | |
Wght | 权重 | |
Act | 活动链接数量 | |
Bck | 备份的服务器数量 | |
Chk | 心跳检测时间 | |
Dwn | 后端服务器连接后都是DOWN的数量 | |
Dwntme | 总的downtime时间 | |
Thrtle | Server 状态 |
4.3 Haproxy IP透传
Web服务器中需要记录客户端的真实IP地址,用于做访问统计、安全防护、行为分析、区域排行等场景
4.3.1 七层透传
不做透传
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
46 defaults
......
52 #option forwardfor except 127.0.0.0/8
[root@Haproxy ~]# systemctl restart haproxy.service
[C:\~]$ curl 172.25.254.100
Web-Server - 172.25.254.20
# 不能显示客户端的IP
[root@Server2 ~]# cat /var/log/nginx/access.log
172.25.254.100 - - [12/Aug/2024:02:12:08 +0800] "GET / HTTP/1.1" 200 27 "-" "curl/8.0.1" "-"
做透传
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
46 defaults
......
52 option forwardfor except 127.0.0.0/8 # 当客户端IP为回环时,不做透传
[root@Haproxy ~]# systemctl restart haproxy.service
[C:\~]$ curl 172.25.254.100
Web-Server - 172.25.254.20
# 显示客户端的IP
[root@Server2 ~]# cat /var/log/nginx/access.log
172.25.254.100 - - [12/Aug/2024:14:13:24 +0800] "GET / HTTP/1.1" 200 27 "-" "curl/8.0.1" "172.25.254.1"
- Nginx 默认配置好透传,而Apache则没有
HTTP七层透传
[root@Server1 ~]# yum install httpd -y
[root@Server1 ~]# systemctl disable nginx.service
[root@Server1 ~]# systemctl start httpd
[C:\~]$ curl 172.25.254.100
Web-Server - 172.25.254.10
# 不显示客户端的IP
[root@Server1 ~]# cat /etc/httpd/logs/access_log
172.25.254.100 - - [12/Aug/2024:14:18:30 +0800] "GET / HTTP/1.1" 200 26 "-" "curl/8.0.1"
[root@Server1 ~]# vim /etc/httpd/conf/httpd.conf
201 LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
[root@Server1 ~]# systemctl restart httpd
[C:\~]$ curl 172.25.254.100
Web-Server - 172.25.254.10
[root@Server1 ~]# cat /etc/httpd/logs/access_log
172.25.254.1 172.25.254.100 - - [12/Aug/2024:14:34:31 +0800] "GET / HTTP/1.1" 200 26 "-" "curl/8.0.1"
4.3.2 四层透传
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
66 listen web-server
67 bind *:80
68 mode tcp # TCP 四层透传
69 balance roundrobin
70 server web1 172.25.254.10:80 check inter 2 fall 2 rise 5
71 server web2 172.25.254.20:80 check inter 2 fall 2 rise 5
# 两个服务均不能显示客户端IP
[root@Server1 ~]# cat /etc/httpd/logs/access_log
- 172.25.254.100 - - [12/Aug/2024:02:37:17 +0800] "GET / HTTP/1.1" 200 26 "-" "curl/8.0.1"
[root@Server2 ~]# cat /var/log/nginx/access.log
172.25.254.100 - - [12/Aug/2024:02:37:18 +0800] "GET / HTTP/1.1" 200 27 "-" "curl/8.0.1" "-"
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
66 listen web-server
67 bind *:80
68 mode tcp
69 balance roundrobin
70 server web1 172.25.254.10:80 check inter 2 fall 2 rise 5
71 server web2 172.25.254.20:80 send-proxy check inter 2 fall 2 rise 5
[root@Haproxy ~]# systemctl restart haproxy.service
[root@Server2 ~]# vim /etc/nginx/nginx.conf
18 log_format main '$remote_addr - $remote_user [$time_local] "$request" '
19 '$status $body_bytes_sent "$http_referer" '
20 '"$proxy_protocol_addr"' # 新增行
21 '"$http_user_agent" "$http_x_forwarded_for"';
39 listen 80 proxy_protocol; # 启用此项,将无法直接访问网站,只能通过四层代理访问,如果做七层透传 proxy_protocol 不能有!!!
[root@Server2 ~]# systemctl restart nginx.service
# Nginx,而Apache已不支持四层透传
[root@Server2 ~]# cat /var/log/nginx/access.log
172.25.254.100 - - [12/Aug/2024:02:48:43 +0800] "GET / HTTP/1.1" 200 27 "-" "172.25.254.1""curl/8.0.1" "-"
4.4 Haproxy ACL
4.4.1 ACL 介绍
访问控制列表ACL(Access Control Lists)
- 一种基于包过滤的访问控制技术
- 根据设定的条件对经过服务器传输的数据包进行过滤
- 基于请求报文头部中的源目地址、源目端口、请求方法、文件后缀等信息内容进行匹配并执行进一步操作
4.4.2 ACL 参数
- 定义ACL
ACL | aclname | criterion | flags | operator | value |
---|---|---|---|---|---|
ACL | 名称 | 匹配规范 | 匹配模式 | 具体操作符 | 操作对象类型 |
名称可以使用大小写字母、数字、冒号,点 . 、中横线 - 、下划线 _ ,并且区分大小写
ACL-criterion 匹配规范
即ACL的判断条件
格式 | 模式 | 说明 |
---|---|---|
hdr string | 提取一个HTTP请求报文的首部 | |
hdr([<name> [,<occc>]]) | 完全匹配字符串 | header的指定信息, 表示在多值中使用的值的出 现次数 |
hdr_beg([<name> [,<occc>]]) | 前缀匹配 | header中指定匹配内容的begin |
hdr_end([<name> [,<occc>]]) | 后缀匹配 | header中指定匹配内容end |
hdr_dom([<name> [,<occc>]]) | 域匹配 | header中的dom(host) |
hdr_dir([<name> [,<occc>]]) | 路径匹配 | header的uri路径 |
hdr_len([<name> [,<occc>]]) | 长度匹配 | header的长度匹配 |
hdr_reg([<name> [,<occc>]]) | 正则表达式匹配 | 自定义表达式(regex)模糊匹配 |
hdr_sub([<name> [,<occc>]]) | 子串匹配 | header中的uri模糊匹配 模糊匹配c 报文中a/b/c也会匹 配 |
ACL-flags 匹配模式
参数 | 说明 |
---|---|
-i | 不区分大小写 |
-m | 使用指定的正则表达式匹配方法 |
-n | 不做DNS解析 |
-u | 禁止ACL重名 |
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进行匹配 |
ACL-value 操作对象
参数 | 说明 |
---|---|
Boolean | 布尔值 |
integer or integer range | 整数或整数范围,比如用于匹配端口范围 |
IP address / network | IP地址或IP范围 |
string | |
exact | 精确比较 |
substring | 子串 |
suffix | 后缀比较 |
prefix | 前缀比较 |
subdir | 路径 |
domain | 域名 |
regular expression | 正则表达式 |
hex block | 16进制 |
多个ACL的组合调用方式
-
多个ACL的逻辑处理
- 与:默认使用
- 或:使用 or 或 || 表示
- 否定:使用 ! 表示
-
多个ACL调用方式
if A B # 与关系,ACL中A和B都要满足为true,默认为与
if A || B # 或,ACL中A或者B满足一个为true
if ! A # 非,取反,不满足ACL才为true
4.4.3 基于 ACL 匹配 访问路径 实现动静分离
Haproxy
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
66 frontend webcluster
67 bind *:80
68 mode http
69 acl static path_sub -m sub static
70 acl php path_sub -m sub php
71 ##################################
72 use_backend webcluster-host if php
73 default_backend default-host
74
75 backend webcluster-host
76 mode http
77 server web1 172.25.254.10:80 check inter 2 fall 2 rise 5
78
79 backend default-host
80 mode http
81 server web2 172.25.254.20:80 check inter 2 fall 2 rise 5
[root@Haproxy ~]# systemctl restart haproxy.service
Server-HTTP
yum install php -y
mkdir -p /var/www/html/php
vim /var/www/html/php/index.html
<?php
phpinfo();
?>
systemctl restart httpd
Server-Nginx
mkdir /usr/share/nginx/html/static -p
echo static - 172.25.254.20 Nginx > /usr/share/nginx/html/static/index.html
# 如果没有做四层透传,则忽略此步骤
[root@Server2 ~]# vim /etc/nginx/nginx.conf
18 log_format main '$remote_addr - $remote_user [$time_local] "$request" '
19 '$status $body_bytes_sent "$http_referer" '
20 '"$proxy_protocol_addr"' # 将此行删去
21 '"$http_user_agent" "$http_x_forwarded_for"';
39 listen 80; # 将四层透传参数 proxy_protocol 去掉
systemctl restart nginx.service
测试
4.5 Haproxy 错误页面
对指定的页面错误代码进行重定向,优雅地显示错误页面
使用 errorfile 指令,可以自定义错误页面
4.5.1 自定义错误页面
# Haproxy 默认使用的错误错误页面
[root@Haproxy ~]# rpm -ql haproxy | 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
格式
errorfile <code> <file>
# code:支持200, 400, 403, 405, 408, 425, 429, 500, 502,503,504
# file:包含完整HTTP响应头的错误页文件的绝对路径.建议后缀 .http 方便与一般的HTML文件相区分
配置
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
63 errorfile 503 /haproxy/errorpages/code-503.http
[root@Haproxy ~]# mkdir /haproxy/errorpages/ -p
[root@Haproxy ~]# cp /usr/share/haproxy/503.http /haproxy/errorpages/code-503.http
[root@Haproxy ~]# vim /haproxy/errorpages/code-503.http
HTTP/1.0 503 Service Unavailable
Cache-Control: no-cache
Connection: close
Content-Type: text/html;charset=UTF-8
<html><body><h1>!!! 503 !!!</h1>
</body></html>
[root@Haproxy ~]# systemctl restart haproxy.service
Server
systemctl stop nginx.service
测试
4.5.2 重定向错误页面
使用 errorloc 指令,遇到错误代码时,重定向错误页面
配置
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
63 errorloc 503 https://www.baidu.com
测试
4.6 Haproxy 四层负载
主要应用于HTTP以外的TCP协议应用服务访问的场景
- MySQL、Redis
- Memcache、RabbitMQ
注意:如果使用frontend和backend,一定在 frontend 和 backend 段中都指定mode tcp
4.6.1 Haproxy
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
82 listen mysql
83 bind *:3306
84 mode tcp
85 balance static-rr
86 server mysql1 172.25.254.10:3306 check inter 2 fall 2 rise 5
87 server mysql2 172.25.254.20:3306 check inter 2 fall 2 rise 5
[root@Haproxy ~]# systemctl restart haproxy.service
[root@Haproxy ~]# yum install mariadb -y
4.6.2 Server1
[root@Server1 ~]# yum install mariadb-server -y
[root@Server1 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
16 [mysqld]
17 server-id=1
[root@Server1 ~]# mysql
MariaDB [(none)]> CREATE USER est@'%' identified by 'est';
MariaDB [(none)]> GRANT ALL ON *.* TO est@'%';
[root@Server1 ~]# systemctl start mariadb
4.6.2 Server2
[root@Server2 ~]# yum install mariadb-server -y
[root@Server2 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
16 [mysqld]
17 server-id=2
[root@Server2 ~]# mysql
MariaDB [(none)]> CREATE USER est@'%' identified by 'est';
MariaDB [(none)]> GRANT ALL ON *.* TO est@'%';
[root@Server1 ~]# systemctl start mariadb
4.6.3 测试
[root@Haproxy ~]# mysql -uest -pest -h 172.25.254.100
MariaDB [(none)]> SELECT @@server_id;
+-------------+
| @@server_id |
+-------------+
| 2 |
+-------------+
MariaDB [(none)]> show variables like 'hostname';
+---------------+-------------+
| Variable_name | Value |
+---------------+-------------+
| hostname | Server2.org |
+---------------+-------------+
MariaDB [(none)]> SELECT @@server_id;
+-------------+
| @@server_id |
+-------------+
| 1 |
+-------------+
MariaDB [(none)]> show variables like 'hostname';
+---------------+-------------+
| Variable_name | Value |
+---------------+-------------+
| hostname | Server1.org |
+---------------+-------------+
4.7 Haproxy https实现
4.7.1 Haproxy
mkdir /etc/haproxy/certs/
openssl req -newkey rsa:2048 -nodes -sha256 -keyout /etc/haproxy/certs/haproxy.org.key -x509 -days 365 -out /etc/haproxy/certs/haproxy.org.crt
# Country Name (2 letter code) [XX]:CN
# State or Province Name (full name) []:Shanghai
# Locality Name (eg, city) [Default City]:SHANGHAI
# Organization Name (eg, company) [Default Company Ltd]:Haproxy
# Organizational Unit Name (eg, section) []:Webserver
# Common Name (eg, your name or your server's hostname) []:www.est.org
# Email Address []:admin@est.org
[root@Haproxy ~]# cat /etc/haproxy/certs/haproxy.org.key /etc/haproxy/certs/haproxy.org.crt > /etc/haproxy/certs/haproxy.pem
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen web-https
bind *:443 ssl crt /etc/haproxy/certs/haproxy.pem
mode http
balance roundrobin
server web1 172.25.254.10:80 check inter 2 fall 2 rise 5
server web2 172.25.254.20:80 check inter 2 fall 2 rise 5
[root@Haproxy ~]# systemctl restart haproxy.service
4.7.2 Server1
systemctl restart nginx.service
4.7.2 Server2
systemctl restart nginx.service
4.7.3 测试
4.7.4 全站加密
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend Webcluster
bind *:80
mode http
redirect scheme https if !{ ssl_fc }
listen web-https
bind *:443 ssl crt /etc/haproxy/certs/haproxy.pem
mode http
balance roundrobin
server web1 172.25.254.10:80 check inter 2 fall 2 rise 5
server web2 172.25.254.20:80 check inter 2 fall 2 rise 5
[root@Haproxy ~]# systemctl restart haproxy.service
测试