目录
1、HAProxy的负载均衡
1.1socat工具的使用
1.1.1对于单进程
1.1.2对于多进程处理方法(对haproxy做热处理)
2、Haproxy的算法
2.1静态算法
<1>static-rr
<2>first
2.2动态算法
<1>roundrobin
<2>leastconn
<3>random
2.3其他算法(以下算法取决于hash-type 是否是consistent)
<1>Source
<2>map-base取模法
<3>一致性 hash
<4>uri
<5>url_param
<6>hdr(User-Agent) #基于客户端请求报文
3、haproxy的状态页
4、haproxy高级算法及配置
4.2 IP透传
4.2.1七层透传
4.2.2 四层IP透传
5、ACL配置选项
5.1 ACL匹配模式
5.2 ACL匹配规范:
5.3 ACL实战
ACL示例1-域名匹配
ACL示例2-基于源IP或子网调度访问
ACL示例3-基于源地址的访问控制
ACL示例4-匹配浏览器类型
ACL示例5-基于文件后缀名实现动静分离
ACL示例6-匹配访问路径实现动静分离
6、HAProxy自定义错误页面
7、MYSQL的负载均衡
8、HAProxy https 实现
1、HAProxy的负载均衡
HAProxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。
HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。
并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。
1.1socat工具的使用
对服务器动态权重和其它状态可以利用 socat工具进行调整,Socat 是 Linux 下的一个多功能的网络工具,名字来由是Socket CAT,相当于netCAT的增强版.Socat 的主要特点就是在两个数据流之间建立双向通道,且支持众多协议和链接方式。如IP、TCP、UDP、IPv6、Socket文件等
——动态调整haproxy中的参数
示例:
[root@haproxy ~]# dnf install socat -y
1.1.1对于单进程
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
[root@haproxy ~]# systemctl restart haproxy.service
[root@haproxy ~]# echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock
#显示详细信息
[root@haproxy ~l#echo "show servers state" | socat stdio /var/lib/haproxy/haproxy.sock
#显示服务的状态
[root@haproxy ~]# echo "get weight webcluster/web1" | socat stdio /var/lib/haproxy/haproxy.sock
#查看web1这个服务的权重值
[root@haproxy ~]# echo "set weight webcluster/web1 2" | socat stdio /var/lib/haproxy/haproxy.sock
#设置web1这个权重值为2
[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
#开启此服务的进程
[root@haproxy ~]# echo "help" | socat stdio /var/lib/haproxy/stats #查看socat的帮助信息
1.1.2对于多进程处理方法(对haproxy做热处理)
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
[root@haproxy ~]# systemctl restart haproxy.service
stats进程此时不能使用,但stats1和stats2可以使用
[root@haproxy ~]# echo "help" | socat stdio /var/lib/haproxy/stats
2024/08/08 23:51:38 socat[4832] E connect(5, AF=1 "/var/lib/haproxy/stats", 24): Connection refused
[root@haproxy ~]# echo "show info" | socat stdio /var/lib/haproxy/stats1
Name: HAProxy
Version: 1.8.27-493ce0b
Release_date: 2020/11/06
Nbthread: 1
Nbproc: 2
Process_num: 1
Pid: 4802
Uptime: 0d 0h02m09s
…
2、Haproxy的算法
Haproxy通过固定参数 balance 指明对后端服务器的调度算法
balance参数可以配置在listen或backend选项中
Haproxy的调度算法分为静态和动态调度算法
有些算法可以根据参数在静态和动态算法中相互转换。
2.1静态算法
静态算法只能重启生效
后端服务器理论上无限
<1>static-rr
基于权重的轮询调度,不支持运行时利用socat进行权重的动态调整(只支持0和1,不支持其它值)及后端服务器慢启动,其后端主机数量没有限制,相当于LVS中的 wrr
<2>first
根据服务器在列表中的位置,自上而下进行调度,但是其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务,因此会忽略服务器的权重设置,此方式使用较少
不支持用socat进行动态修改权重,可以设置0和1,可以设置其它值但无效
2.2动态算法
基于后端服务器状态进行调度适当调整
新请求将优先调度至当前负载较低的服务器
权重可以在haproxy运行时动态调整无需重启
<1>roundrobin
基于权重的轮询动态调度算法,支持权重的运行时调整,不同于lvs中的轮询模式,
HAProxy中的roundrobin支持慢启动(新加的服务器会逐渐增加转发数),其每个后端backend中最多支持4095个real server,支持对real server权重动态调整,roundrobin为默认调度算法,此算法使用广泛
哪个后端服务器负载小就把请求转发给哪个后端服务器
<2>leastconn
leastconn 加权的最少连接的动态,支持权重的运行时调整和慢启动,即:根据当前连接最少的后端服务器而非权重进行优先调度(新客户端连接),比较适合长连接的场景使用,比如:MySQL等场景。
<3>random
在1.9版本开始增加 random的负载平衡算法,其基于随机数作为一致性hash的key,随机负载平衡对于大型服务器场或经常添加或删除服务器非常有用,支持weight的动态调整,weight较大的主机有更大概率获取新请求
2.3其他算法(以下算法取决于hash-type 是否是consistent)
<1>Source
源地址hash,基于用户源地址hash并将请求转发到后端服务器,后续同一个源地址请求将被转发至同一个后端web服务器。
此方式当后端服务器数据量发生变化时,会导致很多用户的请求转发至新的后端服务器,默认为静态方式,但是可以通过hash-type选项进行更改
这个算法一般是在不插入Cookie的TCP模式下使用,也可给不支持会话cookie的客户提供最好的会话粘性,适用于session会话保持但不支持cookie和缓存的场景
源地址有两种转发客户端请求到后端服务器的服务器选取计算方式,分别是取模法和一致性hash
<2>map-base取模法
取模法,对source地址进行hash计算,再基于服务器总权重的取模,最终结果决定将此
请求转发至对应的后端服务器。此方法是静态的,即不支持在线调整权重,不支持慢启动,可实现对后端服务器均衡调度。缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因总权重发生变化而导致调度结果整体改变,hash-type 指定的默认值为此算法
<3>一致性 hash
一致性哈希,当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动,hash(o)mod n ,该hash算法是动态的,支持使用 socat等工具进行在线权重调整,支持慢启动
1、key1=hash(source_ip)%(2^32) [0---4294967295]
2、keyA=hash(后端服务器虚拟ip)%(2^32)
3、将key1和keyA都放在hash环上,将用户请求调度到离key1最近的keyA对应的后端服务器
hash环偏斜问题
增加虚拟服务器IP数量,比如:一个后端服务器根据权重为1生成1000个虚拟IP,再hash。而后端服务器权重为2则生成2000的虚拟IP,再进行hash运算,最终在hash环上生成3000个节点,从而解决hash环偏斜问题
<4>uri
基于对用户请求的URI的左半部分或整个uri做hash,再将hash结果对总权重进行取模后,根据最终结果将请求转发到后端指定服务器,适用于后端是缓存服务器场景,默认是静态算法,也可以通过hash-type
指定map-based和consistent,来定义使用取模法还是一致性hash。
Url:网址要找的路径位置
uri不变访问的地址就不变
<5>url_param
url_param对用户请求的url中的 params 部分中的一个参数key对应的value值作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个real server,如果无没key,将按roundrobin算法
<6>hdr(User-Agent) #基于客户端请求报文
针对用户每个http头部(header)请求中的指定信息做hash,此处由 name 指定的http首部将会被取出并做hash计算,然后由服务器总权重取模以后派发至某挑出的服务器,如果无有效值,则会使用默认的轮询调度。
3、haproxy的状态页
状态页配置项:
4、haproxy高级算法及配置
4.1基于cookie的会话保持
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
[root@localhost ~]# curl -b cookie=lhd1 192.168.182.151
webserver1
[root@localhost ~]# curl -b cookie=lhd2 192.168.182.151 #指定到cookie所设定的值
webserver2
[root@localhost ~]#
-b, --cookie <data> Send cookies from string/file
4.2 IP透传
4.2.1七层透传
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
[root@webserver1 ~]# vim /etc/httpd/conf/httpd.conf #修改apache服务日志
测试:
通过测试可以追踪到是192.168.182.154和192.168.182.153这两个用户端访问的本机服务端
4.2.2 四层IP透传
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
[root@webserver2 ~]# vim /etc/nginx/nginx.conf #nginx服务修改日志格式
测试:可以追踪到是哪个用户访问了本机
5、ACL配置选项
acl <aclname> <criterion> [flags] [operator] [<value>]
acl 名称 匹配规范 匹配模式 具体操作符 操作对象类型
5.1 ACL匹配模式
-i 不区分大小写
-m 使用指定的正则表达式匹配方法
-n 不做DNS解析
-u 禁止acl重名,否则多个同名ACL匹配或关系
5.2 ACL匹配规范:
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也会匹配
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
path_reg : regex match
path_sub : substring match
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
5.3 ACL实战
ACL示例1-域名匹配
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl test hdr_dom(host) -i www.lhd.com
acl test hdr_end(host) -i .com
use_backend webcluster-host if test
default_backend default-host
backend webcluster-host
mode http
server web1 192.168.182.152:80 check
backend default-host
mode http
server web2 192.168.182.153:80 check
测试结果:
[root@localhost ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.182.151 www.lhd.com www.test.com
[root@localhost ~]# curl www.lhd.com
webserver1
[root@localhost ~]# curl www.test.com
webserver1
ACL示例2-基于源IP或子网调度访问
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl ctrl_ip src 192.168.182.154 192.168.182.153 #153和154这两个主机
use_backend webcluster-host if ctrl_ip #如果是这两个主机就访问到web1的后端
default_backend default-host
backend webcluster-host
mode http
server web1 192.168.182.152:80 check
backend default-host
mode http
server web2 192.168.182.153:80 check
测试结果:
[root@webserver2 ~]# curl 192.168.182.151 #192.168.182.153主机所访问的结果索引
web1服务上
webserver1
[root@localhost ~]# curl 192.168.182.151 #192.168.182.154主机所访问的结果
webserver1
[root@webserver1 ~]# curl 192.168.182.151 #192.168.182.152主机所访问的结果默认到web2服务上
webserver2
ACL示例3-基于源地址的访问控制
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl ctrl_ip src 192.168.182.154 192.168.182.153
acl test hdr_dom(host) -i www.lhd.com test所指的是域名
http-request deny if test 拒绝访问test
default_backend default-host
backend webcluster-host
mode http
server web1 192.168.182.152:80 check
backend default-host
mode http
server web2 192.168.182.153:80 check
测试结果:
[root@webserver2 ~]# curl 192.168.182.151 #在192.168.182.153主机上被索引到默认后端
webserver2
[root@localhost ~]# curl 192.168.182.151 #在192.168.182.154主机上被索引到默认后端
webserver2
[root@localhost ~]# curl www.lhd.com 域名被拒绝访问
<html><body><h1>403 Forbidden</h1>
Request forbidden by administrative rules.
</body></html>
ACL示例4-匹配浏览器类型
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl badwebrowers hdr_sub(User-Agent) -i curl wget
http-request deny if badwebrowers
default_backend default-host
backend webcluster-host
mode http
server web1 192.168.182.152:80 check
backend default-host
mode http
server web2 192.168.182.153:80 check
测试结果:
[root@localhost ~]# curl 192.168.182.151
<html><body><h1>403 Forbidden</h1>
Request forbidden by administrative rules.
</body></html>
被索引到默认web2主机上
ACL示例5-基于文件后缀名实现动静分离
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl static path_end -i .html .jpg .png .css .js
acl dhcp path_end -i .php
use_backend webcluster-host if dhcp #如果匹配的是dhcp就使用index.php访问到php默认主页上,如果是static就用index.jpg访问到web2服务上
default_backend default-host
backend webcluster-host
mode http
server web1 192.168.182.152:80 check
backend default-host
mode http
server web2 192.168.182.153:80 check
测试结果:
[root@webserver1 ~]# echo php 192.168.182.152 > /var/www/html/index.php
[root@webserver2 ~]# echo jpg 192.168.182.153 > /usr/share/nginx/html/index.jpg
[root@localhost ~]# curl 192.168.182.151/index.php
php 192.168.182.152
[root@localhost ~]# curl 192.168.182.151/index.jpg
jpg 192.168.182.153
ACL示例6-匹配访问路径实现动静分离
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl static path_sub -m sub /static
acl php path_sub -m sub /php
use_backend webcluster-host if php #如果是匹配的是php就通过/php路径访问到web1服务上,否则则是访问到web2服务上
default_backend default-host
backend webcluster-host
mode http
server web1 192.168.182.152:80 check
backend default-host
mode http
server web2 192.168.182.153:80 check
测试结果:
[root@webserver1 ~]# mkdir -p /var/www/html/php
[root@webserver1 ~]# echo php 192.168.182.152 > /var/www/html/php/index.html
[root@webserver2 ~]# mkdir -p /usr/share/nginx/html/static
[root@webserver2 ~]# echo static 192.168.182.153 > /usr/share/nginx/html/static/index.html
[root@localhost ~]# curl 192.168.182.151/php/
php 192.168.182.152
[root@localhost ~]# curl 192.168.182.151/static/
static 192.168.182.153
6、HAProxy自定义错误页面
先模拟停止两台web服务
[root@haproxy ~]# mkdir -p /etc/haproxy/errorpage
[root@haproxy ~]#
[root@haproxy ~]# cat /usr/share/haproxy/503.http
HTTP/1.0 503 Service Unavailable
Cache-Control: no-cache
Connection: close
Content-Type: text/html
<html><body><h1>503 Service Unavailable</h1>
No server is available to handle this request.
</body></html>
[root@haproxy ~]# cp /usr/share/haproxy/503.http /etc/haproxy/errorpage/bad.http
[root@haproxy ~]# cat /etc/haproxy/errorpage/bad.http
HTTP/1.0 503 Service Unavailable
Cache-Control: no-cache
Connection: close
Content-Type: text/html
<html><body><h1>你是不是没有生么事情</h1>
HAHAHA!!!
</body></html>
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
# 将错误修改
[root@haproxy ~]# systemctl restart haproxy.service
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
#将错误重定向到百度网页
7、MYSQL的负载均衡
[root@webserver1 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[root@webserver1 ~]# systemctl start mariadb.service
[root@webserver2 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[root@webserver2 ~]# systemctl start mariadb.service
Webserver1服务端:
MariaDB [mysql]> create user lhd@'%' identified by '123';
Query OK, 0 rows affected (0.000 sec)
MariaDB [mysql]> grant all on *.* to lhd@'%';
Query OK, 0 rows affected (0.000 sec)
Webserver2服务端:
MariaDB [(none)]> create user lhd@'%' identified by '123';
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> grant all on *.* to lhd@'%';
Query OK, 0 rows affected (0.000 sec)
测试:
[root@haproxy ~]# for i in {1..6}; do mysql -ulhd -p123 -h 192.168.182.151 -e "select @@server_id"; done
+-------------+
| @@server_id |
+-------------+
| 1 |
+-------------+
+-------------+
| @@server_id |
+-------------+
| 2 |
+-------------+
+-------------+
| @@server_id |
+-------------+
| 1 |
+-------------+
+-------------+
| @@server_id |
+-------------+
| 2 |
+-------------+
+-------------+
| @@server_id |
+-------------+
| 1 |
+-------------+
+-------------+
| @@server_id |
+-------------+
| 2 |
+-------------+
8、HAProxy https 实现
1、制作证书
[root@haproxy ~]# mkdir -p /etc/haproxy/certs
[root@haproxy ~]# openssl req -newkey rsa:2048 -nodes -sha256 -keyout /etc/haproxy/certs/lhd.key -x509 -days 365 -out /etc/haproxy/certs/lhd.crt
[root@haproxy ~]# ls /etc/haproxy/certs/
lhd.crt lhd.key
[root@haproxy ~]# cat /etc/haproxy/certs/lhd.crt /etc/haproxy/certs/lhd.key > /etc/haproxy/certs/lhd.pem
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
#全站加密之后,当访问IP时默认是80端口,会自动转到443端口登陆
测试: