Bootstrap

Haproxy

一、haproxy简介

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

二、haproxy的安装

功能ip
haproxy192.168.10.130
RS1
192.168.10.101
RS2
192.168.10.102

2.1haproxy的基本配置信息

global :全局配置段
进程及安全配置相关的参数
性能调整相关参数
Debug 参数
proxies :代理配置段
defaults :为 frontend, backend, listen 提供默认配置
frontend :前端,相当于 nginx 中的 server {}
backend :后端,相当于 nginx 中的 upstream {}
listen :同时拥有前端和后端配置 , 配置简单 , 生产推荐使用

2.1.1global配置

参数实例:

nbproc N:

默认work进程只有一个

 

设置参数为2则会多一个线程

线程多了后通常通过cpu-map参数来绑定cpu

线程设定

线程设定和进程设定互斥

npthread

定向日志文件

在 /etc/rsys.conf中添加

udp协议打开

2.1.2proxies配置

2.1.2.1Proxies配置-defaults

defaults
mode http # HAProxy 实例使用的连接协议
log global # 指定日志地址和记录日志条目的
syslog/rsyslog 日志设备
# 此处的 global 表示使用 global 配置段中
设定的 log 值。
option httplog # 日志记录选项, httplog 表示记录与 HTTP
会话相关的各种属性值
# 包括 HTTP 请求、会话状态、连接数、源地
址以及连接时间等
option dontlognull #dontlognull 表示不记录空会话连接日志
option http-server-close # 等待客户端完整 HTTP 请求的时间,此处为等
10s
option forwardfor except 127 .0.0.0/8 # 透传客户端真实 IP 至后端 web 服务器
# apache 配置文件中加入 :<br>%{X
Forwarded-For}i
# 后在 webserer 中看日志即可看到地址透传
信息
option redispatch # server Id 对应的服务器挂掉后,强制定
向到其他健康的服务器,重新派发
option http-keep-alive # 开启与客户端的会话保持
retries 3 # 连接后端服务器失败次数
timeout http-request 10s # 等待客户端请求完全被接收和处理的最长时
timeout queue 1m # 设置删除连接和客户端收到 503 或服务不可
用等提示信息前的等待时间
timeout connect 120s # 设置等待服务器连接成功的时间
timeout client 600s # 设置允许客户端处于非活动状态,即既不发
送数据也不接收数据的时间
timeout server 600s # 设置服务器超时时间,即允许服务器处于既
不接收也不发送数据的非活动时间
timeout http-keep-alive 60s #session 会话保持超时时间,此时间段内
会转发到相同的后端服务器
timeout check 10s # 指定后端服务器健康检查的超时时间
maxconn 3000
default-server inter 1000 weight 3
2.1.2.2 Proxies配置-frontend 
bind :指定 HAProxy 的监听地址,可以是 IPV4 IPV6 ,可以同时监听多个 IP 或端口,可同时用于 listen
段中
# 格式:
bind [<address>]:<port_range> [, ...] [param*]
# 注意:如果需要绑定在非本机的 IP ,需要开启内核参数: net.ipv4.ip_nonlocal_bind=1
backlog <backlog> # 针对所有 server 配置 , 当前端服务器的连接数达到上限后的后援队列长度,注意:不
支持 backend
 2.1.2.3 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> # 后端服务器从线上转为线下的检查的连续失效次数

测试

 

关闭rs

当rs1和rs2都无法访问时会跳转到

主机打开后

网页访问重定向

2.2haproxy的状态界面

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

2.2.1 状态页配置项

stats enable # 基于默认的参数启用 stats page
stats hide-version # 将状态页中 haproxy 版本隐藏
stats refresh <delay> # 设定自动刷新时间间隔,默认不自动刷新
stats uri <prefix> # 自定义 stats page uri ,默认值: /haproxy?stats
stats auth <user>:<passwd> # 认证时的账号和密码,可定义多个用户 , 每行指定一个用户
# 默认: no authentication
stats admin { if | unless } <cond> # 启用 stats page 中的管理功能

2.2.2 启用状态页 

2.2.3 登录状态页

#pid 为当前 pid 号, process 为当前进程号, nbproc nbthread 为一共多少进程和每个进程多少个线程
pid = 27134 (process #1, nbproc = 1, nbthread = 1)
# 启动了多长时间
uptime = 0d 0h00m04s
# 系统资源限制:内存 / 最大打开文件数 /
system limits: memmax = unlimited; ulimit-n = 200029
# 最大 socket 连接数 / 单进程最大连接数 / 最大管道数 maxpipes
maxsock = 200029; maxconn = 100000; maxpipes = 0
# 当前连接数 / 当前管道数 / 当前连接速率
current conns = 2; current pipes = 0/0; conn rate = 2/sec; bit rate = 0.000 kbps
# 运行的任务 / 当前空闲率
Running tasks: 1/14; idle = 100 %
active UP # 在线服务器
backup UP # 标记为 backup 的服务器
active UP, going down # 监测未通过正在进入 down 过程
backup UP, going down # 备份服务器正在进入 down 过程
active DOWN, going up #down 的服务器正在进入 up 过程
backup DOWN, going up # 备份服务器正在进入 up 过程
active or backup DOWN # 在线的服务器或者是 backup 的服务器已经转换成了 down 状态
not checked # 标记为不监测的服务器
#active 或者 backup 服务器人为下线的
active or backup DOWN for maintenance (MAINT)
#active 或者 backup 被人为软下线 ( 人为将 weight 改成 0)
active or backup SOFT STOPPED for maintenance

2.3socat 工具

对服务器动态权重和其它状态可以利用 socat 工具进行调整, Socat Linux 下的一个多功能的网络工
具,名字来由是 Socket CAT ,相当于 netCAT 的增强版 .Socat 的主要特点就是在两个数据流之间建立双向
通道,且支持众多协议和链接方式。如 IP TCP UDP IPv6 Socket 文件等
范例:利用工具 socat 对服务器动态权重调整
# 修改配置文件
[root@haproxy ~] # vim /etc/haproxy/haproxy.cfg
stats socket /var/lib/haproxy/stats mode 600
haproxy ~] # socat -h
haproxy ~] # echo "help" | socat stdio /var/lib/haproxy/stats
# 查看集群状态
[root@haproxy ~]# echo "show servers state" | socat stdio /var/lib/haproxy/stats 
# 查看 haproxy 状态
[root@haproxy ~]# echo "show info" | socat stdio /var/lib/haproxy/stats

 

# 查看集群权重
[root@haproxy ~]# echo get weight webcluster/web1 | socat stdio
/var/lib/haproxy/stats
2 (initial 2)
[root@haproxy ~]# echo get weight webcluster/web2 | socat stdio
/var/lib/haproxy/stats
1 (initial 1)
# 设置权重
[root@haproxy ~]# echo "set weight webcluster/web1 1 " | socat stdio
/var/lib/haproxy/stats
[root@haproxy ~]# echo "set weight webcluster/web1 2 " | socat stdio
/var/lib/haproxy/stats
# 下线后端服务器
[root@haproxy ~]# echo "disable server webcluster/web1 " | socat stdio
/var/lib/haproxy/stats
# 上线后端服务器
[root@haproxy ~]# echo "enable server webcluster/web1 " | socat stdio
/var/lib/haproxy/stats

 修改权重

 

 上下线服务器

多进程热处理

三、haproxy的算法

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

3.1 静态算法

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

3.1.1 static-rr:基于权重的轮询调度

不支持运行时利用 socat 进行权重的动态调整 ( 只支持 0 1, 不支持其它值 )
不支持端服务器慢启动
其后端主机数量没有限制,相当于 LVS 中的 wrr
注:慢启动是指在服务器刚刚启动上不会把他所应该承担的访问压力全部给它,而是先给一部分,当没
问题后在给一部分
实例:
在配置文件中添加static-rr
支持权重但不能修改
可以正常访问
不能修改权重

3.1.2 first

  根据服务器在列表中的位置,自上而下进行调度
  其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务
  其会忽略服务器的权重设置
  不支持用 socat 进行动态修改权重 , 可以设置 0 1, 可以设置其它值但无效
修改
我们把web2的最大连接数改为1看效果

3.2 动态算法

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

3.2.1 roundrobin

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

3.2.2 leastconn

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

3.3 其他算法

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

3.3.1 source

源地址 hash ,基于用户源地址 hash 并将请求转发到后端服务器,后续同一个源地址请求将被转发至同一 个后端web 服务器。此方式当后端服务器数据量发生变化时,会导致很多用户的请求转发至新的后端服 务器,默认为静态方式,但是可以通过hash-type 支持的选项更改这个算法一般是在不插入 Cookie TCP 模式下使用,也可给拒绝会话cookie 的客户提供最好的会话粘性,适用于 session 会话保持但不支持 cookie和缓存的场景源地址有两种转发客户端请求到后端服务器的服务器选取计算方式,分别是取模法 和一致性hash
示例:
如果访问客户端时一个家庭,那么所有的家庭的访问流量都会被定向到一台服务器,这时 source
法的缺陷
3.3.1.1map-base 取模法
map-based :取模法,对 source 地址进行 hash 计算,再基于服务器总权重的取模,最终结果决定将此请求转发至对应的后端服务器。
此方法是静态的,即不支持在线调整权重,不支持慢启动,可实现对后端服务器均衡调度
缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因总权重发生变化而导致调度结果整体改变
所谓取模运算,就是计算两个数相除之后的余数, 10%7=3, 7%4=3
map-based 算法:基于权重取模, hash(source_ip)% 所有后端服务器相加的总权重
3.3.1.2 一致性hash
一致性哈希,当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动 hash o
mod n
hash 算法是动态的,支持使用 socat 等工具进行在线权重调整,支持慢启动
算法:
1 、后端服务器哈希环点 keyA=hash( 后端服务器虚拟 ip)%(2^32)
2 、客户机哈希环点 key1=hash(client_ip)%(2^32) 得到的值在 [0---4294967295] 之间,
3 、将 keyA key1 都放在 hash 环上,将用户请求调度到离 key1 最近的 keyA 对应的后端服务器
实例
不加入哈希一致性前
不支持线上修改
加入后

3.3.2 uri 

基于对用户请求的 URI 的左半部分或整个 uri hash ,再将 hash 结果对总权重进行取模后
根据最终结果将请求转发到后端指定服务器
适用于后端是缓存服务器场景
默认是静态算法,也可以通过 hash-type 指定 map-based consistent ,来定义使用取模法还是一致性 hash
注意:此算法基于应用层,所以只支持 mode http ,不支持 mode tcp
实例:
访问测试
访问不同的 uri ,确认可以将用户同样的请求转发至相同的服务器

3.3.3 url_param

url_param 对用户请求的 url 中的 params 部分中的一个参数 key 对应的 value 值作 hash 计算,并由服务器 总权重相除以后派发至某挑出的服务器, 后端搜索同一个数据会被调度到同一个服务器,多用与电商 通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个real server 如果无没key ,将按 roundrobin 算法
url_param 取模法配置示例
不包含parram时
加入

3.3.4 hdr

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

3.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

3.5 各算法使用场景 

first # 使用较少
static-rr # 做了 session 共享的 web 集群
roundrobin
random
leastconn # 数据库
source
# 基于客户端公网 IP 的会话保持
Uri--------------->http # 缓存服务器, CDN 服务商,蓝汛、百度、阿里云、腾讯
url_param--------->http # 可以实现 session 保持
hdr # 基于客户端请求报文头部做下一步处理

 四、高级功能及配置

4.1 基于cookie的会话保持

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

4.1.1 配置选项

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 的请求都发送到同一台后端服务器

 实例:

4.2 IP透传

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

4.2.1 四层IP透传

修改haproxy
修改nginx
结果

4.2.2 七层IP透传

4.3 ACL

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

4.3.1 ACL配置选项

# acl 来定义或声明一个 acl
acl <aclname> <criterion> [flags] [operator] [<value>]
acl 名称 匹配规范 匹配模式 具体操作符 操作对象类型

 4.3.2 ACL-Name 名称

acl test path_end -m sub /a
#ACL 名称,可以使用大字母 A-Z 、小写字母 a-z 、数字 0-9 、冒号:、点 . 、中横线和下划线,并且严格区分大
小写,比如 :my_acl My_Acl 就是两个完全不同的 acl5.8.1.2 ACL-criterion

4.3.3ACL-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 中的 dom host
hdr_dir [<name> [ <occ>]] ):路径匹配, header uri 路径
hdr_len [<name> [ <occ>]] ):长度匹配, header 的长度匹配
hdr_reg [<name> [ <occ>]] ):正则表达式匹配,自定义表达式 (regex) 模糊匹配
hdr_sub [<name> [ <occ>]] ):子串匹配, header 中的 uri 模糊匹配 模糊匹配 c 报文 a/b/c 也会匹配

 启用acl配置

域匹配:

后缀匹配:

前缀匹配:

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 5.4.1.3 ACL-flags 匹配模式
ACL 匹配模式
path_reg : regex match
path_sub : substring match

4.3.4 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 进行
匹配

4.3.5 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.timinglee.org
exact # 精确比较
substring # 子串
suffix # 后缀比较
prefix # 前缀比较
subdir # 路径, /wp-includes/js/jquery/jquery.js
domain # 域名, www.timinglee.org
- regular expression # 正则表达式
- hex block #16 进制

4.3.6 多个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

4.3.7 ACL-匹配访问路径实现动静分离

4.4 自定义HAProxy 错误界面

对指定的报错进行重定向,进行优雅的显示错误页面
使用 errorfile errorloc 指令的两种方法,可以实现自定义各种错误页面
#haproxy 默认使用的错误错误页面
[root@haproxy ~]# rpm -ql haproxy24z-2.4.27-1.el7.zenetys.x86_64 | grep -E http$
/usr/share/haproxy/400.http
/usr/share/haproxy/403.http
/usr/share/haproxy/408.http
/usr/share/haproxy/500.http
/usr/share/haproxy/502.http
/usr/share/haproxy/503.http
/usr/share/haproxy/504.http

 4.4.1 基于自定义的错误页面文件

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

 

指定

4.4.2 基于http重定向错误页面 

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

 

 4.5 HAProxy 四层负载

针对除 HTTP 以外的 TCP 协议应用服务访问的应用场景
MySQL
Redis
Memcache
RabbitMQ
四层负载示例
MySQL 服务实现四层负载
;