1、HAProxy 简介

负载均衡:Load Balance,简称LB,是一种服务或基于硬件设备等实现的高可用反向代理技术,负载均衡将特定的业务(web服务、网络流量等)分担给指定的一个或多个后端特定的服务器或设备,从而提高了公司业务的并发处理能力、保证了业务的高可用性、方便了业务后期的水平动态扩展

阿里云SLB介绍 :​​https://yq.aliyun.com/articles/1803​

1-1、为什么使用负载均衡
  • 增加业务并发访问及处理能力-->解决单服务器瓶颈问题
  • 节约公网IP地址-->降低IT支出成本
  • 隐藏内部服务器IP-->提高内部服务器安全性
  • Web服务器的动态水平扩展-->对用户无感知
  • 负载均衡配置简单-->固定格式的配置文件
  • 负载均衡功能丰富-->支持四层和七层,支持动态下线主机
  • 负载均衡性能较强-->并发数万甚至百万
1-2、负载均衡类型

四层:

LVS:Linux Virtual Server
Nginx:1.9版之后
HAProxy:High Availability Proxy

七层:

HAProxy
Nginx

硬件:

F5 https://f5.com/zh
Netscaler https://www.citrix.com.cn/products/citrix-adc/
Array https://www.arraynetworks.com.cn/
深信服 http://www.sangfor.com.cn/
北京灵州 http://www.lingzhou.com.cn/cpzx/llfzjh/
1-3、应用场景
四层:Redis、Mysql、RabbitMQ、Memcached等
七层:Nginx、Tomcat、Apache、PHP、图片、动静分离、API等

随着公司业务的发展,公司负载均衡服务既有四层的,又有七层的,通过LVS实现四层和Nginx实现七层的负载均衡对机器资源消耗比较大,并且管理复杂度提升,运维总监要求,目前需要对前端负载均衡服务进行一定的优化和复用,能否用一种服务同既能实现七层负载均衡,又能实现四层负载均衡,并且性能高效,配置管理容易,而且还是开源。

在企业生产环境中,每天会有很多的需求变更,比如增加服务器、新业务上线、url路由修改、域名配置等等,对于前端负载均衡设备来说,容易维护,复杂度低,是首选指标。在企业中,稳定压倒一切,与其搞得很复杂,经常出问题,不如做的简单和稳定。在企业中,90%以上的故障,来源于需求变更。可能是程序bug,也可能是人为故障,也可能是架构设计问题等。前端负载均衡设备为重中之重,在软件选型上一定充分考虑,能满足业务的前提下,尽可能降低复杂度,提高易维护性

企业版网站:​​https://www.haproxy.com​

社区版网站:​​http://www.haproxy.org/​

github:​​https://github.com/haproxy​

1-4、 HAProxy功能
TCP 和 HTTP反向代理
SSL/TSL服务器
可以针对HTTP请求添加cookie,进行路由后端服务器
可平衡负载至后端服务器,并支持持久连接
支持所有主服务器故障切换至备用服务器
支持专用端口实现监控服务
支持停止接受新连接请求,而不影响现有连接
可以在双向添加,修改或删除HTTP报文首部
响应报文压缩
支持基于pattern实现连接请求的访问控制
通过特定的URI为授权用户提供详细的状态信息
支持http反向代理
支持动态程序的反向代理
支持基于数据库的反向代理

不具备的功能:

正向代理--squid,nginx
缓存代理--varnish
web服务--nginx、tengine、apache、php、tomcat
UDP--目前不支持UDP协议
单机性能--相比LVS性能较差
2、HAProxy 安装

​https://www.haproxy.org/​

#ubuntu-APT安装
[root@haproxy ~]#apt-get install software-properties-common
[root@haproxy ~]#add-apt-repository ppa:vbernat/haproxy-2.6
[root@haproxy ~]#apt update
[root@haproxy ~]#apt-cache madison haproxy
#安装指定版本
[root@haproxy ~]#apt install haproxy=2.6.6-1ppa1~focal

#验证haproxy版本
[root@haproxy ~]#haproxy -v

=====================================
#centos安装
yum install haproxy -y
第三方安装包
官方没有提供rpm相关的包,可以通过第三方仓库的rpm包
从第三方网站下载rpm包:https://pkgs.org/download/haproxy
2-1、编译安装 HAProxy

编译安装HAProxy 2.6 LTS版本,更多源码包下载地址:​​http://www.haproxy.org/download/​

2-1-1、解决 lua 环境

HAProxy 支持基于lua实现功能扩展,lua是一种小巧的脚本语言,于1993年由巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组开发,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能

由于CentOS7 之前版本自带的lua版本比较低并不符合HAProxy要求的lua最低版本(5.3)的要求,因此需要编译安装较新版本的lua环境,然后才能编译安装HAProxy,所有建议用ubuntu
2-1-2、Ubuntu 基础环境
#安装基础命令及编译依赖环境
[root@ubuntu2004 ~]#apt -y install gcc make libssl-dev libpcre3 libpcre3-dev zlib1g-dev libreadline-dev libsystemd-dev
[root@ubuntu2004 src]#cd /usr/local/src
[root@ubuntu2004 src]#wget http://www.lua.org/ftp/lua-5.4.4.tar.gz

[root@ubuntu2004 src]#tar xf lua-5.4.4.tar.gz
[root@ubuntu2004 src]#ls
lua-5.4.4 lua-5.4.4.tar.gz
[root@ubuntu2004 src]#cd lua-5.4.4/
[root@ubuntu2004 lua-5.4.4]#make linux test
[root@ubuntu2004 lua-5.4.4]#./src/lua -v
Lua 5.4.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio
[root@ubuntu2004 ~]#tar xf haproxy-2.6.6.tar.gz
[root@ubuntu2004 ~]#cd haproxy-2.6.6/
#参考INSTALL文件进行编译安装
[root@ubuntu2004 haproxy-2.6.6]#make ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_LUA=1 LUA_INC=/usr/local/src/lua-5.4.4/src/ LUA_LIB=/usr/local/src/lua-5.4.4/src
[root@ubuntu2004 haproxy-2.6.6]#make install PREFIX=/apps/haproxy
[root@ubuntu2004 haproxy-2.6.6]#ln -s /apps/haproxy/sbin/haproxy /usr/sbin/

#验证HAProxy版本
[root@ubuntu2004 haproxy-2.6.6]#haproxy -v
[root@ubuntu2004 haproxy-2.6.6]#mkdir /etc/haproxy

#创建自定义的配置文件
[root@ubuntu2004 haproxy-2.6.6]#vim /etc/haproxy/haproxy.cfg
global
maxconn 100000
chroot /apps/haproxy
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
user haproxy
group haproxy
daemon
pidfile /var/lib/haproxy/haproxy.pid
log 127.0.0.1 local2 info

defaults
option http-keep-alive
option forwardfor
maxconn 100000
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms

listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth haadmin:123456

#listen web_port
# bind 10.0.0.102:80
# mode http
# log global
# server web1 127.0.0.1:8080 check inter 3000 fall 2 rise 5

#准备socket文件目录
[root@ubuntu2004 haproxy-2.6.6]#mkdir /var/lib/haproxy

#设置用户和目录权限
[root@ubuntu2004 haproxy-2.6.6]#groupadd -g 99 -r haproxy
[root@ubuntu2004 haproxy-2.6.6]#useradd -g haproxy -u 99 -r -s /sbin/nologin -d /var/lib/haproxy haproxy

#检查配置文件语法
[root@ubuntu2004 haproxy-2.6.6]#haproxy -c -f /etc/haproxy/haproxy.cfg
Configuration file is valid

#创建service文件
[root@ubuntu2004 haproxy-2.6.6]#vim /usr/lib/systemd/system/haproxy.service
[Unit]
Description=HAProxy Load Balancer
After=syslog.target network.target

[Service]
ExecStartPre=/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c -q
ExecStart=/usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /var/lib/haproxy/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target


[root@ubuntu2004 haproxy-2.6.6]#systemctl daemon-reload
[root@ubuntu2004 haproxy-2.6.6]#systemctl enable --now haproxy.service
[root@ubuntu2004 haproxy-2.6.6]#systemctl status haproxy.service

Haproxy_负载均衡

Haproxy_haproxy_02

2-2、基于 Docker 部署

Haproxy 官方镜像

https://hub.docker.com/_/haproxy/
[root@rocky8 ~]#mkdir /data/haproxy -p
[root@rocky8 ~]#cat > /data/haproxy/haproxy.cfg
global
maxconn 100000
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
uid 99
gid 99
daemon
pidfile /var/lib/haproxy/haproxy.pid
log 127.0.0.1 local3 info

defaults
option http-keep-alive
option forwardfor
maxconn 100000
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms

listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth admin:123456

[root@rocky8 ~]#docker run -d --name my-haproxy -v /data/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro -p 9999:9999 --sysctl net.ipv4.ip_unprivileged_port_start=0 haproxy:2.6.6-alpine3.16

Haproxy_lua_03

3、HAProxy 基础配置

HAProxy 的配置文件haproxy.cfg由两大部分组成,分别是global和proxies部分

global:全局配置段

进程及安全配置相关的参数
性能调整相关参数
Debug参数

proxies:代理配置段

defaults:为frontend, backend, listen提供默认配置
frontend:前端,相当于nginx中的server {}
backend:后端,相当于nginx中的upstream {}
listen:同时拥有前端和后端配置,配置简单,生产推荐使用
3-1、Global配置
3-1-1、Global 配置参数说明
chroot #锁定运行目录
deamon #以守护进程运行
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin process 1
#socket文件,并可以通过此文件管理
user, group, uid, gid #运行haproxy的用户身份
#nbproc n #开启的haproxy worker 进程数,默认进程数是一个, nbproc从HAProxy2.5开始不再支持
nbthread 1 #和多进程 nbproc配置互斥(版本有关,CentOS8的haproxy1.8无此问题),指定每个haproxy进程开启的线程数,默认为每个进程一个线程
#如果同时启用nbproc和nbthread 会出现以下日志的错误,无法启动服务
Apr 7 14:46:23 haproxy haproxy: [ALERT] 097/144623 (1454) : config : cannot enable multiple processes if multiple threads are configured. Please use either nbproc or nbthread but not both.
#cpu-map 1 0 #绑定haproxy worker 进程至指定CPU,将第1个worker进程绑定至0号CPU
#cpu-map 2 1 #绑定haproxy worker 进程至指定CPU,将第2个worker进程绑定至1号CPU
cpu-map auto:1/1-8 0-7 #haproxy2.4中启用nbthreads,在global配置中添加此选项,可以进行线程和CPU的绑定,nbproc选项2.5版本中将会删除,每个进程中1-8个线程分别绑定0-7号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、HAProxy日志配置

HAproxy本身不记录客户端的访问日志.此外为减少服务器负载,一般生产中HAProxy不记录日志.也可以配置HAProxy利用rsyslog服务记录日志到指定日志文件中

3-2-1、HAProxy配置
#在global配置项定义:
log 127.0.0.1 local{1-7} info #基于syslog记录日志到指定设备,级别有(err、warning、info、debug)

listen web_port
bind 127.0.0.1:80
mode http
log global #开启当前web_port的日志功能,默认不记录日志
server web1 127.0.0.1:8080 check inter 3000 fall 2 rise 5

# systemctl restart haproxy
3-2-2、Rsyslog配置
[root@ubuntu2004 ~]#vim /etc/rsyslog.conf
......
# provides UDP syslog reception
module(load="imudp")
input(type="imudp" port="514")
......

[root@ubuntu2004 ~]#vim /etc/rsyslog.d/50-default.conf
......
local2.info /var/log/haproxy.log
......
[root@ubuntu2004 ~]#systemctl restart rsyslog
[root@ubuntu2004 ~]#ss -nulp
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
UNCONN 0 0 0.0.0.0:514 0.0.0.0:* users:(("rsyslogd",pid=36898,fd=5))
......
#访问haproxy自动生成日志文件
3-2-3、启动本地和远程日志
[root@ubuntu2004 ~]#vim /etc/haproxy/haproxy.cfg
global
......
log 127.0.0.1 local2 info
log 10.0.0.18 local2 info
......
[root@ubuntu2004 ~]#systemctl restart haproxy.service
#本地日志设置如3-2-2

#远程日志
[root@rocky8 ~]#vim /etc/rsyslog.conf
......
# Provides UDP syslog reception
# for parameters see http://www.rsyslog.com/doc/imudp.html
module(load="imudp") # needs to be done just once
input(type="imudp" port="514")
......
local2.info /var/log/haproxy.log
......

[root@rocky8 ~]#systemctl restart rsyslog.service
#访问haproxy自动生成日志文件
[root@rocky8 ~]#tail /var/log/haproxy.log
Oct 24 20:54:15 10.0.0.101 haproxy[37246]: Connect from 10.0.0.1:60876 to 10.0.0.101:9999 (stats/HTTP)
Oct 24 20:54:15 10.0.0.101 haproxy[37246]: Connect from 10.0.0.1:60876 to 10.0.0.101:9999 (stats/HTTP)
3-3、Proxies 配置

官方文档:​​http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#4​

defaults [<name>]   #默认配置项,针对以下的frontend、backend和listen生效,可以多个name也可以没有name
frontend <name> #前端servername,类似于Nginx的一个虚拟主机 server和LVS服务集群。
backend <name> #后端服务器组,等于nginx的upstream和LVS中的RS服务器
listen <name> #将frontend和backend合并在一起配置,相对于frontend和backend配置更简洁,生产常用

注意:name字段只能使用大小写字母,数字,‘-’(dash),'_‘(underscore),'.' (dot)和 ':'(colon),并且严格区分大小写

3-3-1、Proxies配置-defaults
#defaults 配置参数
option redispatch #当server Id对应的服务器挂掉后,强制定向到其他健康的服务器,重新派发
option abortonclose #当服务器负载很高时,自动结束掉当前队列处理比较久的连接,针对业务情况选择开启
option http-keep-alive #开启与客户端的会话保持
option forwardfor #透传客户端真实IP至后端web服务器
mode http|tcp #设置默认工作类型,使用TCP服务器性能更好,减少压力
timeout http-keep-alive 120s #session 会话保持超时时间,此时间段内会转发到相同的后端服务器
timeout connect 120s #客户端请求从haproxy到后端server最长连接等待时间(TCP连接之前),默认单位ms
timeout server 600s #客户端请求从haproxy到后端服务端的请求处理超时时长(TCP连接之后),默认单位ms,如果超时,会出现502错误,此值建议设置较大些,防止出现502错误
timeout client 600s #设置haproxy与客户端的最长非活动时间,默认单位ms,建议和timeout server相同
timeout check 5s #对后端服务器的默认检测超时时间
default-server inter 1000 weight 3 #指定后端服务器的默认设置
3-3-2、Proxies配置-listen 简化配置

使用listen替换 frontend和backend的配置方式,可以简化设置,常用于TCP协议的应用

[root@ubuntu2004 ~]#vim /etc/haproxy/haproxy.cfg
listen web_port
bind 10.0.0.101:80
mode http
option forwardfor
log global
server web1 10.0.0.18:80 check inter 3000 fall 3 rise 5
server web2 10.0.0.28:80 check inter 3000 fall 3 rise 5
[root@ubuntu2004 ~]#haproxy -c -f /etc/haproxy/haproxy.cfg
[root@ubuntu2004 ~]#systemctl restart haproxy.service
3-3-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
frontend http_proxy    #监听http的多个IP的多个端口和sock文件
bind :80,:443,:8801-8810
bind 10.0.0.1:10080,10.0.0.1:10443
bind /var/run/ssl-frontend.sock user root mode 600 accept-proxy

frontend http_https_proxy #https监听
bind :80
bind :443 ssl crt /etc/haproxy/site.pem #公钥和私钥公共文件

frontend http_https_proxy_explicit #监听ipv6、ipv4和unix sock文件
bind ipv6@:80
bind ipv4@public_ssl:443 ssl crt /etc/haproxy/site.pem
bind unix@ssl-frontend.sock user root mode 600 accept-proxy

listen external_bind_app1 #监听file descriptor
bind "fd@${FD_APP1}"
3-3-4、Proxies配置-backend

定义一组后端服务器,backend服务器将被frontend进行调用。 注意: backend 的名称必须唯一,并且必须在listen或frontend中事先定义才可以使用,否则服务无法启动

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 #将后端服务器标记为不可用状态,即维护状态,除了持久模式,将不再接受连接,状态为深黄色,优雅下线,不再接受新用户的请求
maxconn <maxconn> #当前后端server的最大并发连接数,放在,放在server 指令后面
redir http://www.baidu.com #将请求临时(302)重定向至其它URL,只适用于http模式,放在server 指令后面

redirect 配置

#注意:此指令和redir功能相似,但不属于server指令后面,是独立存放在listen,frontend,backend语句块
redirect prefix http://www.baidu.com/ #将请求临时(302)重定向至其它URL,只适用于http模式
[root@ubuntu2004 ~]#vim /etc/haproxy/haproxy.cfg
frontend wang-test-http
bind 10.0.0.101:80
mode http
use_backend wang-test-nodes
backend wang-test-nodes
mode http
option forwardfor
server 10.0.0.18 10.0.0.18:80 check inter 3000 fall 3 rise 5
server 10.0.0.28 10.0.0.28:8008 check inter 3000 fall 3 rise 5

[root@ubuntu2004 ~]#systemctl restart haproxy.service
3-3-5、使用子配置文件保存配置

当业务众多时,将所有配置都放在一个配置文件中,会造成维护困难。可以考虑按业务分类,将配置信息拆分,放在不同的子配置文件中,从而达到方便维护的目的。

注意: 子配置文件的文件后缀必须为.cfg

#创建子配置目录
[root@ubuntu2004 ~]#mkdir /etc/haproxy/conf.d

#添加子配置目录到unit文件中
[root@ubuntu2004 ~]#vim /lib/systemd/system/haproxy.service

[Unit]
Description=HAProxy Load Balancer
After=syslog.target network.target

[Service]
#修改下面两行
ExecStartPre=/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d/ -c -q
ExecStart=/usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d/ -p /var/lib/haproxy/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target

#创建子配置文件,注意:必须为cfg后缀非.开头的配置文件
[root@ubuntu2004 ~]#vim /etc/haproxy/conf.d/ha_test.cfg

listen WEB_PORT
bind 10.0.0.101:80
mode http
balance roundrobin
server web1 10.0.0.18:80 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:8008 check inter 3000 fall 2 rise 5
4、HAProxy 调度算法

HAProxy通过固定参数 balance 指明对后端服务器的调度算法,该参数可以配置在listen或backend选项中。 HAProxy的调度算法分为静态和动态调度算法,但是有些算法可以根据参数在静态和动态算法中相互转换。

4-1、静态算法

静态算法:按照事先定义好的规则轮询进行调度,不关心后端服务器的当前负载、连接数和响应速度等,且无法实时动态修改权重(只能为0和1,不支持其它值)或者修改后不生效,如果需要修改只能靠重启HAProxy生效。

4-1-1 、Socat 工具

对服务器动态权重和其它状态可以利用 socat工具进行调整,Socat 是 Linux 下的一个多功能的网络工具,名字来由是Socket CAT,相当于netCAT的增强版.Socat 的主要特点就是在两个数据流之间建立双向通道,且支持众多协议和链接方式。如 IP、TCP、 UDP、IPv6、Socket文件等

[root@ubuntu2004 ~]#apt install -y socat
[root@ubuntu2004 ~]#echo "help" | socat stdio /var/lib/haproxy/haproxy.sock
[root@ubuntu2004 ~]#echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock #可以用于实现Zabbix监控
[root@ubuntu2004 ~]#echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock | awk '/CurrConns/{print $2}' #获取当前连接数
0
[root@ubuntu2004 ~]#echo "show servers state" | socat stdio /var/lib/haproxy/haproxy.sock

#修改weight
[root@ubuntu2004 ~]#echo "set weight WEB_PORT/web2 2" | socat stdio /var/lib/haproxy/haproxy.sock

[root@ubuntu2004 ~]#echo "get weight WEB_PORT/web2" | socat stdio /var/lib/haproxy/haproxy.sock
2 (initial 1)

#将后端服务器禁用
[root@ubuntu2004 ~]#echo "disable server WEB_PORT/web2" | socat stdio /var/lib/haproxy/haproxy.sock

#启用后端服务器
[root@ubuntu2004 ~]#echo "enable server WEB_PORT/web2" | socat stdio /var/lib/haproxy/haproxy.sock

#将后端服务器软下线,即weight设为0
[root@ubuntu2004 ~]#echo "set weight WEB_PORT/web2 0" | socat stdio /var/lib/haproxy/haproxy.sock
4-1-2、static-rr 算法

static-rr:基于权重的轮询调度,不支持运行时利用socat进行权重的动态调整(只支持0和1,不支持其它值)及后端服务器慢启动,其后端主机数量没有限制,相当于LVS中的 wrr

listen web_host
bind 10.0.0.101:80,:8801-8810,10.0.0.101:9001-9010
mode http
log global
balance static-rr
server web1 10.0.0.18:80 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:8080 weight 2 check inter 3000 fall 2 rise 5
4-2-3、first 算法

first:根据服务器在列表中的位置,自上而下进行调度,但是其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务,因此会忽略服务器的权重设置,此方式使用较少 不支持用socat进行动态修改权重,可以设置0和1,可以设置其它值但无效

listen web_host
bind 10.0.0.101:80,:8801-8810,10.0.0.101:9001-9010
mode http
log global
balance first
server web1 10.0.0.18:80 maxconn 2 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:8080 weight 1 check inter 3000 fall 2 rise 5
4-2、动态算法

动态算法:基于后端服务器状态进行调度适当调整,新请求将优先调度至当前负载较低的服务器,且权重可以在haproxy运行时动态调整无需重启。

4-2-1、roundrobin 算法

roundrobin:基于权重的轮询动态调度算法,支持权重的运行时调整,不同于lvs中的rr轮训模式,HAProxy中的roundrobin支持慢启动(新加的服务器会逐渐增加转发数),其每个后端backend中最多支持4095个real server,支持对real server权重动态调整,roundrobin为默认调度算法,此算法使用广泛

listen web_host
bind 10.0.0.101:80,:8801-8810,10.0.0.101:9001-9010
mode http
log global
balance roundrobin
server web1 10.0.0.18:80 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:80 weight 2 check inter 3000 fall 2 rise 5
4-2-2、leastconn 算法
listen web_host
bind 10.0.0.101:80,:8801-8810,10.0.0.101:9001-9010
mode http
log global
balance leastconn
server web1 10.0.0.18:80 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:80 weight 2 check inter 3000 fall 2 rise 5
4-2-3、random 算法

在1.9版本开始增加 random的负载平衡算法,其基于随机数作为一致性hash的key,随机负载平衡对于大型服务器场或经常添加或删除服务器非常有用,支持weight的动态调整,weight较大的主机有更大概率获取新请求

listen web_host
bind 10.0.0.101:80,:8801-8810,10.0.0.101:9001-9010
mode http
log global
balance random
server web1 10.0.0.18:80 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:80 weight 2 check inter 3000 fall 2 rise 5
4-3、其他算法

其它算法即可作为静态算法,又可以通过选项成为动态算法

4-3-1、source 算法

源地址hash,基于用户源地址hash并将请求转发到后端服务器,后续同一个源地址请求将被转发至同一个后端web服务器。此方式当后端服务器数据量发生变化时,会导致很多用户的请求转发至新的后端服务器,默认为静态方式,但是可以通过hash-type选项进行更改 这个算法一般是在不插入Cookie的TCP模式下使用,也可给不支持会话cookie的客户提供会话粘性,适用于需要session会话保持但不支持cookie和缓存的场景 源地址有两种转发客户端请求到后端服务器的服务器选取计算方式,分别是取模法和一致性hash

4-3-2、map-base 取模法

map-based:取模法,对source地址进行hash计算,再基于服务器总权重的取模,最终结果决定将此请求转发至对应的后端服务器。此方法是静态的,即不支持在线调整权重,不支持慢启动,可实现对后端服务器均衡调度。缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因总权重发生变化而导致调度结果整体改变,hash-type 指定的默认值为此算法

所谓取模运算,就是计算两个数相除之后的余数,10%7=3, 7%4=3
map-based算法:基于权重取模,hash(source_ip)%所有后端服务器相加的总权重
4-3-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环偏斜问题
listen web_host
bind 10.0.0.101:80,:8888-8899,10.0.0.101:9001-9010
mode tcp
log global
balance source
hash-type consistent
server web1 10.0.0.18:80 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:80 weight 1 check inter 3000 fall 2 rise 5
4-3-4、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>
#uri 取模法配置示例
[root@ubuntu2004 ~]#vim /etc/haproxy/conf.d/ha_test.cfg
listen web_host
bind 10.0.0.101:80,:8888-8899,10.0.0.101:9001-9010
mode http
log global
balance uri
server web1 10.0.0.18:80 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:80 weight 1 check inter 3000 fall 2 rise 5

[root@ubuntu2004 ~]#haproxy -c -f /etc/haproxy/conf.d/ha_test.cfg
[root@ubuntu2004 ~]#systemctl restart haproxy.service
#uri 一致性hash配置示例

listen web_host
bind 10.0.0.101:80,:8888-8899,10.0.0.101:9001-9010
mode http
log global
balance uri
hash-type consistent
server web1 10.0.0.18:80 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:80 weight 1 check inter 3000 fall 2 rise 5
4-3-5、url_param 算法

url_param对用户请求的url中的 params 部分中的一个参数key对应的value值作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个real server,如果无key,将按roundrobin算法

#假设:
url = http://www.wang.com/foo/bar/index.php?key=value
#则:
host = "www.wang.com"
url_param = "key=value"
# url_param取模法配置示例
listen web_host
bind 10.0.0.101:80,:8888-8899,10.0.0.101:9001-9010
mode http
log global
balance url_param userid
server web1 10.0.0.18:80 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:80 weight 1 check inter 3000 fall 2 rise 5
#url_param一致性hash配置示例
listen web_host
bind 10.0.0.101:80,:8888-8899,10.0.0.101:9001-9010
mode http
log global
balance url_param userid
hash-type consistent
server web1 10.0.0.18:80 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:80 weight 1 check inter 3000 fall 2 rise 5
4-3-6、hdr 算法

针对用户每个http头部(header)请求中的指定信息做hash,此处由 name 指定的http首部将会被取出并hash计算,然后由服务器总权重取模以后派发至某挑出的服务器,如果无有效值,则会使用默认的轮询调度

#hdr取模法配置示例,针对不同的浏览器进行调度
listen web_host
bind 10.0.0.101:80,:8888-8899,10.0.0.101:9001-9010
mode http
log global
balance hdr(User-Agent)
server web1 10.0.0.18:80 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:80 weight 1 check inter 3000 fall 2 rise 5
# 一致性hash配置示例
listen web_host
bind 10.0.0.101:80,:8888-8899,10.0.0.101:9001-9010
mode http
log global
balance hdr(User-Agent)
hash-type consistent
server web1 10.0.0.18:80 weight 1 check inter 3000 fall 2 rise 5
server web2 10.0.0.28:80 weight 1 check inter 3000 fall 2 rise 5
4-3-7、rdp-cookie 算法

rdp-cookie对远windows远程桌面的负载,使用cookie保持会话,默认是静态,也可以通过hash-type指定map-based和consistent,来定义使用取模法还是一致性hash。

listen RDP
bind 10.0.0.101:3389
balance rdp-cookie
mode tcp
server rdp0 10.0.0.88:3389 check fall 3 rise 5 inter 2000 weight 1
4-4、算法总结
#静态
static-rr--------->tcp/http
first------------->tcp/http

#动态
roundrobin-------->tcp/http
leastconn--------->tcp/http
random------------>tcp/http

#以下静态和动态取决于hash_type是否consistent
source------------>tcp/http
Uri--------------->http
url_param--------->http
hdr--------------->http
rdp-cookie-------->tcp

#各种算法使用场景
first #使用较少

static-rr #做了session共享的 web 集群
roundrobin
random

leastconn #数据库
source #基于客户端公网 IP 的会话保持
Uri--------------->http #缓存服务器,CDN服务商,蓝汛、百度、阿里云、腾讯
url_param--------->http #可以实现session保持
hdr #基于客户端请求报文头部做下一步处理
rdp-cookie #基于Windows主机,很少使用
5、HAProxy 高级功能
5-1、基于 Cookie 的会话保持

cookie value:为当前server指定cookie值,实现基于cookie的会话黏性,相对于基于 source 地址hash 调度算法对客户端的粒度更精准,但同时也加重了haproxy负载,目前此模式使用较少, 已经被session共享服务器代替 注意:不支持 tcp mode,使用 http mode

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的请求都发送到同一台后端服务器
listen web_port
bind 10.0.0.101:80,:8081-8090,10.0.0.101:9000-9090
balance roundrobin
mode http #不支持 tcp mode
log global
cookie webtest insert nocache indirect
server web01 10.0.0.18:80 check weight 1 inter 3000 fall 2 rise 3 cookie web1
server web02 10.0.0.28:8008 check weight 1 inter 3000 fall 2 rise 3 cookie web2
#curl测试
[root@rocky8 ~]#curl -b webtest=web1 10.0.0.101
10.0.0.18
[root@rocky8 ~]#curl -b webtest=web1 10.0.0.101
10.0.0.18
[root@rocky8 ~]#curl -b webtest=web1 10.0.0.101
10.0.0.18
[root@rocky8 ~]#curl -b webtest=web2 10.0.0.101
10.0.0.28
[root@rocky8 ~]#curl -b webtest=web2 10.0.0.101
10.0.0.28
[root@rocky8 ~]#curl -b webtest=web2 10.0.0.101
10.0.0.28
[root@rocky8 ~]#curl -vb webtest=web2 10.0.0.101
* Rebuilt URL to: 10.0.0.101/
* Trying 10.0.0.101...
* TCP_NODELAY set
* Connected to 10.0.0.101 (10.0.0.101) port 80 (#0)
> GET / HTTP/1.1
> Host: 10.0.0.101
> User-Agent: curl/7.61.1
> Accept: */*
> Cookie: webtest=web2
......
5-2、HAProxy 状态页

通过web界面,显示当前HAProxy的运行状态

5-2-1、状态页配置项
stats enable         #基于默认的参数启用stats page
stats hide-version #将状态页中haproxy版本隐藏
stats refresh <delay> #设定自动刷新时间间隔,默认不自动刷新,以秒为单位
stats uri <prefix> #自定义stats page uri,默认值:/haproxy?stats
stats realm <realm> #账户认证时的提示信息,示例:stats realm HAProxy\Statistics
stats auth <user>:<passwd> #认证时的账号和密码,可定义多个用户,每行指定一个用户.默认:no authentication
stats admin { if | unless } <cond> #启用stats page中的管理功能
listen ha_status
bind :666 #监听666端口,不要监听6666端口,谷歌内核的浏览器把6666端口禁止了
stats enable #启用stats状态页面
stats hide-version #隐藏版本信息
stats uri /ha_status #自定义状态页uri路径
stats realm "haproxy auth" #自定义认证提示信息,浏览器显示不出来
stats auth admin:123456 #认证用户名密码(可以定义多个用户)
stats auth root:123456 #认证用户名密码
stats admin if TRUE #启用管理功能

Haproxy_负载均衡_04

#浏览器打开状态页显示信息说明:
pid = 45177 (process #1, nbproc = 1, nbthread = 1) #pid为当前pid号,process为当前进程号,nbproc和nbthread为一共多少进程和每个进程多少个线程
uptime = 0d 0h00m16s #启动了多长时间
system limits: memmax = unlimited; ulimit-n = 200134 #系统资源限制:内存/最大打开文件数
maxsock = 200134; maxconn = 100000; maxpipes = 0 #最大socket连接数/单进程最大连接数/最大管道数maxpipes
current conns = 3; current pipes = 0/0; conn rate = 1/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 or backup DOWN for maintenance (MAINT) #active或者backup服务器人为下线的
active or backup SOFT STOPPED for maintenance #active或者backup被人为软下线(人为将weight改成0)
5-2-2、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:拒绝回复量


5-3、IP透传

web服务器中需要记录客户端的真实IP地址,用于做访问统计、安全防护、行为分析、区域排行等场景。

5-3-1、四层负载

在LVS 传统的四层负载设备中,把client发送的报文目标地址(原来是负载均衡设备的IP地址),根据均衡设备设置的选择web服务器的规则选择对应的web服务器IP地址,这样client就可以直接跟此服务器建立TCP连接并发送数据,而四层负载自身不参与建立连接 而和LVS不同,haproxy是伪四层负载均衡,因为haproxy 需要分别和前端客户端及后端服务器建立连接

5-3-2、七层代理

七层负载均衡服务器起了一个反向代理服务器的作用,服务器建立一次TCP连接要三次握手,而client要访问Web Server要先与七层负载设备进行三次握手后建立TCP连接,把要访问的报文信息发送给七层负载均衡;然后七层负载均衡再根据设置的均衡规则选择特定的 Web Server,然后通过三次握手与此台Web Server建立TCP连接,然后Web Server把需要的数据发送给七层负载均衡设备,负载均衡设备再把数据发送给client;所以,七层负载均衡设备起到了代理服务器的作用,七层代理需要和Client和后端服务器分别建立连接

5-3-3、四层IP透传
#haproxy:
[root@ubuntu2004 ~]#vim /etc/haproxy/conf.d/ha_test.cfg
listen web_port
bind 10.0.0.101:80
mode tcp #不支持http协议
balance roundrobin
server web1 10.0.0.18:80 send-proxy check inter 3000 fall 3 rise 3 ##添加send-proxy
server web2 10.0.0.28:8008 send-proxy check inter 3000 fall 3 rise 3

[root@ubuntu2004 ~]#haproxy -c -f /etc/haproxy/conf.d/ha_test.cfg
[root@ubuntu2004 ~]#systemctl restart haproxy.service


#nginx:
#在访问日志中通过变量$proxy_protocol_addr 记录透传过来的客户端IP
[root@rocky8 ~]#vim /etc/nginx/nginx.conf
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" "$proxy_protocol_addr"'
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
[root@rocky8 ~]#vim /etc/nginx/conf.d/dayu.org.conf
server {
listen 80 proxy_protocol;
[root@rocky8 ~]#nginx -s reload
5-3-4、七层IP透传

当haproxy工作在七层的时候,也可以透传客户端真实IP至后端服务器

在由haproxy发往后端主机的请求报文中添加“X-Forwarded-For"首部,其值为前端客户端的地址;用于向后端主发送真实的客户端IP

option forwardfor [ except <network> ] [ header <name> ] [ if-none ]

[ except <network> ]:请求报请来自此处指定的网络时不予添加此首部,如haproxy自身所在网络
[ header <name> ]:使用自定义的首部名称,而非“X-Forwarded-For",示例:X-client
[ if-none ] 如果没有首部才添加首部,如果有使用默认值
#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
#haproxy:
[root@ubuntu2004 ~]#vim /etc/haproxy/conf.d/ha_test.cfg
listen web_port_1
bind 10.0.0.101:80
mode http
option forwardfor
log global
balance random
server web1 10.0.0.18:80 check inter 3000 fall 3 rise 3
server web2 10.0.0.28:8008 check inter 3000 fall 3 rise 3

#nginx配置:
[root@rocky8 ~]#vim /etc/nginx/nginx.conf
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" "$proxy_add_x_forwarded_for"'
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
[root@rocky8 ~]#nginx -s reload
#tomcat 配置:conf目录下的server.xml
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%{X-Forwarded-For}i %h %l %u %t "%r" %s %b" />
5-4、报文修改

在http模式下,基于实际需求修改客户端的请求报文与响应报文,通过reqadd和reqdel在请求报文添加删除字段,通过rspadd与rspidel在响应报文中添加与删除字段。

#修改请求host首部,默认host首部会保留客户端原首部haproxy不会修改
http-request set-header host www.wangxiaochun.com

#添加向后端服务器发送的请求报文首部
http-request add-header <name> <fmt> [ { if | unless } <condition> ]
#示例:http-request add-header X-Haproxy-Current-Date %T

#删除向后端服务器发送的请求报文首部
http-request del-header <name> [ { if | unless } <condition> ]

#修改响应首部
http-response set-header server wangserver

#添加向客户端发送的响应报文首部
http-response add-header <name> <fmt> [ { if | unless } <condition> ]

#删除向客户端发送的响应报文首部
http-response del-header <name>
#示例:http-response del-header Server
5-5、自定义日志格式

log global 开启日志功能,默认只会在记录下面格式的日志

option httplog 可以采用 http 格式记录下来,并且可以使用相关指令将特定信息记录在haproxy的日志中但一般不建议开启,这会加重 HAProxy 负载

5-5-1、配置选项
log global                #开启记录日志,默认不开启
option httplog #开启记录httplog日志格式选项
capture cookie <name> len <length> #捕获请求和响应报文中的 cookie及值的长度,将之记录到日志
capture request header <name> len <length> #捕获请求报文中指定的首部内容和长度并记录日志
capture response header <name> len <length> #捕获响应报文中指定的内容和长度首部并记录日志

#示例:
log global
option httplog
capture request header Host len 256
capture request header User-Agent len 512
capture request header Referer len 15
capture request header X-Forwarded-For len 15

listen web_host
bind 10.0.0.101:80
mode http
log global
balance roundrobin
option httplog
capture request header User-Agent len 512
capture request header Host len 256
server web1 10.0.0.18:80 check inter 3000 fall 3 rise 3
server web2 10.0.0.28:8008 check inter 3000 fall 3 rise 3
5-6、压缩功能

对响应给客户端的报文进行压缩,以节省网络带宽,但是会占用部分CPU性能

建议在后端服务器开启压缩功能,而非在HAProxy上开启压缩

5-6-1、配置选项
compression algo <algorithm> ... #启用http协议中的压缩机制,常用算法有gzip,deflate

#压缩算法<algorithm>支持下面类型:
identity #debug调试使用的压缩方式
gzip #常用的压缩方式,与各浏览器兼容较好
deflate #有些浏览器不支持
raw-deflate #新式的压缩方式
compression type <mime type> ... #要压缩的文件类型
#示例:
compression algo gzip deflate
compression type text/html text/css text/plain
listen web_host
bind 10.0.0.101:80
mode http
log global
balance roundrobin
option httplog
compression algo gzip deflate
compression type text/plain text/html text/css text/xml text/javascript application/javascript
server web1 10.0.0.18:80 check inter 3000 fall 3 rise 3
server web2 10.0.0.28:8008 check inter 3000 fall 3 rise 3
[root@rocky8 ~]#curl -is --compressed 10.0.0.101/m.txt
HTTP/1.1 200 OK
server: nginx/1.14.1
date: Tue, 25 Oct 2022 03:48:31 GMT
content-type: text/plain
last-modified: Tue, 25 Oct 2022 03:48:00 GMT
etag: W/"63575c70-a"
accept-ranges: bytes
content-encoding: deflate
transfer-encoding: chunked
vary: Accept-Encoding

text.test
5-7、后端服务器健康性监测
5-7-1、三种状态监测方式
基于四层的传输端口做状态监测,此为默认方式
基于指定 URI 做状态监测,需要访问整个页面资源,占用更多带宽
基于指定 URI 的 request 请求头部内容做状态监测,占用较少带宽,建议使用此方式
5-7-2、基于应用层http协议进行健康性检测

基于应用层http协议,采有不同的监测方式,对后端real server进行状态监测 注意: 此方式会导致在后端服务器生成很多的HAProxy发起的访问日志

ption httpchk #启用七层健康性检测,对tcp 和 http 模式都支持,默认为:OPTIONS /HTTP/1.0 (nginx默认不支持,apache默认支持)
option httpchk <uri>
option httpchk <method> <uri>
option httpchk <method> <uri> <version>
#期望以上检查得到的响应码
http-check expect [!] <match> <pattern>
#示例:
http-check expect status 200
http-check expect ! rstatus ^5 #支持正则表达式
listen web_host
bind 10.0.0.101:80
mode http
balance roundrobin
#option httpchk GET /monitor/check.html #默认HTTP/1.0
#option httpchk GET /monitor/check.html HTTP/1.0
#option httpchk GET /monitor/check.html HTTP/1.1 #注意:HTTP/1.1强制要求必须有Host字段
option httpchk HEAD /monitor/check.html HTTP/1.1\r\nHost:\ 10.0.0.8 #使用HEAD减少网络流量
cookie SERVER-COOKIE insert indirect nocache
server web1 10.0.0.18:80 cookie web1 check inter 3000 fall 3 rise 5
server web2 10.0.0.28:8008 cookie web2 check inter 3000 fall 3 rise 5

#在所有后端服务建立检测页面
[root@backend ~]#mkdir /var/www/html/monitor/
[root@backend ~]#echo monitor > /var/www/html/monitor/check.html
#关闭一台Backend服务器
[root@backend1 ~]#systemctl stop httpd
5-8、ACL

访问控制列表(ACL,Access Control Lists)是一种基于包过滤的访问控制技术,它可以根据设定的条件对经过服务器传输的数据包进行过滤(条件匹配),即对接收到的报文进行匹配和过滤,基于请求报文头部中的源地址、源端口、目标地址、目标端口、请求方法、URL、文件后缀等信息内容进行匹配并执行进一步操作,比如允许其通过或丢弃。

5-8-1、定义ACL配置选项
acl  <aclname>  <criterion>  [flags]  [operator]  [<value>]
acl 名称 匹配规范 匹配模式 具体操作符 操作对象类型
5-8-2、ACL-Name
acl image_service hdr_dom(host) -i img.wang.com
#ACL名称,可以使用大字母A-Z、小写字母a-z、数字0-9、冒号:、点.、中横线和下划线,并且严格区分大小写,比如:my_acl和My_Acl就是两个完全不同的acl
5-8-3、ACL-criterion
#定义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中的domain name
hdr_dir([<name> [,<occ>]]):路径匹配,header的uri路径
hdr_len([<name> [,<occ>]]):长度匹配,header的长度匹配
hdr_reg([<name> [,<occ>]]):正则表达式匹配,自定义表达式(regex)模糊匹配
hdr_sub([<name> [,<occ>]]):子串匹配,header中的uri模糊匹配
#示例:
hdr(<string>) 用于测试请求头部首部指定内容
hdr_dom(host) 请求的host名称,如 www.wang.com,m.wang.com
hdr_beg(host) 请求的host开头,如 www. img. video. download. ftp.
hdr_end(host) 请求的host结尾,如 .com .net .cn

hdr(host) ==> www.wang.org:8080 #hdr(host)代表域名+端口
hdr_domain(host) ==> www.wang.org #domain(host)代表域名

#有些功能是类似的,比如以下几个都是匹配用户请求报文中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
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 wang

url : string
#提取请求中的整个URL。一个典型的应用是具有预取能力的缓存,以及需要从数据库聚合多个信息并将它们保存在缓存中的网页门户入口,推荐使用path
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

src #源IP
src_port #源PORT

dst #目标IP
dst_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

listen web_host
bind 10.0.0.101:80
mode http
log global
balance roundrobin
option httplog
acl bad_agent hdr_sub(User-Agent) -i curl wget
http-request deny if bad_agent
server web1 10.0.0.18:80 check inter 3000 fall 3 rise 3
server web2 10.0.0.28:8008 check inter 3000 fall 3 rise 3
5-8-4、ACL-flags

ACL匹配模式

-i 不区分大小写
-m 使用指定的pattern匹配方法
-n 不做DNS解析
-u 禁止acl重名,否则多个同名ACL匹配或关系
5-8-5、ACL-operator
#ACL 操作符
整数比较: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-8-6、ACL-value
#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.wang.com
exact #精确比较
substring #子串
suffix #后缀比较
prefix #前缀比较
subdir #路径, /wp-includes/js/jquery/jquery.js
domain #域名,www.wang.com
- regular expression #正则表达式
- hex block #16进制
5-8-7、多个ACL的组合调用方式
#多个ACL的逻辑处理
与:隐式(默认)使用
或:使用“or" 或 “||"表示
否定:使用 "!" 表示
#多个ACL调用方式:
#示例:
if valid_src valid_port #与关系,ACL中A和B都要满足为true,默认为与
if invalid_src || invalid_port #或,ACL中A或者B满足一个为true
if ! invalid_src #非,取反,不满足ACL才为true
#ACL示例:域名匹配
[root@ubuntu2004 ~]#vim /etc/haproxy/conf.d/ha_test.cfg
frontend org_http
bind 10.0.0.101:80
mode http
balance roundrobin

acl wang_domain hdr_dom(host) -i www.wang.org
acl li_domain hdr_dom(host) -i www.li.org

use_backend wang.org if wang_domain
use_backend li.org if li_domain
default_backend sorry_server

backend wang.org
mode http
server 10.0.0.18 10.0.0.18:80 check inter 3000 fall 3 rise 3

backend li.org
mode http
server 10.0.0.28 10.0.0.28:8008 check inter 3000 fall 3 rise 3

backend sorry_server
mode http
server sorry_server 10.0.0.101:666
~
#将指定的源地址调度至指定的web服务器组
[root@ubuntu2004 ~]#vim /etc/haproxy/conf.d/ha_test.cfg

frontend org_http
bind 10.0.0.101:80
mode http
balance roundrobin

acl wang_domain hdr_dom(host) -i www.wang.org
acl li_domain hdr_dom(host) -i www.li.org
acl ip_test src 10.0.0.1 #基于源地址的ACL,定义多个ACL的顺序无关

use_backend li.org if ip_test #放在前面的ACL规则优先生效,引用ACL时,严格的ACL应放在前面
use_backend wang.org if wang_domain
use_backend li.org if li_domain
default_backend sorry_server

backend wang.org
mode http
server 10.0.0.18 10.0.0.18:80 check inter 3000 fall 3 rise 3

backend li.org
mode http
server 10.0.0.28 10.0.0.28:8008 check inter 3000 fall 3 rise 3

backend sorry_server
mode http
server sorry_server 10.0.0.101:666
#拒绝指定IP或者IP范围访问
[root@ubuntu2004 ~]#vim /etc/haproxy/conf.d/ha_test.cfg

frontend org_http
bind 10.0.0.101:80
mode http
balance roundrobin

acl ip_deny src 10.0.0.1 192.168.100.0/24

http-request deny if ip_deny
default_backend sorry_server

backend wang.org
mode http
server 10.0.0.18 10.0.0.18:80 check inter 3000 fall 3 rise 3

backend li.org
mode http
server 10.0.0.28 10.0.0.28:8008 check inter 3000 fall 3 rise 3

backend sorry_server
mode http
server sorry_server 10.0.0.101:666
#匹配客户端浏览器,将不同类型的浏览器调动至不同的服务器组
#拒绝curl和wget的访问
[root@ubuntu2004 ~]#vim /etc/haproxy/conf.d/ha_test.cfg

frontend org_http
bind 10.0.0.101:80
mode http
balance roundrobin

acl user_agent hdr_sub(User-Agent) -i curl wget #基于浏览器的ACL
acl user_ab hdr_sub(User-Agent) -i ApacheBench

redirect prefix http://www.baidu.com if user_agent #302 临时重定向至新URL
http-request deny if user_ab #拒绝user_ab
default_backend sorry_server

backend wang.org
mode http
server 10.0.0.18 10.0.0.18:80 check inter 3000 fall 3 rise 3

backend li.org
mode http
server 10.0.0.28 10.0.0.28:8008 check inter 3000 fall 3 rise 3

backend sorry_server
mode http
server sorry_server 10.0.0.101:666


##模拟ApacheBench访问
[root@rocky8 ~]#curl -A ApacheBench 10.0.0.101
<html><body><h1>403 Forbidden</h1>
Request forbidden by administrative rules.
</body></html>
#基于文件后缀名实现动静分离
[root@ubuntu2004 ~]#vim /etc/haproxy/conf.d/ha_test.cfg

frontend org_http
bind 10.0.0.101:80
mode http
balance roundrobin

acl static path_end -i .jpg .jpeg .png .gif .css .js .html
acl php path_end -i .php

use_backend wang.org if static
use_backend li.org if php

default_backend sorry_server

backend wang.org
mode http
server 10.0.0.18 10.0.0.18:80 check inter 3000 fall 3 rise 3

backend li.org
mode http
server 10.0.0.28 10.0.0.28:8008 check inter 3000 fall 3 rise 3

backend sorry_server
mode http
server sorry_server 10.0.0.101:666
#匹配访问路径实现动静分离
[root@ubuntu2004 ~]#vim /etc/haproxy/conf.d/ha_test.cfg

frontend org_http
bind 10.0.0.101:80
mode http
balance roundrobin

acl static path_end -i /static /images /javascript ##基于路径的ACL
acl static path_end -i .jpg .jpeg .png .gif .css .js .html #ACL同名为或关系
acl php path_end -i .php

use_backend wang.org if static
use_backend li.org if php

default_backend sorry_server

backend wang.org
mode http
server 10.0.0.18 10.0.0.18:80 check inter 3000 fall 3 rise 3

backend li.org
mode http
server 10.0.0.28 10.0.0.28:8008 check inter 3000 fall 3 rise 3

backend sorry_server
mode http
server sorry_server 10.0.0.101:666
~
5-8-8、使用预定义ACL

ACL name

Equivalent to

Usage

FALSE

always_false

never match

HTTP

req_proto_http

match if protocol is valid HTTP

HTTP_1.0

req_ver 1.0

match HTTP version 1.0

HTTP_1.1

req_ver 1.1

match HTTP version 1.1

HTTP_CONTENT

hdr_val(content-length) gt 0

match an existing content-length

HTTP_URL_ABS

url_reg [/:]*://

match absolute URL with scheme

HTTP_URL_SLASH

url_beg /

match URL beginning with "/"

HTTP_URL_STAR

url *

match URL equal to "*"

LOCALHOST

src 127.0.0.1/8

match connection from local host

METH_CONNECT

method CONNECT

match HTTP CONNECT method

METH_DELETE

method DELETE

match HTTP DELETE method

METH_GET

method GET HEAD

match HTTP GET or HEAD method

METH_HEAD

method HEAD

match HTTP HEAD method

METH_OPTIONS

method OPTIONS

match HTTP OPTIONS method

METH_POST

method POST

match HTTP POST method

METH_PUT

method PUT

match HTTP PUT method

METH_TRACE

method TRACE

match HTTP TRACE method

RDP_COOKIE

req_rdp_cookie_cnt gt 0

match presence of an RDP cookie

REQ_CONTENT

req_len gt 0

match data in the request buffer

TRUE

always_true

always match

WAIT_END

wait_end

wait for end of content analysis

5-9、自定义 HAProxy 错误界面

对指定的报错进行重定向,进行优雅的显示错误页面

使用errorfile和errorloc指令的两种方法,可以实现自定义各种错误页面

5-9-1、基于自定义的错误页面文件
#自定义错误页
errorfile <code> <file>
<code> #HTTP status code.支持200, 400, 403, 405, 408, 425, 429, 500, 502,503,504
<file> #包含完整HTTP响应头的错误页文件的绝对路径。 建议后缀为".http",以和一般的html文件相区分

#示例:
errorfile 400 /etc/haproxy/errorfiles/400badreq.http
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
errorfile 503 /etc/haproxy/errorfiles/503sorry.http
defaults
#option forwardfor
#no option http-use-htx 支持html文件,此设置和版本有关,2.1不支持
#......
#加下面行

errorfile 500 /usr/local/haproxy/html/500.http
errorfile 502 /usr/local/haproxy/html/502.http
errorfile 503 /usr/local/haproxy/html/503.http
[root@ubuntu2004 ~]#vim /etc/haproxy/haproxy.cfg
defaults
......
errorfile 503 /data/haproxy/503.http
......

[root@ubuntu2004 ~]#vim /data/haproxy/503.http

HTTP/1.1 503 Service Unavailable
Content-Type:text/html;charset=utf-8
#注意此处要有空行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>报错页面</title>
</head>
<body>
<center><h1>网站维护中......请稍候再试</h1></center>
<center><h2>联系电话:400-123-4567</h2></center>
<center><h3>503 Service Unavailable</h3></center>
</body>
[root@ubuntu2004 ~]#systemctl restart haproxy.service

Haproxy_ubuntu_05

5-10、HAProxy 四层负载

针对除HTTP以外的TCP协议应用服务访问的应用场景

MySQL
Redis
Memcached
RabbitMQ

注意:如果使用frontend和backend,一定在 frontend 和 backend 段中都指定mode tcp

listen redis-port
bind 10.0.0.7:6379
mode tcp
balance leastconn
server server1 10.0.0.17:6379 check
server server2 10.0.0.27:6379 check backup
#对 MySQL 服务实现四层负载
[root@ubuntu2004 ~]#vim /etc/haproxy/ha_mysql.cfg

listen wang_mysql
bind 10.0.0.101:3306
mode tcp
balance leastconn
server mysql1 10.0.0.18:3306 check
server mysql2 10.0.0.28:3306 check #如果不写端口号,可以转发,但无法check状态

#或者使用frontend和backend实现

frontend mysql
bind :3306
mode tcp #必须指定tcp模式
default_backend mysqlsrvs
backend mysqlsrvs
mode tcp #必须指定tcp模式
balance leastconn
server mysql1 10.0.0.18:3306
server mysql2 10.0.0.28:3306
[root@rocky8 ~]#yum install -y mariadb-server
[root@rocky8 ~]#systemctl start mariadb.service
[root@rocky8 ~]#mysql -e "grant all on *.* to test@'10.0.0.%' identified by '123456'"

[root@rocky8 ~]#vim /etc/my.cnf
[mysqld]
server-id=18 #在另一台主机为28

[root@rocky8 ~]#systemctl restart mariadb.service

[root@rocky8 ~]#mysql -utest -p123456 -h10.0.0.28 -e "show variables like 'hostname'"
+---------------+---------------+
| Variable_name | Value |
+---------------+---------------+
| hostname | rocky8.li.org |
+---------------+---------------+
[root@rocky8 ~]#mysql -utest -p123456 -h10.0.0.18 -e "show variables like 'hostname'"
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| hostname | rocky8.wang.org |
+---------------+-----------------+

[root@rocky8 ~]#mysql -utest -p123456 -h10.0.0.101 -e 'select @@server_id'
+-------------+
| @@server_id |
+-------------+
| 18 |
+-------------+
[root@rocky8 ~]#mysql -utest -p123456 -h10.0.0.101 -e 'select @@server_id'
+-------------+
| @@server_id |
+-------------+
| 28 |
+-------------+
5-11、HAProxy Https 实现

haproxy支持https,基于性能考虑,证书是在后端服务器比如nginx上实现,即用户到haproxy利用tcp模式再到后端服务器

# 基于tcp 模式实现(不建议使用,使用此方法,后端服务器都需要做https)
[root@ubuntu2004 ~]#vim /etc/haproxy/conf.d/ha_test.cfg

listen org_http
bind 10.0.0.101:80
redirect scheme https if !{ ssl_fc }
mode http
balance roundrobin
server 10.0.0.18 10.0.0.18:80 check inter 3000 fall 3 rise 3
server 10.0.0.28 10.0.0.28:8008 check inter 3000 fall 3 rise 3
listen org_https
bind 10.0.0.101:443
mode tcp
log global
server 10.0.0.18 10.0.0.18:443 check inter 3000 fall 3 rise 3
server 10.0.0.28 10.0.0.28:443 check inter 3000 fall 3 rise 3

Haproxy 可以实现 Https 的证书安全,即从用户到haproxy为https,从haproxy到后端服务器用http通信

#配置HAProxy支持https协议,支持ssl会话;
bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE

#指令 crt 后证书文件为PEM格式,需要同时包含证书和所有私钥
cat demo.key demo.crt > demo.pem

#把80端口的请求利用302重向定443
bind *:80
redirect scheme https if !{ ssl_fc }

#向后端传递用户请求的协议和端口(frontend或backend)
http_request set-header X-Forwarded-Port %[dst_port]
http_request add-header X-Forwared-Proto https if { ssl_fc }
#证书制作
[root@ubuntu2004 ~]#mkdir /etc/haproxy/certs
[root@ubuntu2004 ~]#cd /etc/haproxy/certs
[root@ubuntu2004 certs]#openssl genrsa -out www.wang.org.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
.......................+++++
.+++++
e is 65537 (0x010001)
[root@ubuntu2004 certs]#openssl req -x509 -newkey rsa:2048 -subj "/CN=www.wang.org" -keyout www.wang.org.key -nodes -days 3650 -out www.wang.org.crt
Generating a RSA private key
........................+++++
......................................+++++
writing new private key to 'www.wang.org.key'
-----
[root@ubuntu2004 certs]#cat www.wang.org.key www.wang.org.crt > www.wang.org.pem
# 配置Https
[root@ubuntu2004 certs]#vim /etc/haproxy/conf.d/ha_test.cfg

frontend http_80
bind 10.0.0.101:80
bind 10.0.0.101:443 ssl crt /etc/haproxy/certs/www.wang.org.pem
redirect scheme https if !{ ssl_fc }
http-request set-header X-forwarded-Port %[dst_port]
http-request add-header X-forwarded-proto https if { ssl_fc }

mode http
balance roundrobin
log global
option httplog
use_backend servers

backend servers
mode http
server web01 10.0.0.18:80 check inter 3000 fall 3 rise 3
server web02 10.0.0.28:8008 check inter 3000 fall 3 rise 3