Haproxy

1 HAProxy入门

1.1 负载均衡

什么是负载均衡

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

为什么使用负载均衡

Web服务器的动态水平扩展-->对用户无感知 

增加业务并发访问及处理能力-->解决单服务器瓶颈问题 

节约公网IP地址-->降低IT支出成本 

隐藏内部服务器IP-->提高内部服务器安全性 

配置简单-->固定格式的配置文件 

功能丰富-->支持四层和七层,支持动态下线主机 

性能较强-->并发数万甚至数十万

负载均衡的分类

四层(OSI的传输层)负载均衡:

  • LVS(Linux Virtual Server)
  • HAProxy(High Availability Proxy)
  • Nginx(1.9之后版本)

七层负载均衡:

  • HAProxy
  • Nginx

也有硬件负载均衡,其功能比软件更强大,而且负载能力也高于软件负载:

  • F5
  • 深信服

1.2 HAProxy介绍

HAProxy是法国开发者 威利塔罗(Willy Tarreau) 在2000年使用C语言开发的一个开源软件,是一款具备高并发(一万 以上)、高性能的TCP和HTTP负载均衡器,支持基于cookie的持久性,自动故障切换,支持正则表达式及web状态 统计,目前最新TLS版本为2.0

HAProxy分为社区版和企业版:

企业版版加入了Web应用防火墙 、HTTP协议验证、ACL,映射和TLS票证密钥同步等新功能,同时提供技术支持。不过文章内容是围绕社区版展开。

1.2.1 HAProxy功能

HAProxy功能:

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

HAProxy不具备功能:

  • 正向代理
  • 缓存代理
  • Web服务器
  • UDP协议支持
  • 单机性能相比LVS性能差

1.2.2 HAProxy工作方式

HAProxy借助于OS上几种常见的技术来实现性能的最大化。

  • 单进程、事件驱动模型显著降低了上下文切换的开销及内存占用。
  • 内存分配器在固定大小的内存池中可实现即时内存分配,这能够显著减少创建一个会话的时长
  • 精心地降低了昂贵的系统调用,大部分工作都在用户空间完成,如时间读取、缓冲聚合及文件描述符的启用和禁用等

当HAProxy启动后,会负责下面任务:

  • 接收请求
  • 定时检查服务器状态
  • 和其他HAProxy节点交换信息

2 HAProxy安装和基础配置

2.1 Centos安装

2.1.1 默认yum源安装

默认的base仓库中包含haproxy的安装包文件,但是版本比较旧,是1.5.18的版本,距离当前版本已经有较长时间 没有更新,由于版本比较旧所以有很多功能不支持,如果对功能和性能没有要求可以使用此版本,否则推荐使用新 版本。

[root@localhost ~]# yum install haproxy -y
[root@localhost ~]# yum info haproxy
Loaded plugins: fastestmirror
Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast
Loading mirror speeds from cached hostfile
Available Packages
Name        : haproxy
Arch        : x86_64
Version     : 1.5.18
Release     : 9.el7_9.1
Size        : 835 k
Repo        : updates/7/x86_64
Summary     : TCP/HTTP proxy and load balancer for high availability environments
URL         : http://www.haproxy.org/
License     : GPLv2+

2.1.2 第三方包安装

安装包下载:https://pkgs.org/download/haproxy

[root@localhost ~]# rpm -ivh cheese-release-7-1.noarch.rpm
[root@localhost ~]# yum install haproxy-1.8.14-1.el7.x86_64.rpm -y

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

2.1.3 编译安装HAProxy

编译安装haproxy-2.2.19版本,源码包下载:http://www.haproxy.org/download/

[root@localhost src]# ls
haproxy-2.2.19.tar.gz
[root@localhost src]# tar -xf haproxy-2.2.19.tar.gz
[root@localhost src]# cd haproxy-2.2.19

由于centos自带的lua版本比较低并不符合HAProxy要求的lua最低版本(5.3)的要求,因此需要编译安装较新版本的 lua环境,然后才能编译安装HAProxy

[root@localhost src]# wget http://www.lua.org/ftp/lua-5.3.5.tar.gz

# 安装依赖包
[root@localhost src]# yum install libtermcap-devel ncurses-devel libevent-devel readline-devel
[root@localhost src]# tar xf lua-5.3.5.tar.gz 
[root@localhost src]# cd lua-5.3.5
# 一条命令完成编译和安装lua
[root@localhost lua-5.3.5]# make linux install
[root@localhost lua-5.3.5]# lua -v
Lua 5.3.5  Copyright (C) 1994-2018 Lua.org, PUC-Rio

现在可以继续安装haproxy

[root@localhost haproxy-2.2.19]#yum -y install gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel \
systemd-devel net-tools vim iotop bc zip unzip zlib-devel lrzsz tree screen lsof \
tcpdump wget ntpdate

# 第一次编译出现下面告警
make: warning:  Clock skew detected.  Your build may be incomplete
# 还原虚拟机快照导致时间错误,同步一次时间再次编译即可解决报错
[root@localhost haproxy-2.2.19]# ntpdate cn.pool.ntp.org
[root@localhost haproxy-2.2.19]# make -j 4 ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 USE_LUA=1 LUA_INC=/usr/local/src/lua-5.3.5/src/ LUA_LIB=/usr/local/src/lua-5.3.5/src PREFIX=/usr/local/haproxy
[root@localhost haproxy-2.2.19]# make install PREFIX=/usr/local/haproxy

# 完成编译安装后查看安装目录
[root@localhost haproxy-2.2.19]# ls /usr/local/haproxy/
doc  sbin  share
[root@localhost haproxy-2.2.19]# ls /usr/local/haproxy/sbin/
haproxy

# 由于只有一个二进制程序,所以可以拷贝到环境变量目录中
[root@localhost haproxy-2.2.19]# cp /usr/local/haproxy/sbin/haproxy /usr/sbin/

# 验证haproxy版本
[root@localhost haproxy-2.2.19]# haproxy -v
HA-Proxy version 2.2.19-7ea3822 2021/11/29 - 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.19.html
Running on: Linux 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64

创建systemctl管理服务文件

[root@localhost local]# 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

创建相关文件

# 创建配置文件
[root@localhost local]# cat /etc/haproxy/haproxy.cfg 
global
maxconn 100000
chroot /usr/local/haproxy
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
uid 99
gid 99
daemon

# 创建PID目录
[root@localhost local]# mkdir /var/lib/haproxy
[root@localhost local]# chown 99.99 /var/lib/haproxy/ -R
[root@localhost local]# systemctl start haproxy

2.2 基础配置详解

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

2.2.1 全局配置参数

常用配置选项示例

# 锁定运行目录
chroot 
# 以守护进程运行
deamon 
#stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin # 绑定socket文件
# 运行haproxy的用户身份
user, group, uid, gid 
# 开启的haproxy进程数,与CPU保持一致
nbproc 
# 指定每个haproxy进程开启的线程数,默认为每个进程一个线程
nbthread 
# 绑定haproxy 进程至指定CPU
cpu-map 1 0   
# 每个haproxy进程的最大并发连接数
maxconn  
# 每个haproxy进程ssl最大连接数,用于haproxy配置了证书的场景下
maxsslconn   
# 每个进程每秒创建的最大连接数量
maxconnrate  
# 后端server状态check随机提前或延迟百分比时间,建议2-5(20%-50%)之间
spread-checks 
# 指定pid文件路径
pidfile 
# 定义全局的syslog服务器;最多可以定义两个,Facility字段中local0到local7是给用户使用的,用于自定义应用日志   存储,在/etc/rsyslog.conf 中设置Facility字段对应日志存储的位置。
log 127.0.0.1 local3 info 

2.2.2 Proxies配置

代理配置段

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

# name字段只能使用”-”、”_”、”.”、和”:”,并且严格区分大小写,例如:Web和web是完全不同的两组服务器。

defaults 配置参数:

option redispatch     	# 当server Id对应的服务器挂掉后,强制定向到其他健康的服务器,重新派发
option abortonclose   	# 当服务器负载很高的时候,自动结束掉当前队列处理比较久的链接,关闭
option http-keep-alive 	# 开启与客户端的会话保持
option forwardfor     	# 透传客户端真实IP至后端web服务器
mode http 					# 设置默认工作类型
timeout http-keep-alive 120s # session 会话保持超时时间,范围内会转发到相同的后端服务器
timeout connect 120s 	# 客户端请求从haproxy到后端server的最长连接等待时间(TCP之前)
timeout server 600s 		# 客户端请求从haproxy到后端服务端的请求处理超时时长(TCP之后)
timeout client 600s 		# 设置haproxy与客户端的最长非活动时间
timeout check   5s   	# 对后端服务器的默认检测超时时间

frontend配置参数:

bind:指定HAProxy的监听地址,可以是IPV4或IPV6,可以同时监听多个IP或端口,可同时用于listen字段中
bind [<address>]:<port_range> [, ...] [param*]
# 监听http的多个IP的多个端口和sock文件
listen http_proxy 
   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

# https监听
listen http_https_proxy 
   bind :80
   bind :443 ssl crt /etc/haproxy/site.pem

# 监听ipv6、ipv4和unix sock文件
listen http_https_proxy_explicit 
   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
   
# 监听file descriptor
listen external_bind_app1 
   bind "fd@${FD_APP1}"

backend配置参数:

# 指定负载协议类型
mode http/tcp   

# 配置选项,后面加httpchk,smtpchk,mysql-check,pgsql-check方法,可用于实现更多应用层检测功能。
option 

# 定义后端real server
server   

check 			# 对指定real进行健康状态检查,默认不开启
    addr IP   	# 可指定的健康状态监测IP
    port num 	# 指定的健康状态监测端口
    inter num 	# 健康状态检查间隔时间,默认2000 ms
    fall num   # 后端服务器失效检查次数,默认为3
    rise num   # 后端服务器从下线恢复检查次数,默认为2
weight 			# 默认为1,最大值为256,0表示不参与负载均衡
backup 			# 将后端服务器标记为备份状态
disabled 		# 将后端服务器标记为不可用状态
redirect prefix http://www.edu.net/   # 将请求临时重定向至其它URL,只适用于http模式
maxconn <maxconn>:						 # 当前后端server的最大并发连接数
backlog <backlog>:						 # 当server的连接数达到上限后的后援队列长度

frontend+backend配置范例

# 官网业务访问入口======================================
frontend WEB_PORT_80
	# 绑定的是haproxy所在服务器
   bind 192.168.7.248:80
   mode http
   use_backend web_prot_http_nodes
backend web_prot_http_nodes
   mode http
   option forwardfor
   # 要转发的后端服务器
   server 192.168.7.101 192.168.7.101:8080   check inter 3000 fall 3 rise 5
   server 192.168.7.102 192.168.7.102:8080   check inter 3000 fall 3 rise 5

listen替代frontend+backend

# 官网业务访问入口=====================================
listen WEB_PORT_80
   bind 192.168.7.102:80
   mode http
   option forwardfor
   server web1   192.168.7.101:80   check inter 3000 fall 3 rise 5
   server web2   192.168.7.101:80   check inter 3000 fall 3 rise 5

3 HAProxy调度算法

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

http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#4-balance

3.1 静态算法

静态算法:按照事先定义好的规则轮询公平调度,不关心后端服务器的当前负载、链接数和相应速度等,且无法实 时修改权重,只能靠重启HAProxy生效。

使用命令行进行动态权重调整:

# Socat 是 Linux 下的一个多功能的网络工具,名字来由是Socket CAT,Socat 的主要特点就是在两个数据流之间建立   通道,且支持众多协议和链接方式。如 IP、TCP、 UDP、IPv6、Socket文件等。

# 安装socat
[root@localhost ~]# yum install socat

# 显示当前进程的haproxy状态信息
[root@localhost ~]# echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock
Name: HAProxy
Version: 2.2.19-7ea3822
# 查看后端服务器权重
[root@localhost ~]# echo "get weight web_port/web1" | socat stdio /var/lib/haproxy/haproxy.sock
1 (initial 1)

# 访问官网查看更多支持的Unix Socket命令
http://cbonte.github.io/haproxy-dconv/2.2/management.html#9.3

3.1.1 static-rr

static-rr:基于权重的轮询调度,不支持权重的运行时调整及后端服务器慢启动,其后端主机数量没有限制

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance static-rr
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 2 check inter 3000 fall 2 rise 5

3.1.2 first

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

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance first
 server web1 192.168.7.103:80 maxconn 2 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

3.2 动态算法

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

3.2.1 roundrobin

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

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance roundrobin
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 2 check inter 3000 fall 2 rise 5

动态调整权限

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

[root@localhost ~]#  echo "set weight web_port/web2 3" | socat stdio /var/lib/haproxy/haproxy.sock

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

3.2.2 leastconn

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

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance leastconn
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5 

3.3 其他算法

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

3.3.1 source

源地址hash,基于用户源地址hash并将请求转发到后端服务器,默认为静态即取模方式,但是可以通过hash-type 支持的选项更改,后续同一个源地址请求将被转发至同一个后端web服务器,比较适用于session保持/缓存业务等 场景。

源地址有两种转发客户端请求到后端服务器的服务器选取计算方式,分别是取模法一致性hash

取模法

map-based:使用服务器权重进行模二运算,来确定转发的后端服务器。server = hash(key)mod N,N代表所有服务器权重之和,hash(key)在这里对应源地址hash的值,根据取模的值来决定往哪个对应的后端服务器转发

该hash是静态的即不支持在线调整权重,不支持慢启动,其对后端服务器调度均衡,缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因权重发生变化而导致调度结果整体改变。

基于权重取模:(2^32-1)%(1+1+2)

取模法配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode tcp
 log global
 balance source
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

一致性hash

一致性哈希,该hash是动态的,支持在线调整权重,支持慢启动,优点在于当服务器的总权重发生变化时,对调度 结果影响是局部的,不会引起大的变动,这里使用一个图来简单了解下其原理

image

首先将整个Hash空间组织成一个虚拟的圆环,接着对各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台服务器就确定在了哈希环的一个位置上。如上图有A、B、C三台服务器。接着将用户请求Hash后确认在环上的位置,同时规定每个对象都属于其最近的服务器,逆时针方向(或顺时针,取决于使用的约定)。这样就确定了用户的请求应该分配给哪台后端服务器。

但是如果服务器节点太少可能会出现大部分请求调度到同一个服务器情况,如下图

image

为了使请求均匀分布,Hash算法引入了虚拟节点机制,即对每一个服务器节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。

数据定位算法不变,只需要增加一步:虚拟节点到实际点的映射。

image

在将虚拟节点放置在环上

image

虚拟节点越多,分布越均衡

一致性hash配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode tcp
 log global
 balance source
 hash-type consistent
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5 

3.3.2 uri

基于对用户请求的uri做hash并将请求转发到后端指定服务器,也可以通过map-based和consistent定义使用取模 法还是一致性hash。

uri 取模法配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance uri
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5 

uri 一致性hash配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance uri
 hash-type consistent
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

3.3.3 url_param

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

假设url = http://www.magedu.com/foo/bar/index.php?k1=v1&k2=v2
则:
host = "www.magedu.com"
url_param = "k1=v1&k2=v2"

url_param取模法配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance url_param name,age #支持对单个及多个url_param 值hash
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

url_param一致性hash配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance url_param name,age #支持对单个及多个url_param 值hash
 hash-type consistent
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

3.3.4 hdr

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

hdr取模法配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance hdr(User-Agent)
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5 

一致性hash配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance hdr(User-Agent)
 hash-type consistent
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

rdp-cookie对远windows程桌面的负载,使用cookie保持会话

rdp-cookie取模法配置示例

listen RDP
 bind 192.168.7.101:3389
 balance rdp-cookie
 mode tcp
 server rdp0 172.18.132.20:3389 check fall 3 rise 5 inter 2000 weight 1

rdp-cookie一致性hash配置示例

listen RDP
 bind 192.168.7.101:3389
 balance rdp-cookie
 hash-type consistent
 mode tcp
 server rdp0 172.18.132.20:3389 check fall 3 rise 5 inter 2000 weight 1 

3.3.6 random

在1.9版本开始增加一个叫做random的负载平衡算法,其基于一个随机数作为一致性hash的key,随机负载平衡对 于大型服务器场或经常添加或删除服务器非常有用,因为它可以避免在这种情况下由roundrobin或leastconn导致 的锤击效应。

random配置实例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance random
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5 

4 高级功能及配置

4.1 IP地址透传

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

4.1.1 四层IP透传

haproxy 配置

# send-proxy参数会强制使用PROXY protocol协议,PROXY protocol协议提供了安全传输客户端地址等连接信息的功能
listen web_prot_http_nodes
 bind 192.168.7.101:80
 mode tcp
 balance roundrobin
 server web1 blogs.studylinux.net:80 send-proxy check inter 3000 fall 3 rise 5

nginx配置

server {
 listen 80 proxy_protocol;
 #listen 80;
 server_name www.edu.net;

要在Nginx日志中查看客户端的真实IP地址还需要配置日志参数$proxy_protocol_addr

http {
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"'
                      '$proxy_protocol_addr:$server_port';

4.1.2 七层IP透传

HAProxy配置

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

配置
defaults
# header关键字允许用户使用自定义名称来替代默认的‘X-Forwarded-For’,注意如果修改了默认‘X-Forwarded-For’,   后端服务器使用的变量名应当和自定义名称相同
option forwardfor header X-Cluster-Client-IP 

listen web_host
 bind 192.168.7.101:80
 mode http
 log global
 balance random
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

web服务器日志格式配置

# nginx日志格式
# 使用$http_name变量来获取传递过来的‘X-Forwarded-For’值,注意这里自定义名称为全小写,-使用_代替
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                   '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_cluster_client_ip"';

验证日志内容

[root@nginx ~]# tail -f  /apps/nginx/logs/access.log -n0
192.168.10.208 - - [15/Dec/2021:12:08:35 +0800] "GET / HTTP/1.1" 200 10 "-" "curl/7.29.0" "192.168.10.211"

4.2 基于cookie的会话保持

cookie value:为当前server指定cookie值,实现基于cookie的会话黏性

4.2.1 配置选项

cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ]
              [ postonly ] [ preserve ] [ httponly ] [ secure ]
              [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
              [ dynamic ] [ attr <value> ]*
              # name:cookie 的key名称,用于实现持久连接
 				  # insert:如果没有就插入新的cookie
 				  # indirect:不会向客户端发送服务器已经处理过请求的cookie信息,间接
 				  # nocache:当client和hapoxy之间有缓存时,不缓存cookie 

4.2.2 配置示例

listen web_host
 bind 192.168.7.101:80
 mode http
 log global
 balance roundrobin
 cookie SERVER-COOKIE insert indirect nocache
 server web1 192.168.7.103:80 cookie web1 check inter 3000 fall 3 rise 5
 server web2 192.168.7.104:80 cookie web2 check inter 3000 fall 3 rise 5 

4.3 HAProxy状态页

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

4.3.1 状态页

# 基于默认的参数启用stats page
stats enable 
# 隐藏版本
stats hide-version 
# 设定自动刷新时间间隔
stats refresh <delay> 
# 自定义stats page uri,默认值:/haproxy?stats
stats uri <prefix> 
# 账户认证时的提示信息,示例:stats realm : HAProxy\ Statistics
stats realm <realm> 
# 认证时的账号和密码,可使用多次,默认:no authentication
stats auth <user>:<passwd> 
# 启用stats page中的管理功能
stats admin { if | unless } <cond> 

4.3.2 状态页配置

listen stats
    bind 0.0.0.0:9009
    mode http
    stats enable
    #stats hide-version
    stats uri /haproxy-status
    stats realm   HAProxy\ Stats\ Page
    stats auth    admin:123321
    #stats refresh 30s

4.3.3 访问状态页

image

关于状态页指标含义可以参考文章:https://www.haproxy.com/blog/exploring-the-haproxy-stats-page/

在官方文档中则描述了CVS格式的各项参数:http://cbonte.github.io/haproxy-dconv/2.2/management.html#9.1。

4.4 自定义HAProxy错误界面

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

4.4.1 基于错误页面文件

defaults
#option forwardfor
#no option http-use-htx
#...... #以下三行
errorfile 500 /usr/local/haproxy/html/500.html
errorfile 502 /usr/local/haproxy/html/502.html
errorfile 503 /usr/local/haproxy/html/503.html 

4.4.2 基于http重定向

defaults
#option http-keep-alive
#option forwardfor
#no option http-use-htx
#...... 以下一行
errorloc 503 http://192.168.7.102/error_page/503.html 

4.5 web服务器状态监测

通过URI请求访问后端服务器来监测后端服务器是否在线

4.5.1 状态监测方式

option httpchk

option httpchk uri

option httpchk method uri

option httpchk method uri version

可分为下面三种监测方式

  • 基于四层的传输端口做状态监测
  • 基于指定URI做状态监测
  • 基于指定URI的request请求头部内容做状态监测

4.5.2 配置范例

 说明
 # 使用HEAD方法只获取报头,减少传输的数据内容同时达到监测效果
 # 较之前版本在\r\n之后可以设置请求头和请求体,不过在2.2版本中这一方式已被启用,请使用http-check send来替代
 # 该方法
 # /check.html指代的是网站根目录下的内容而不是服务器目录内容

listen web_host
 bind 192.168.7.101:80
 mode http
 balance roundrobin
 log global
 option httplog
 #option httpchk GET /check.html HTTP/1.0

 # 较之前版本设置监控内容添加请求头和请求体
 #option httpchk HEAD /check.html HTTP/1.0\r\nHost:\ www
 
 # 2.2版本之后添加请求头和请求体
 option httpchk HEAD /check.html HTTP/1.0
 http-check send hdr Host www
 cookie SERVER-COOKIE insert indirect nocache
 server web1 192.168.7.103:80 cookie web1 check inter 3000 fall 3 rise 5
 server web2 192.168.7.104:80 cookie web2 check inter 3000 fall 3 rise 5 

使用tcpdump命令来验证请求头是否添加成功

[root@nginx ~]# tcpdump -i eth0 port 80 -s 1024 -A | grep host
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 1024 bytes
host: www
host: www

4.6 ACL

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

4.6.1 ACL格式规范

acl <aclname> <criterion> [flags] [operator] [<value>] ...

aclname

ACL名称,可以使用大字母A-Z、小写字母a-z、数字0-9、冒号:、点.、中横线和下划线,并且严格区分大小写,必 须Image_site和image_site完全是两个acl。

criterion

定义ACL匹配规范

  hdr([<name>[,<occ>]])     : exact string match
  hdr_beg([<name>[,<occ>]]) : prefix match
  hdr_dir([<name>[,<occ>]]) : subdir match
  hdr_dom([<name>[,<occ>]]) : domain match
  hdr_end([<name>[,<occ>]]) : suffix match
  hdr_len([<name>[,<occ>]]) : length match
  hdr_reg([<name>[,<occ>]]) : regex match
  hdr_sub([<name>[,<occ>]]) : substring match
  
  dst 		目标IP
  dst_port  目标PORT

  src       源IP
  src_port  源PORT

范例:

 hdr(<string>) 	# 用于测试请求头部首部指定内容
 hdr_dom(host) 	# 请求的host名称,如 www.magedu.com
 hdr_beg(host) 	# 请求的host开头,如 www. img. video. download. ftp.
 hdr_end(host) 	# 请求的host结尾,如 .com .net .cn
 path_beg 			# 请求的URL开头,如/static、/images、/img、/css
 path_end  			# 请求的URL中资源的结尾,如 .gif .png .css .js .jpg .jpeg

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

flags

The following ACL flags are currently supported:

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

operator

整数匹配:eq、ge、gt、le、lt

字符匹配:

  • exact match (-m str) :字符串必须完全匹配模式
  • substring match (-m sub) :在提取的字符串中查找模式,如果其中任何一个被发现,ACL将匹配
  • prefix match (-m beg) :在提取的字符串首部中查找模式,如果其中任何一个被发现,ACL将匹配
  • suffix match (-m end) :将模式与提取字符串的尾部进行比较,如果其中任何一个匹配,则ACL进行匹配
  • subdir match (-m dir) :查看提取出来的用斜线分隔(“/”)的字符串,如果其中任何一个匹配,则ACL进 行匹配
  • domain match (-m dom) :查找提取的用点(“.”)分隔字符串,如果其中任何一个匹配,则ACL进行匹配

value

The ACL engine can match these types against patterns of the following types :

  • boolean
  • integer or integer range
  • IP address / network
  • string (exact, substring, suffix, prefix, subdir, domain)
  • regular expression
  • hex block

4.6.2 ACL调用方式

ACL组合条件

  • 与:隐式(默认)使用

  • 或:使用“or” 或 “||”表示

  • 否定:使用“!“ 表示

范例:

# 域名匹配
listen web_host
    bind 192.168.7.101:80
    mode http
    balance roundrobin
    log global
    option httplog
    acl web_host hdr_dom(host) www.edu.net
    use_backend test_host if web_host
    default_backend default_web
backend test_host
    mode http
    server web1 192.168.10.207 check inter 2000 fall 3 rise 5
backend default_web
    mode http
    server web1 192.168.10.209:80 check inter 2000 fall 3 rise 5 

测试访问

# 访问www.edu.net时转发到207,访问192.168.10.208 时转发至209
[root@localhost ~]# curl www.edu.net
PC Server
[root@localhost ~]# curl 192.168.10.208
192.168.10.209

4.6.3 预定义ACL

http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#7.4

ACL name Equivalent to Usage
FALSE always_false never match
HTTP req.proto_http match if request protocol is valid HTTP
HTTP_1.0 req.ver 1.0 match if HTTP request version is 1.0
HTTP_1.1 req.ver 1.1 match if HTTP request version is 1.1
HTTP_CONTENT req.hdr_val(content-length) gt 0 match an existing content-length in the HTTP request
HTTP_URL_ABS url_reg [/:]*😕/ match absolute URL with scheme

范例:

listen web_host
    bind 192.168.7.101:80
    mode http
    balance roundrobin
    log global
    option httplog

    acl static_path path_beg -i /static /images /javascript
    # 这里TRUE表示值不为空
    use_backend static_path_host if HTTP_1.1 TRUE static_path
    default_backend default_web 
    
backend php_server_host
    mode http
    server web1 192.168.7.103 check inter 2000 fall 3 rise 5

backend static_path_host
    mode http
    server web1 192.168.7.104 check inter 2000 fall 3 rise 5

backend default_web
    mode http
    server web1 192.168.7.102:80 check inter 2000 fall 3 rise 5

4.7 报文修改

在http模式下,基于实际需求修改客户端的请求报文与响应报文,通过reqadd和reqdel在请求报文添加删除字段, 通过rspadd与rspidel在响应报文中添加与删除字段。不过,在2.2版本中这些方式已被弃用,官方推荐http-request deny/allow/tarpit来替代reqdeny/reqpass/reqtarpit,http-request会配合ACL规则使用。

范例:

acl nagios src 192.168.129.3
acl local_net src 192.168.0.0/16
acl auth_ok http_auth(L1)

http-request allow if nagios
http-request allow if local_net auth_ok
http-request auth realm Gimme if local_net auth_ok
http-request deny

文档链接:

官方不同版本文档:http://cbonte.github.io/haproxy-dconv/

中文文档:http://www.ttlsa.com/linux/haproxy-study-tutorial/

一致性哈希原理与实现:https://www.jianshu.com/p/528ce5cd7e8f

posted @ 2021-12-17 19:00  bestvae  阅读(500)  评论(0编辑  收藏  举报