web集群-负载均衡集群-HAproxy

简介

HAProxy是使用C语言开发的一个开源软件,是一款具备高并发(一万以上)、高性能的TCP和HTTP负载均衡器,支持基于cookie的持久性,自动故障切换,支持正则表达式及web状态统计。
官方站点

功能

支持功能

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

不支持的功能

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

体系结构

web集群-负载均衡集群-HAproxy

编译安装

软件包 版本
HAProxy haproxy-2.2.9 社区版
LUA lua-5.4.0

HAProxy源码包下载地址http://www.haproxy.org/download/

HAproxy依赖的Lua环境

HAProxy 支持基于lua实现功能扩展,lua是一种脚本语言,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua 官网www.lua.org
Lua 应用场景

游戏开发
独立应用脚本
Web 应用脚本
扩展和数据库插件,如MySQL Proxy
安全系统,如入侵检测系统

Centos 基础环境
参考链接http://www.lua.org/start.htm
CentOS7 自带的lua版本比较低并不符合HAProxy要求的lua最低版本(5.3)的要求,因此需要编译安装较新版本的lua环境,然后才能编译安装HAProxy,

Lua编译安装

1、安装编译环境与lua
[root@node1 ~]# yum install gcc readline-devel -y
[root@node1 ~]# wget -c http://www.lua.org/ftp/lua-5.4.0.tar.gz

2、进行lua编译
[root@node1 ~]# cd /usr/local/src/lua-5.4.0/
[root@node1 lua-5.4.0]# make linux test

3、查看lua版本
[root@node1 lua-5.4.0]# src/lua -v
Lua 5.4.0  Copyright (C) 1994-2020 Lua.org, PUC-Rio

HAproxy编译安装

1、HAProxy 2.0以上版本编译参数:本文使用的是社区版2.2.9 
[root@node1 ~]# yum -y install gcc openssl-devel pcre-devel systemd-devel
[root@node1 ~]# wget -c https://www.haproxy.org/download/2.2/src/haproxy-2.2.9.tar.gz
[root@node1 ~]# tar xf haproxy-2.2.9.tar.gz  -C /usr/local/src/

2、安装可以参考/usr/local/src/haproxy-2.2.9/INSTALL文件,文件中要求make>=3.80版本,gcc>=3.4版本
查看make与gcc版本
[root@node1 haproxy-2.2.9]# rpm -q  make 
make-3.82-24.el7.x86_64
[root@node1 haproxy-2.2.9]# rpm -q gcc
gcc-4.8.5-44.el7.x86_64

3、参考INSTALL文件进行编译安装
[root@node1 haproxy-2.2.9]#  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.0/src/ LUA_LIB=/usr/local/src/lua-5.4.0/src/
[root@node1 haproxy-2.2.9]# make install PREFIX=/usr/local/src/haproxy

4、将命令目录连接到/usr/sbin/目录下,可以直接使用haproxy命令
[root@node1 haproxy-2.2.9]# ln -sv /usr/local/src/haproxy/sbin/haproxy /usr/sbin/
"/usr/sbin/haproxy" -> "/usr/local/src/haproxy/sbin/haproxy"

5、查看haproxy版本
[root@node1 haproxy-2.2.9]# haproxy -v
HA-Proxy version 2.2.9-a947cc2 2021/02/06 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2025.
Known bugs: http://www.haproxy.org/bugs/bugs-2.2.9.html
Running on: Linux 3.10.0-1062.el7.x86_64 #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64


haproxy -V 	  查看参数
haproxy -vv   可查看编译中的选项
haproxy -v	  

HAProxy启动脚本

[root@node1 ~]# 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 
 
 [Install] 
 WantedBy=multi-user.target

HAProxy配置文件

global    #全局配置参数
        maxconn 100000          #最大连接数
        chroot /usr/local/src/haproxy   #haproxy连接目录
        stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin  #套接字
        #uid 99 
        #gid 99 
        user haproxy  #用户
        group haproxy #组
        daemon 		#守护进程的方式
        #nbproc 1 	
        #cpu-map 1 0 
        #cpu-map 2 1 
        #cpu-map 3 2 
        #cpu-map 4 3 
        pidfile /var/lib/haproxy/haproxy.pid #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  #绑定本地所有IP地址的9999端口
        stats enable	
        log global     #全局日志记录
        stats uri /haproxy-status
        stats auth haadmin:123456  #认证:用户名:密码

[root@node1 ~]# mkdir /var/lib/haproxy
[root@node1 ~]# useradd -r -s /sbin/nologin -d /var/lib/haproxy haproxy
[root@node1 ~]# systemctl start haproxy

查看haproxy的状态页面

浏览器访问: http://192.168.16.11:9999/haproxy-status
登录用户名密码访问,用户名密码在配置文件中 listen stats字段中已设置
web集群-负载均衡集群-HAproxy
HAProxy 的配置文件haproxy.cfg由两大部分组成,分别是globalproxies部分

global:全局配置段

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

官方文档 global配置说明http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#3

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 work 进程数,默认进程数是一个 
#nbthread 1 				#指定每个haproxy进程开启的线程数,默认为每个进程一个线程,和nbproc互斥(版本有关) 

如果同时启用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 进程至指定CPU,将第一个work进程绑定至0号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、多进程和线程配置

1、编辑配置文件中的global字段
[root@node1 ~]# vim /etc/haproxy/haproxy.cfg 
 global
        maxconn 100000
        chroot /usr/local/src/haproxy
        stats socket /var/lib/haproxy/haproxy.sock1 mode 600 level admin process 1   #守护进程1
        stats socket /var/lib/haproxy/haproxy.sock2 mode 600 level admin process 2   #守护进程2
        #uid 99 
        #gid 99 
        user haproxy
        group haproxy
        daemon
        nbproc 2   			#开启的haproxy work 进程数为 2
        #cpu-map 1 0 
        #cpu-map 2 1 
        #cpu-map 3 2 
        #cpu-map 4 3 
        pidfile /var/lib/haproxy/haproxy.pid
        log 127.0.0.1 local2 info

2、重启服务
[root@node1 ~]# systemctl restart haproxy.servic

3、HaProxy日志配置

#在global配置项定义: 
global
	log 127.0.0.1 local2 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

[root@node1 ~]# vim /etc/rsyslog.conf 
$ModLoad imudp
$UDPServerRun 514
# Save boot messages also to haproxy.log
local2.*                                                /var/log/haproxy.log

重启日志服务
[root@node1 ~]# systemctl restart rsyslog.service 

proxies:代理配置段

defaults:为frontend, backend, listen提供默认配置
frontend:前端,相当于nginx中的server {} 
backend:后端,相当于nginx中的upstream {} 
listen:同时拥有前端和后端配置

官方文档proxies配置说明http://cbonte.github.io/haproxy-dconv/2.2/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),并且严格区分大小写

1、 Proxies配置-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 	#指定后端服务器的默认设置

2、Proxies配置-frontend

配置参数:
bind: #指定HAProxy的监听地址,可以是IPV4或IPV6,可以同时监听多个IP或端口,可同时用于listen字段中 

#格式: 
bind [<address>]:<port_range> [, ...] [param*] 

注意:如果需要绑定在非本机的IP,需要开启内核参数:net.ipv4.ip_nonlocal_bind=1

3、Proxies配置-backend

mode http|tcp 				#指定负载协议类型,和对应的frontend必须一致 
option 						#配置选项 
server						#定义后端real server

注意:option后面加 httpchk,smtpchk,mysql-check,pgsql-check,ssl-hello-chk方法,可用于实现更多应用层检测功能。

option 配选项说明:
check 						对指定real进行健康状态检查,如果不加此设置,默认不开启检查 
		addr <IP> 			可指定的健康状态监测IP,可以是专门的数据网段,减少业务网络的流量 
		port <num> 			指定的健康状态监测端口 
		inter <num> 		健康状态检查间隔时间,默认2000 ms 
		fall <num> 			后端服务器从线上转为线下的检查的连续失效次数,默认为3 
		rise <num>			后端服务器从下线恢复上线的检查的连续有效次数,默认为2 
weight <weight> 			默认为1,最大值为256,0表示不参与负载均衡,但仍接受持久连接 
backup 						将后端服务器标记为备份状态,只在所有非备份主机down机时提供服务,类似 Sorry Server 
disabled 					将后端服务器标记为不可用状态,即维护状态,除了持久模式,将不再接受连接 
redirect prefix http://www.baidu.com/	 将请求临时(302)重定向至其它URL,只适用于 http模式 
redir http://www.baidu.com 				 将请求临时(302)重定向至其它URL,只适用于 http模式 
maxconn <maxconn> 						 当前后端server的最大并发连接数 
backlog <backlog> 						 当前端服务器的连接数达到上限后的后援队列长度,注意:不支持backend

负载均衡配置

主机名及IP地址 角色
node1:192.168.16.11 HAproxy
node2:192.168.16.12 服务节点1
node3:192.168.16.13 服务节点2
node4:192.168.16.14 测试端
内核版本 3.10.0-1062.el7.x86_64
发行版本 CentOS Linux release 7.7.1908 (Core)

基础环境:各服务器关闭防火墙

[root@node1 ~]# systemctl stop firewalld.service 
[root@node2 ~]# systemctl stop firewalld.service 
[root@node3 ~]# systemctl stop firewalld.service 

基于frontend+backend配置实例

1、后端节点配置服务:node2,node3

[root@node2 ~]# yum install httpd -y
[root@node2 ~]# echo "this is a test1 " > /var/www/html/index.html
[root@node2 ~]# systemctl start httpd
[root@node3 ~]# yum install httpd -y
[root@node3 ~]#  echo "this is a test2 " > /var/www/html/index.html
[root@node3 ~]# systemctl start httpd

2、haproxy节点配置:node1

1、编辑配置文件
[root@node1 ~]# vim /etc/haproxy/haproxy.cfg 
 global
        maxconn 100000
        chroot /usr/local/src/haproxy
        stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin 
        #stats socket /var/lib/haproxy/haproxy.sock2 mode 600 level admin process 2
        #uid 99 
        #gid 99 
        user haproxy
        group haproxy
        daemon
        #nbproc 2
        #cpu-map 1 0 
        #cpu-map 2 1 
        #cpu-map 3 2 
        #cpu-map 4 3 
        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

 frontend webserver
        mode tcp
        bind 192.168.16.11:80
        use_backend webpool1   

 backend webpool1
        server web1 192.168.16.12:80 check
        server web2 192.168.16.13:80 check

开启内核参数
[root@node1 ~]# vim /etc/sysctl.conf 
net.ipv4.ip_nonlocal_bind = 1

立即生效
[root@node1 ~]# sysctl -p  
net.ipv4.ip_nonlocal_bind = 1

重启服务
[root@node1 ~]# systemctl restart rsyslog.service 

3、测试:node4

[root@node4 ~]# for ((i=1;i<=10;i++)); do  curl 192.168.16.11; done
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 

基于listen配置实例

1、haproxy节点配置:node1

1、修改配置文件,加入listen配置项
 listen web_port
        mode tcp
        bind :880
        server web1 192.168.16.12:80 check
        server web2 192.168.16.13:80 check

2、重启服务
[root@node1 ~]# systemctl restart  haproxy.service 

2、测试:node4

[root@node4 ~]# for ((i=1;i<=10;i++)); do  curl 192.168.16.11:880; done
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 

基于子配置文件保存配置实例

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

haproxy节点配置:node1

1、创建子配置文件的目录
[root@node1 ~]# mkdir /etc/haproxy/conf.d
2、编辑子配置文件
[root@node1 ~]# vim /etc/haproxy/conf.d/web01.cfg
 listen web01
        mode tcp
        bind :8880
        server web1 192.168.16.12:80 check
        server web2 192.168.16.13:80 check                                          

3、将子配置文件目录加入到服务启动项中,编辑启动配置文件
[root@node1 ~]# 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 -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

[Install]
WantedBy=multi-user.target
                             
4、将服务重新加载并启动
[root@node1 ~]# systemctl daemon-reload 
[root@node1 ~]# systemctl restart haproxy.service 

测试:node4

[root@node4 ~]# for ((i=1;i<=10;i++)); do  curl 192.168.16.11:8880; done
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 

HAproxy调度算法

HAProxy通过固定参数 balance 指明对后端服务器的调度算法,该参数可以配置在listen或backend选项中。
官方文档http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#4-balance

1、静态算法

按照事先定义好的规则轮询公平调度,不关心后端服务器的当前负载、链接数和响应速度等,且无法实时修改权重,只能靠重启HAProxy生效,或者使用socat工具

socat工具

参考文件http://www.dest-unreach.org/socat/doc/socat.html
对服务器动态权重和其它状态的调整,特点就是在两个数据流之间建立通道,且支持众多协议和链接方式。

1、安装socat工具
[root@node1 ~]# yum install socat -y

2、根据配置文件查看服务器的速率
[root@node1 ~]# echo "show servers state" | socat stdio /var/lib/haproxy/haproxy.sock
1
# be_id be_name srv_id srv_name srv_addr srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_result srv_check_health srv_check_state srv_agent_state bk_f_forced_id srv_f_forced_id srv_fqdn srv_port srvrecord
4 webpool1 1 web1 192.168.16.12 2 0 1 1 14151 6 3 4 6 0 0 0 - 80 -
4 webpool1 2 web2 192.168.16.13 2 0 1 1 14151 6 3 4 6 0 0 0 - 80 -
5 web_port 1 web1 192.168.16.12 2 0 1 1 14151 6 3 4 6 0 0 0 - 80 -
5 web_port 2 web2 192.168.16.13 2 0 1 1 14151 6 3 4 6 0 0 0 - 80 -
6 web01 1 web1 192.168.16.12 2 0 1 1 14151 6 3 4 6 0 0 0 - 80 -
6 web01 2 web2 192.168.16.13 2 0 1 1 14151 6 3 4 6 0 0 0 - 80 -

3、获取权值
[root@node1 ~]#  echo "get weight web01/web1" | socat stdio /var/lib/haproxy/haproxy.sock
1 (initial 

4、修改weight,针对单进程有效
[root@node1 ~]# echo "set weight web01/web1 3" | socat stdio /var/lib/haproxy/haproxy.sock

5、若后端服务器需要处理,可将后端服务器禁用,针对单线程
[root@node1 ~]#  echo "disable server web01/web1" | socat stdio /var/lib/haproxy/haproxy.sock

6、将后端服务器weight设置为0,不参与负载均衡
[root@node1 ~]#  echo "get weight web01/web1 0" | socat stdio /var/lib/haproxy/haproxy.sock

7、开启后端禁用的服务器,针对单线程
[root@node1 ~]#  echo "enable server web01/web1" | socat stdio /var/lib/haproxy/haproxy.sock

8、将后端服务器禁用,针对多进程 
首先将配置文件中多线程的规律性找出,将一个不同处设置为一个变量
[root@centos7 ~]# vim /etc/haproxy/haproxy.cfg 
...... 
stats socket /var/lib/haproxy/haproxy.sock1 mode 600 level admin process 1 
stats socket /var/lib/haproxy/haproxy.sock2 mode 600 level admin process 2 
stats socket /var/lib/haproxy/haproxy.sock3 mode 600 level admin process 3 
stats socket /var/lib/haproxy/haproxy.sock4 mode 600 level admin process 4 
nbproc 4
.....

可以逐个进行单线程禁用,也可使用for循环语句及变量进行多线程禁用。
[root@node1 ~]# for ((i=1;i<=4;i++))
> do
> echo "disable server web01/webi" | socat stdio /var/lib/haproxy/haproxyi.socki
> done

静态算法的weight只能更改为0或1,否则会有以下提示信息:
Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.

static-rr(加权轮询)

基于权重的轮询调度,不支持权重的运行时利用socat进行动态调整及后端服务器慢启动,其后端主机数量没有限制,相当于LVS中的 wrr

编辑配置文件
[root@node1 ~]# vim /etc/haproxy/conf.d/web01.cfg 
 listen web01
        mode tcp
        bind :8880
        balance static-rr
        server web1 192.168.16.12:80 weight 1 check
        server web2 192.168.16.13:80 weight 2 check

重启服务
[root@node1 ~]# systemctl restart haproxy.service 

测试:静态算法的weight只能更改为0或1
[root@node1 ~]# echo "set weight web_port/web1 3" | socat stdio /var/lib/haproxy/haproxy.sock
Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.

测试:
[root@node1 ~]# echo "get weight web01/web1" | socat stdio /var/lib/haproxy/haproxy.sock
1 (initial 1)
[root@node1 ~]# echo "get weight web01/web2" | socat stdio /var/lib/haproxy/haproxy.sock
2 (initial 2)
[root@node4 ~]# for ((i=1;i<=10;i++)); do  curl 192.168.16.11:8880; done
this is a test1 
this is a test2 
this is a test2 
this is a test1 
this is a test2 
this is a test2 
this is a test1 
this is a test2 
this is a test2 
this is a test1

first

根据服务器在列表中的位置,自上而下进行调度,但是其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务,因此会忽略服务器的权重设置,此方式使用较少

编辑配置文件
[root@node1 ~]# vim /etc/haproxy/conf.d/web01.cfg 
 listen web01
        mode tcp
        bind :8880
        balance first
        server web1 192.168.16.12:80 check
        server web2 192.168.16.13:80 check
 
 重启服务
[root@node1 ~]# systemctl restart haproxy.service 

测试:
[root@node4 ~]# for ((i=1;i<=10;i++)); do  curl 192.168.16.11:8880; done
this is a test1 
this is a test1 
this is a test1 
this is a test1 
this is a test1 
this is a test1 
this is a test1 
this is a test1 
this is a test1 
this is a test1 

2、动态算法

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

roundrobin(轮询算法)HAproxy默认调度算法

基于权重的轮询动态调度算法
支持权重的运行时调整
支持慢启动(新加的服务器会逐渐增加转发数)
backend中最多支持4095个real server
支持对real server权重动态调整,可以使用socat进行调整。

编辑配置文件
[root@node1 ~]# vim /etc/haproxy/conf.d/web01.cfg 
 listen web01
        mode tcp
        bind :8880
        balance roundrobin
        server web1 192.168.16.12:80 check
        server web2 192.168.16.13:80 check
 
 重启服务
[root@node1 ~]# systemctl restart haproxy.service 

测试:
[root@node4 ~]# for ((i=1;i<=10;i++)); do  curl 192.168.16.11:8880; done
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2

leastconn(最少连接)

支持权重的运行时调整和慢启动,即当前后端服务器连接最少的优先调度(新客户端连接),比较适合长连接的场景使用。

编辑配置文件
[root@node1 ~]# vim /etc/haproxy/conf.d/web01.cfg 
 listen web01
        mode tcp
        bind :8880
        balance leastconn
        server web1 192.168.16.12:80 check
        server web2 192.168.16.13:80 check
 
 重启服务
[root@node1 ~]# systemctl restart haproxy.service

测试:
[root@node4 ~]# for ((i=1;i<=10;i++)); do  curl 192.168.16.11:8880; done
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 

random(负载平衡)

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

编辑配置文件
[root@node1 ~]# vim /etc/haproxy/conf.d/web01.cfg 
 listen web01
        mode tcp
        bind :8880
        balance random
        server web1 192.168.16.12:80 weight 1 check
        server web2 192.168.16.13:80 weight 5 check
 
 重启服务:
[root@node1 ~]# systemctl restart haproxy.service 

测试:
[root@node4 ~]# for ((i=1;i<=10;i++)); do  curl 192.168.16.11:8880; done
this is a test1 
this is a test2 
this is a test2 
this is a test2 
this is a test1 
this is a test2 
this is a test2 
this is a test2 
this is a test2 
this is a test2

3、其他算法(可静可动)

可以作为静态算法,也可通过选项称为动态算法

(1)source算法(源地址hash)

基于用户源地址hash并将请求转发到一个后端服务器,后续同一个源请求将是同一个服务器进行服务。此方式当后端服务器数据量发生变化时,会导致很多用户的请求转发至新的后端服务器。
默认静态方式,可以通过hash-type指定map-based和consistent,来定义使用取模法还是一致性hash。

源地址选取后端服务器的计算方式:

计算方法一:map-based(取模法)

对source地址进行hash计算,再基于服务器总权重的取模,最终结果决定将此请求转发至对应的后端服务器。

该算法是静态的
不支持在线调整权重
不支持慢启动,可实现对后端服务器均衡调度

缺点

当服务器的总权重发生变化时,即有服务器上线或下线,都会因总权重发生变化而导致调度结果整体改变,hash-type 默认该算法

计算方法二:一致性hash

当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动,

该算法是动态的
支持在线权重调整,可使用 socat
支持慢启动

基于source算法,hash-type为map-based:

[root@node1 ~]# vim /etc/haproxy/conf.d/web01.cfg 
 listen web01
        mode tcp
        bind :8880
        balance source
        hash-type map-based
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check

[root@node1 ~]# systemctl restart haproxy.service 
[root@node1 ~]# echo "set weight web01/web1 3" | socat stdio /var/lib/haproxy/haproxy.sock
Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.

基于source算法,hash-type为consistent:

[root@node1 ~]# vim /etc/haproxy/conf.d/web01.cfg 
 listen web01
        mode tcp
        bind :8880
        balance source
        hash-type consistent
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check

[root@node1 ~]# systemctl restart haproxy.service 
[root@node1 ~]# echo "set weight web01/web1 3" | socat stdio /var/lib/haproxy/haproxy.sock                                        

(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>

基于uri算法,hash-type为map-based:

 listen web01
        mode http                   #只能为http类型
        bind :8880
        balance uri
        hash-type map-based
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check

基于uri算法,hash-type为map-based:

 listen web01
        mode http
        bind :8880
        balance uri
        hash-type consistent
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check

(3)url_param算法

基于对用户请求的URI中的 params 部分中的一个参数key对应的value值作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个real server。
如果无key,将按默认的roundrobin算法
此算法是应用层,所有只支持 mode http ,不支持 mode tcp

假设: url = http://www.openlab.com/foo/bar/index.php?key=value 
则:
	host = "www.openlab.com" 
	url_param = "key=value"

基于url_param算法,hash-type为map-based:

 listen web01
        mode http
        bind :8880
        balance url_param userid
        hash-type map-based
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check

基于url_param算法,hash-type为consistent:

 listen web01
        mode http
        bind :8880
        balance url_param userid
        hash-type consistent
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check

(4)hdr算法

基于用户每个http头部(header)请求中的指定信息做hash,此处由 name 指定的http首部将会被取出并做hash计算,然后由服务器总权重取模以后派发至某挑出的服务器。
如无有效的值,则会使用默认的轮询调度。
此算法是应用层,所有只支持 mode http ,不支持 mode tcp

基于hdr算法,hash-type为map-based:

 listen web01
        mode http
        bind :8880
        balance har(User-Agent)    #根据浏览器类型进行hash
        hash-type map-based
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check

基于hdr算法,hash-type为consistent:

 listen web01
        mode http
        bind :8880
        balance har(User-Agent)
        hash-type consistent
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check

重启服务后测试:

[root@node4 ~]# curl -v 192.168.16.11:8880
* About to connect() to 192.168.16.11 port 8880 (#0)
*   Trying 192.168.16.11...
* Connected to 192.168.16.11 (192.168.16.11) port 8880 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.16.11:8880
> Accept: */*
> 
< HTTP/1.1 200 OK
< date: Fri, 26 Feb 2021 13:54:10 GMT
< server: Apache/2.4.6 (CentOS)
< last-modified: Fri, 26 Feb 2021 05:01:25 GMT
< etag: "11-5bc3629028f97"
< accept-ranges: bytes
< content-length: 17
< content-type: text/html; charset=UTF-8
< 
this is a test1 

[root@node4 ~]# curl -vA "chrome" 192.168.16.11:8880
* About to connect() to 192.168.16.11 port 8880 (#0)
*   Trying 192.168.16.11...
* Connected to 192.168.16.11 (192.168.16.11) port 8880 (#0)
> GET / HTTP/1.1
> User-Agent: chrome
> Host: 192.168.16.11:8880
> Accept: */*
> 
< HTTP/1.1 200 OK
< date: Fri, 26 Feb 2021 13:53:36 GMT
< server: Apache/2.4.6 (CentOS)
< last-modified: Fri, 26 Feb 2021 05:01:38 GMT
< etag: "11-5bc3629caea7f"
< accept-ranges: bytes
< content-length: 17
< content-type: text/html; charset=UTF-8
< 
this is a test2 

[root@node4 ~]# curl -vA "firefox" 192.168.16.11:8880
* About to connect() to 192.168.16.11 port 8880 (#0)
*   Trying 192.168.16.11...
* Connected to 192.168.16.11 (192.168.16.11) port 8880 (#0)
> GET / HTTP/1.1
> User-Agent: firefox
> Host: 192.168.16.11:8880
> Accept: */*
> 
< HTTP/1.1 200 OK
< date: Fri, 26 Feb 2021 13:53:08 GMT
< server: Apache/2.4.6 (CentOS)
< last-modified: Fri, 26 Feb 2021 05:01:25 GMT
< etag: "11-5bc3629028f97"
< accept-ranges: bytes
< content-length: 17
< content-type: text/html; charset=UTF-8
< 
this is a test1 

(5)rdp-cookie

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

基于rdp-cookie算法,hash-type为map-based:

 listen web01
        mode http
        bind :8880
        balance rdp-cookie
        hash-type map-based
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check

基于rdp-cookie算法,hash-type为consistent:

 listen web01
        mode http
        bind :8880
        balance rdp-cookie
        hash-type consistent
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check

HAproxy高级功能

1、基于cookie的会话保持

cookie value:为当前server指定cookie值,实现基于cookie的会话黏性,相对于基于 source 地址hash 调度算法对客户端的粒度更精准,但同时也加大了haproxy负载。
不支持 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的请求都发送到同一台后端服务器

基于cookie编辑配置文件:node1

[root@node1 ~]# vim /etc/haproxy/conf.d/web01.cfg 
 listen web01
        mode http      #不支持 tcp,支持 http
        bind :8880
        balance roundrobin		#默认roundrobin
        log global				#全局日志
        cookie webser insert nocache indirect	#cookie相关配置
        server web1 192.168.16.12:80  check cookie web1
        server web2 192.168.16.13:80  check cookie web1

[root@node1 ~]# systemctl restart  haproxy.service 

测试:node4

[root@node4 ~]# curl -i 192.168.16.11:8880
HTTP/1.1 200 OK
date: Sun, 28 Feb 2021 01:22:25 GMT
server: Apache/2.4.6 (CentOS)
last-modified: Fri, 26 Feb 2021 05:01:25 GMT
etag: "11-5bc3629028f97"
accept-ranges: bytes
content-length: 17
content-type: text/html; charset=UTF-8
set-cookie: web01=web1; path=/					#cookie信息
cache-control: private

this is a test1 
[root@node4 ~]# curl -i 192.168.16.11:8880
HTTP/1.1 200 OK
date: Sun, 28 Feb 2021 01:22:28 GMT
server: Apache/2.4.6 (CentOS)
last-modified: Fri, 26 Feb 2021 05:01:38 GMT
etag: "11-5bc3629caea7f"
accept-ranges: bytes
content-length: 17
content-type: text/html; charset=UTF-8
set-cookie: web01=web1; path=/ 					#cookie信息
cache-control: private

this is a test2

基于cookie指定后端的服务名查看对应网页信息

[root@node4 ~]# curl -b webser=web1 192.168.16.11:8880  
this is a test1 
[root@node4 ~]# curl -b webser=web2 192.168.16.11:8880
this is a test1 

2、HAProxy状态页

通过web界面,显示当前HAProxy的运行状态:
官方文档http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#4-stats%20admin

配置文件中参数说明:

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中的管理功能

(1)版本隐藏示例,修改 listen stats配置项

配置修改前页面
web集群-负载均衡集群-HAproxy
隐藏版本信息配置:

[root@node1 ~]# vim /etc/haproxy/haproxy.cfg 
 listen stats
        mode http
        bind 0.0.0.0:9999
        stats enable
        log global
        stats uri /haproxy-status
        stats auth haadmin:123456
        stats hide-version    #添加该配置项
        
[root@node1 ~]# systemctl restart  haproxy.service

配置修改后页面隐藏了版本信息
web集群-负载均衡集群-HAproxy

(2)自定义uri示例,修改 listen stats配置项

[root@node1 ~]# vim /etc/haproxy/haproxy.cfg
 listen stats
        mode http
        bind 0.0.0.0:9999
        stats enable
        log global
        stats uri /haproxy-status
        stats auth haadmin:123456
        stats hide-version
        stats uri /status-page    	#自定义uri命名

[root@node1 ~]# systemctl restart  haproxy.service

web集群-负载均衡集群-HAproxy
web集群-负载均衡集群-HAproxy

(3)启用状态页管理功能,修改 listen stats配置项

[root@node1 ~]# vim /etc/haproxy/haproxy.cfg 
 listen stats
        mode http
        bind 0.0.0.0:9999
        stats enable
        log global
        stats uri /haproxy-status
        stats auth haadmin:123456
        stats hide-version
        stats uri /status-page
        stats admin if TRUE    			#编译该配置项

[root@node1 ~]# systemctl restart  haproxy.service

web集群-负载均衡集群-HAproxy

状态页面参数说明

web集群-负载均衡集群-HAproxy

pid = 1991 (process #1, nbproc = 1, nbthread = 1) 
							#pid为当前pid号,process为当前进程号,nbproc和nbthread为一共多少进程和每个进程多少个线程 
uptime = 0d 0h00m04s 		#启动了多长时间 
system limits: memmax = unlimited; ulimit-n = 200044 
							#系统资源限制:内存;最大打开文件数
maxsock = 200044; maxconn = 100000; maxpipes = 0 
							#最大socket连接数;单进程最大连接数; 最大管道数
current conns = 2; current pipes = 0/0; conn rate = 2/sec; bit rate = 0.000 kbps 
							#当前连接数;当前管道数;当前连接速率 
Running tasks: 1/26; 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)

backend 信息说明

web集群-负载均衡集群-HAproxy
session rate(每秒的连接会话信息):

cur:		每秒的当前会话数量 
max:		每秒新的最大会话数量 
limit:		每秒新的会话限制量 

sessions(会话信息):

cur:		当前会话量
max:		最大会话量 
limit: 		限制会话量
Total:		总共会话量 
LBTot:		选中一台服务器所用的总时间 
Last:		和服务器的持续连接时间 
Wght:		权重

Bytes(流量统计):

In:			网络的字节输入总量 
Out:		网络的字节输出总量 

Denied(拒绝统计信息):

Req:		拒绝请求量 
Resp:		拒绝回复量

Errors(错误统计信息):

Req:		错误请求量
conn:		错误链接量
Resp:		错误响应量

Warnings(警告统计信息):

Retr:		重新尝试次数
Redis:		再次发送次数

Server(real server信息):

Status:		后端机的状态,包括UP和DOWN
LastChk:	持续检查后端服务器的时间
Act:		活动链接数量
Bck:		备份的服务器数量
Chk:		心跳检测时间
Dwn:		后端服务器连接后都是DOWN的数量
Dwntme:		总的downtime时间
Thrtle:		server 状态

3、IP透传

IP透传目的:记录客户端的真实IP地址,用户访问的统计、安全维护、行为分析等

(1)四层IP透传配置:

修改后端服务器的全局日志格式:

[root@node2 ~]# vim /etc/httpd/conf/httpd.conf 
  # LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%{X-Forwarded-For}i %l %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

[root@node2 ~]# systemctl restart httpd

访问测试:node4

[root@node4 ~]# for ((i=1;i<=10;i++)); do  curl 192.168.16.11:8880 ; done
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1 
this is a test2 
this is a test1

后端服务器查看日志

[root@node2 ~]# tail  -3 /var/log/httpd/access_log 
192.168.16.14 - [28/Feb/2021:11:24:46 +0800] "GET / HTTP/1.1" 200 17 "-" "curl/7.29.0"
192.168.16.14 - [28/Feb/2021:11:24:46 +0800] "GET / HTTP/1.1" 200 17 "-" "curl/7.29.0"
192.168.16.14 - [28/Feb/2021:11:24:46 +0800] "GET / HTTP/1.1" 200 17 "-" "curl/7.29.0"

(2)七层IP透传配置:

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

option forwardfor [ except <network> ] [ header <name> ] [ if-none ] 
[ except <network> ]:请求报请来自此处指定的网络时不予添加此首部,如haproxy自身所在网络 
[ header <name> ]:使用自定义的首部名称,而非“X-Forwarded-For”
[ if-none ] 如果没有首部才添加首部,如果有使用默认值

下载扩展源

[root@node6 ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

4、报文修改

在http模式下,基于实际需求修改客户端的请求报文与响应报文,通过reqadd和reqdel在请求报文添加删除字段,通过rspadd与rspidel在响应报文中添加与删除字段。
官方文档:
http://cbonte.github.io/haproxy-dconv/2.1/configuration.html#4-http-request
http://cbonte.github.io/haproxy-dconv/2.1/configuration.html#4-http-response

5、自定义日志格式

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

[root@node1 ~]# tail -1 /var/log/haproxy.log 
Feb 28 20:16:38 localhost haproxy[3068]: Connect from 192.168.16.14:46656 to 192.168.16.11:8880 (web01/HTTP)

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

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

haproxy端修改日志格式参数:node1

 listen web01
        mode http
        bind :8880
        balance roundrobin
        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
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check 

测试:node4

[root@node4 ~]# for ((i=1;i<=2;i++)); do  curl 192.168.16.11:8880 ; done
this is a test1 
this is a test2 

haproxy端查看日志:node1

[root@node1 ~]# tail -1 /var/log/haproxy.log 
Feb 28 20:49:11 localhost haproxy[3211]: 192.168.16.14:46700 [28/Feb/2021:20:49:11.424] web01 web01/web2 0/0/0/1/1 200 250 - - ---- 1/1/0/0/0 0/0 {192.168.16.11:8880|curl/7.29.0||} "GET / HTTP/1.1"

6、HAProxy压缩功能

对响应给客户端的报文进行压缩,以节省网络带宽,但是会占用部分CPU性能,建议在后端服务器开启压缩功能,而非在HAProxy上开启压缩
配置选项:

compression algo <algorithm> ... 	#启用http协议中的压缩机制,常用算法有gzip,deflate 
<algorithm>支持下面类型: 
		identity 			#debug调试使用的压缩方式 
		gzip 				#常用的压缩方式,与各浏览器兼容较好 
		deflate 			#有些浏览器不支持 
		raw-deflate 		#新式的压缩方式 
compression type <mime type> ... 	#要压缩的文件类型

haproxy服务器配置压缩参数:node1

[root@node1 ~]# vim /etc/haproxy/conf.d/web01.cfg 
 listen web01
        mode http
        bind :8880
        balance roundrobin
        log global
        option httplog
        compression algo gzip deflate
        compression type compression type text/plain text/html text/css text/xml text/javascript application/javascript
        server web1 192.168.16.12:80  check
        server web2 192.168.16.13:80  check
        
[root@node1 ~]# systemctl restart  haproxy.service

后端服务器准备文件:node3

[root@node3 ~]# cat  /var/www/html/index.html 
this is a test2 

测试:node4

[root@node4 ~]# curl -is --compressed 192.168.16.11:8880/index.html
HTTP/1.1 200 OK
date: Sun, 28 Feb 2021 12:41:15 GMT
server: Apache/2.4.6 (CentOS)
last-modified: Fri, 26 Feb 2021 05:01:25 GMT
etag: W/"11-5bc3629028f97"
accept-ranges: bytes
content-type: text/html; charset=UTF-8
content-encoding: deflate
transfer-encoding: chunked
vary: Accept-Encoding

this is a test1

7、web服务检测状态

三种状态监测方式

基于四层的tcp端口做状态监测,此为默认方式 
基于指定 URI 做状态监测 
基于指定 URI 的request请求头部内容做状态监测

(1)基于tcp端口的健康检查配置

- inter : 2000 		不加该参数,正常情况默认每两秒检查一次。
- rise  : 2 		不加该参数,在RS宕机后恢复前,检查2次OK,认为其复合,并加入集群组中
- fall  : 3 		不加该参数,检查3此后,认为RS宕机,剔除集群组
- port  : default server port 		不加该参数,默认就是端口检查
- addr  : specific address for the test (default = address server)
- maxconn :2048 	最大连接数,
- weight :12 		权重

编辑配置文件中健康检查参数

 listen web01
        mode tcp
        bind :8880
        balance roundrobin
        log global
        option httpchk
        server web1 192.168.16.12:80  check port 80 inter 5000 fall 5
        server web2 192.168.16.13:80  check port 80 inter 5000 fall 5

[root@node1 ~]# systemctl restart  haproxy.service

(2) 基于HTTP的直接IP URL方式的健康检查

第一种HEAD配置方式

1)修改配置文件中健康检查选项
   option httpchk HEAD /index.html HTTP/1.0
   
2)重启haproxy服务
[root@node1 ~]# systemctl restart  haproxy.service

3)查看haproxy页面状态

第二种GET配置方法

1)修改配置文件中健康检查选项
   option httpchk GET /index.html
   
2)重启haproxy服务
[root@node1 ~]# systemctl restart  haproxy.service

3)查看haproxy页面状态

8、ACL

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

acl <aclname> <criterion> [flags] [operator] [<value>] 
acl 	名称 	匹配规范	   匹配模式 具体操作符   操作对象类型

criterion

hdr string
#提取在一个HTTP请求报文的首部 
hdr([<name> [,<occ>]]):完全匹配字符串,header的指定信息,<occ> 表示在多值中使用的值的出现次数 
hdr_beg([<name> [,<occ>]]):前缀匹配,header中指定匹配内容的begin 
hdr_end([<name> [,<occ>]]):后缀匹配,header中指定匹配内容end 
hdr_dom([<name> [,<occ>]]):域匹配,header中的domain name 
hdr_dir([<name> [,<occ>]]):路径匹配,header的uri路径 
hdr_len([<name> [,<occ>]]):长度匹配,header的长度匹配 
hdr_reg([<name> [,<occ>]]):正则表达式匹配,自定义表达式(regex)模糊匹配 
hdr_sub([<name> [,<occ>]]):子串匹配,header中的uri模糊匹配

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开头 
path_end : suffix match #请求的URL中资源的结尾
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

flags

-i 不区分大小写 
-m 使用指定的pattern匹配方法 
-n 不做DNS解析 
-u 禁止acl重名,否则多个同名ACL匹配或关系

operato(操作符)

整数比较: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进行匹配

value

- Boolean #布尔值 
- integer or integer range   #整数或整数范围,比如用于匹配端口范围 
- IP address / network		 #IP地址或IP范围, 192.168.0.1 ,192.168.0.1/24 
- string--> www.openlab.com 
 	exact –精确比较 
 	substring—子串 
 	suffix-后缀比较 
 	prefix-前缀比较 
 	subdir-路径, 	#/wp-includes/js/jquery/jquery.js 
 	domain-域名,	#www.openlab.com 
- regular expression 		#正则表达式 
- hex block					#16进制

ACL调用方式:

与:		隐式(默认)使用 
或:		使用“or” 或 “||”表示 
否定:	使用 "!" 表示

例:匹配访问路径实现动静分离

后端服务器网页配置:node2,node3

[root@node2 ~]# mkdir /var/www/html/static
[root@node2 ~]# echo "静态页面" > /var/www/html/static/index.html 
[root@node3 ~]#  mkdir /var/www/html/dynamic 
[root@node3 ~]# [root@node3 ~]# echo "动态页面" > /var/www/html/dynamic/index.html

haproxy端配置文件编辑:node1

[root@node1 ~]# vim /etc/haproxy/conf.d/web01.cfg 
frontend http
   bind :8880
   option http-keep-alive
   timeout http-keep-alive 30s

   acl static path_beg -i /static
   acl static path_reg -i ^/.+.(js|css|ico|bmp|jpg|jpeg|png|swf|cur|html)$

   acl dynamic path_beg -i /dynamic
   acl dynamic path_reg -i ^/.+.(php|jsp|html)$

   use_backend static_pool if staticv
   use_backend dynamic_pool if dynamic
   default_backend dynamic_pool

backend static_pool
   server static_page 192.168.16.12:80 check

backend dynamic_pool
   server dynamic_page 192.168.16.13:80 check

[root@node1 ~]# systemctl restart  haproxy.service                                                      

测试:node4

[root@node4 ~]# curl 192.168.16.11:8880/dynamic/
动态页面
[root@node4 ~]# curl 192.168.16.11:8880/static/
静态页面

9、自定义HAProxy错误界面

使用errorfileerrorloc指令,可以自定义各种错误页面
自定义错误页

errorfile <code> <file> 
	<code> #HTTP status code.支持200, 400, 403, 405, 408, 425, 429, 500, 502,503,504 
	<file> #包含完整HTTP响应的错误页文件的绝对路径。 建议后缀“ .http”,以和一般的html文件相区分

错误页面重定向

errorloc <code> <url> 
#相当于errorloc302 <code> <url>,利用302重定向至指URL

编辑自定义错误页面配置:node1

[root@node1 ~]# vim /etc/haproxy/haproxy.cfg 
defaults
        option http-keep-alive
        option forwardfor except 192.168.16.0/24
        maxconn 100000
        mode http
        timeout connect 300000ms
        timeout client 300000ms
        timeout server 300000ms
        errorfile 503 /usr/local/src/haproxy/html/503.http

创建文件存放目录及编辑网页内容:node1

[root@node1 ~]# mkdir /usr/local/src/haproxy/html -p
[root@node1 ~]# vim /usr/local/src/haproxy/html/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@node1 ~]# systemctl restart  haproxy.service

10、HAProxy后端不参与负载

编辑配置文件:node1

[root@node1 ~]# vim /etc/haproxy/haproxy.cfg 
 frontend webserver
        mode tcp
        bind 192.168.16.11:80
        use_backend webpool1

 backend webpool1
        server web1 192.168.16.12:80 check backup   #添加backup参数
        server web2 192.168.16.13:80 check

测试:node4

在这里插入代码片[root@node4 ~]# for ((i=1;i<=10;i++)); do  curl 192.168.16.11 ; done
动态页面
动态页面
动态页面
动态页面
动态页面
动态页面
动态页面
动态页面
动态页面
动态页面
上一篇:高可用RabbitMQ集群的搭建及原理分析


下一篇:Haproxy搭建 Web 群集实验