目录
4.1设置backup --- sorryserver的端口
一、haproxy简介
HAProxy
是法国开发者 威利塔罗
(Willy Tarreau)
在
2000
年使用
C
语言开发的一个开源软件
是一款具备高并发
(
万级以上
)
、高性能的
TCP
和
HTTP
负载均衡器
支持基于
cookie
的持久性,自动故障切换,支持正则表达式及
web
状态统计
企业版网站:
https://www.haproxy.com
社区版网站:
http://www.haproxy.org
github
:
https://github.com/haprox
企业版本和社区版功能对比
二、haproxy实验
1.环境部署
haproxy | 192.168.5.100 |
webserver1 | 192.168.5.10 |
webserver2 | 192.168.5.20 |
2.haproxy的基本部署方法及负载均衡的实现
2.1安装软件
dnf install haproxy -y
2.2haproxy的基本配置
3.haproxy的全局配置参数及日志分离
3.1多线程设定
3.2自定义日志
vim /etc/rsyslog.conf
4.haproxy-proxies中的常用配置参数
4.1设置backup --- sorryserver的端口
disabled指定下线的后端服务器
4.2访问重定向
5.haproxy热更新方法
5.1socat
下载
dnf install socat -y
# 查看 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/stats2 (initial 2)[root@haproxy ~]# echo get weight webcluster/web2 | socat stdio /var/lib/haproxy/stats1 (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
针对多进程问题
6.haproxy中的算法
6.1静态算法
静态算法:按照事先定义好的规则轮询公平调度,不关心后端服务器的当前负载、连接数和响应速度 等,且无法实时修改权重(
只能为
0
和
1,
不支持其它值
)
,只能靠重启
HAProxy
生效。
6.1.1static-rr:基于权重的轮询调度
6.1.2 first
# 在两台主机上分别执行此循环,可以观察是否 102 被调度到while true;do curl 172.25.254.100 ; sleep 0.1;done
6.2动态算法
6.2.1roundrobin
动态调整权重
[root@haproxy ~]# echo "set weight webserver_80/webserver1 2" | socat stdio/var/lib/haproxy/haproxy.sock
6.2.2 leastconn
6.3其他算法
6.3.1source
6.3.1.1 map-base 取模法
所谓取模运算,就是计算两个数相除之后的余数,
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 ----- > nodeb1112 ------> nodec1113 ------> nodea如果 a 下线后,权重数量发生变化1111%2=1 , 1112%2=0 , 1113%2=11112 和 1113 被调度到的主机都发生变化,这样会导致会话丢失
# 不支持动态调整权重值[root@haproxy ~]# echo "set weight webserver_80/webserver1 2" | socat stdio/var/lib/haproxy/haproxy.sockBackend 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.sock0 (initial 1)
6.3.1.2 一致性hash
一致性哈希,当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动
hash
(
o
) mod n
该
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 数量,比如:一个后端服务器根据权重为 1 生成 1000 个虚拟 IP ,再 hash 。而后端服务器权 重为2 则生成 2000 的虚拟 IP ,再 bash, 最终在 hash 环上生成 3000 个节点,从而解决 hash 环偏斜问题
hash
对象
Hash
对象到后端服务器的映射关系:
一致性
hash
示意图
后端服务器在线与离线的调度方式
一致性
hash
配置示例
6.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>
6.3.2.1 uri 取模法配置示例
6.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"
6.3.3.1 url_param取模法配置示例
6.3.4 hdr
针对用户每个
http
头部
(header)
请求中的指定信息做
hash
,
此处由
name
指定的
http
首部将会被取出并做
hash
计算,
然后由服务器总权重取模以后派发至某挑出的服务器,如果无有效值,则会使用默认的轮询调度。
6.3.4.1 hdr取模法配置示例
6.3.6 算法总结
# 静态static-rr--------->tcp/httpfirst------------->tcp/http# 动态roundrobin-------->tcp/httpleastconn--------->tcp/http# 以下静态和动态取决于 hash_type 是否 consistentsource------------>tcp/httpUri--------------->httpurl_param--------->httphdr--------------->http
6.3.7 各算法使用场景
first # 使用较少static-rr # 做了 session 共享的 web 集群roundrobinleastconn # 数据库source# 基于客户端公网 IP 的会话保持Uri--------------->http # 缓存服务器, CDN 服务商,蓝汛、百度、阿里云、腾讯url_param--------->http # 可以实现 session 保持hdr # 基于客户端请求报文头部做下一步处理
三.高级功能及配置
3.1基于cookie的会话保持
cookie value
:为当前
server
指定
cookie
值,实现基于
cookie
的会话黏性,相对于基于
source
地址
hash调度算法对客户端的粒度更精准,但同时也加大了haproxy
负载,目前此模式使用较少, 已经被
session共享服务器代替
3.1.1 配置选项
cookie name [ rewrite | insert | prefix ][ indirect ] [ nocache ][ postonly ] [preserve ][ httponly ] [ secure ][ domain ]* [ maxidle <idle> ][ maxlife ]name : #cookie 的 key 名称,用于实现持久连接insert : # 插入新的 cookie, 默认不插入 cookieindirect : # 如果客户端已经有 cookie, 则不会再发送 cookie 信息nocache : # 当 client 和 hapoxy 之间有缓存服务器(如: CDN )时,不允许中间缓存器缓存 cookie ,# 因为这会导致很多经过同一个 CDN 的请求都发送到同一台后端服务器
3.2HAProxy状态页
3.2.1 状态页配置项
stats enable # 基于默认的参数启用 stats pagestats hide-version # 将状态页中 haproxy 版本隐藏stats refresh <delay> # 设定自动刷新时间间隔,默认不自动刷新stats uri <prefix> # 自定义 stats page uri ,默认值: /haproxy?statsstats auth <user>:<passwd> # 认证时的账号和密码,可定义多个用户 , 每行指定一个用户# 默认: no authenticationstats admin { if | unless } <cond> # 启用 stats page 中的管理功能
登录状态页
#pid 为当前 pid 号, process 为当前进程号, nbproc 和 nbthread 为一共多少进程和每个进程多少个线程pid = 27134 (process #1, nbproc = 1, nbthread = 1)# 启动了多长时间uptime = 0d 0h00m04s# 系统资源限制:内存 / 最大打开文件数 /system limits: memmax = unlimited; ulimit-n = 200029# 最大 socket 连接数 / 单进程最大连接数 / 最大管道数 maxpipesmaxsock = 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
backend server
信息
session rate(
每秒的连接会话信息
):
Errors(
错误统计信息
)
:
cur:
每秒的当前会话数量
:
Req:
错误请求量
max:
每秒新的最大会话数量
conn:
错误链接量
limit:
每秒新的会话限制量
Resp:
错误响应量
sessions(
会话信息
):
Warnings(
警告统计信息
)
:
cur:
当前会话量
Retr:
重新尝试次数
max:
最大会话量
Redis:
再次发送次数
limit:
限制会话量
Total:
总共会话量
Server(real server
信息
)
:
LBTot:
选中一台服务器所用的总时间
Status:
后端机的状态,包括
UP
和
DOWN
Last
:和服务器的持续连接时间
LastChk:
持续检查后端服务器的时间
Wght:
权重
Bytes(
流量统计
)
:
Act:
活动链接数量
In:
网络的字节输入总量
Bck:
备份的服务器数量
Out:
网络的字节输出总量
Chk:
心跳检测时间
Dwn:
后端服务器连接后都是
DOWN
的数量
Denied(
拒绝统计信息
)
:
Dwntme:
总的
downtime
时间
Req:
拒绝请求量
Thrtle:server
状态
Resp:
拒绝回复量
####
3.3 IP透传
3.3.2 四层IP透传
# 查看日志内容[root@rs1 ~]# tail -n 3 /var/log/nginx/access.log192.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" "-"192.168.0.10 - - [10/Jul/2024:15:41:56 +0800] "GET / HTTP/1.1" "172.25.254.10"20018 "-" "curl/7.29.0"
3.3.3 七层IP透传
配置
web
服务器,记录负载均衡透传的客户端
IP
地址
#apache 配置:
LogFormat "%{X-Forwarded-For}i %a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%
{User-Agent}i\"" combined
#nginx 日志格式:
$proxy_add_x_forwarded_for: 包括客户端IP和中间经过的所有代理的IP
$http_x_forwarded_For: 只有客户端IP
log_format main '"$proxy_add_x_forwarded_for" - $remote_user [$time_local]
"$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $http_x_forwarded_For';
#查看日志如下:
[root@rs1 ~]# tail -n 3 /var/log/nginx/access.log
"172.25.254.10, 192.168.0.10" 192.168.0.10 - - [10/Jul/2024:16:15:00 +0800] "GET
/ HTTP/1.1"200 18 "-" "curl/7.29.0" "172.25.254.10"
[root@rs2 ~]# tail -n 3 /etc/httpd/logs/access_log
172.25.254.10 192.168.0.10 - - [11/Jul/2024:00:15:00 +0800] "GET / HTTP/1.1" 200
27 "-" "curl/7.29.0
3.4 ACL
基于源IP或子网调度访问
示例:
vim/etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl ctrl_ip src 172.25.254.1 172.25.254.20 192.168.0.0/24 -----符合条件的访问RS1
use_backend webcluster-host if ctrl_ip
default_backend default-host
backend webcluster-host
mode http
server web1 172.25.254.10:80 check inter 2 fall 2 rise 5
backend default-host
mode http
server web2 172.25.254.20:80 check inter 2 fall 2 rise 5
测试:
[root@werserver2 ~]# curl 172.25.254.100
webserver1 - 172.25.254.10
[root@haproxy ~]# curl www.test.com
webserver2 - 172.25.254.20
[root@haproxy ~]#
frontend webcluster
bind *:80
mode http
acl ctrl_ip src 172.25.254.1 172.25.254.20 192.168.0.0/24
http-request deny if ctrl_ip ------ 符合条件的拒绝访问
default_backend default-host
backend webcluster-host
mode http
server web1 172.25.254.10:80 check inter 2 fall 2 rise 5
backend default-host
mode http
server web2 172.25.254.20:80 check inter 2 fall 2 rise 5
测试:
[root@werserver2 ~]# curl 172.25.254.100
webserver1 - 172.25.254.10
[root@werserver2 ~]# curl 172.25.254.100
<html><body><h1>403 Forbidden</h1>
Request forbidden by administrative rules.
</body></html>
[root@werserver2 ~]#
[root@haproxy ~]# curl www.test.com ---- 默认走RS2,走的default
webserver2 - 172.25.254.20
基于浏览器的访问控制
示例:
vim/etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl badwebrowers hdr_sub(User-Agent) -i wget
http-request deny if badwebrowers
default_backend default-host
backend webcluster-host
mode http
server web1 172.25.254.10:80 check inter 2 fall 2 rise 5
backend default-host
mode http
server web2 172.25.254.20:80 check inter 2 fall 2 rise 5
基于文件后缀名实现动静分离
RS主机上:
[root@webserver1 ~]# dnf install php -y
[root@webserver1 ~]# systemctl restart nginx.service
[root@webserver1 ~]#
[root@webserver1 ~]# vim /usr/share/nginx/html/index.php
<?php
phpinfo();
?>
查看是否能访问到php
自定义haproxy的错误界面
两台web服务都给他挂掉
[root@werserver1 ~]# systemctl stop nginx.service
[root@werserver2 ~]# systemctl stop nginx.service
此时访问不到
重定向错误文件
3.5 haproxy的四层负载
测试
3.6 haproxy中https实现
haproxy
可以实现
https
的证书安全
,
从用户到
haproxy
为
https,
从
haproxy
到后端服务器用
http
通信
但基于性能考虑
,
生产中证书都是在后端服务器比如
nginx
上实现
#配置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 }
3.6.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
3.6.2 https
配置示例
haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webserver
bind *:80
redirect scheme https if !{ ssl_fc }
mode http
use_backend webcluster
frontend webserver-https
bind *:443 ssl crt /etc/haproxy/timinglee.org.pem
mode http
use_backend webcluster
backend webcluster
mode http
balance roundrobin
server web1 172.25.254.200:80 check inter 3s fall 3 rise 5
server web2 172.25.254.201:80 check inter 3s fall 3 rise 5
[root@客户端 ~]#curl -IkL http://172.25.254.100
HTTP/1.1 302 Found
content-length: 0
location: https://www.timinglee.org/
cache-control: no-cache
HTTP/1.1 200 OK
date: Sat, 04 Apr 2020 02:31:31 GMT
server: Apache/2.4.6 (CentOS) PHP/5.4.16
last-modified: Thu, 02 Apr 2020 01:44:13 GMT
etag: "a-5a244f01f8adc"
accept-ranges: bytes
content-length: 10
content-type: text/html; charset=UTF-8
[root@centos6 ~]#curl -Ik https://www.timinglee.org
HTTP/1.1 200 OK
date: Sat, 04 Apr 2020 02:31:50 GMT
server: Apache/2.4.6 (CentOS) PHP/5.4.16
last-modified: Thu, 02 Apr 2020 01:44:28 GMT
etag: "a-5a244f0fd5175"
accept-ranges: bytes
content-length: 10
content-type: text/html; charset=UTF-8