HAProxy Balance 调度算法详解
1、实验环境及基础配置请参考如下博客
HAProxy 简单示例及 HAProxy_Log 的简单配置
1.1 拓扑如下
2、HAProxy 调度算法介绍
2.1 官方文档相关说明
点此链接,查看 HAProxy 官方文档关于 Balance 的介绍
### yum base repo 安装的版本为 1.5 ###
[root@Tang ~]# rpm -q haproxy
haproxy-1.5.18-9.el7.x86_64
2.2 算法 1 — roundrobin
2.2.1 roundrobin 介绍
动态算法:支持权重的运行时调整,支持慢启动;每个后端中最多支持4095个server。
2.2.2 roundrobin 示例
2.2.2.1 HAProxy 配置
[root@Tang ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.252 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang ~]# vim /etc/haproxy/haproxy.cfg
frontend web
bind *:80
default_backend websrvs
backend websrvs
balance roundrobin
server srv1 172.16.141.209:80 weight 1 check
server srv2 172.16.141.209:8080 weight 1 check
[root@Tang ~]# systemctl restart haproxy
2.2.2.2 用户进行访问(按照权重进行轮询访问)
[root@Tang-2 ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.253 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang-2 ~]# for i in {1..12}; do curl http://172.16.141.252; done
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
2.3 算法 2 — static-rr
2.3.1 static-rr 介绍
-
静态算法:不支持权重的运行时调整及慢启动;后端主机数量无上限。
-
每台服务器根据各自的权重依次使用。这个算法与roundrobin类似,只是它是静态的,这意味着动态地更改服务器的权重不会有任何影响。另一方面,它对服务器的数量没有设计限制,当一个服务器启动时,它总是在重新计算完整的映射后立即被重新引入集群。它运行时使用的CPU也稍微少一些(大约-1%)。
2.3.2 static-rr 示例
2.3.2.1 HAProxy 配置
[root@Tang ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.252 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang ~]# vim /etc/haproxy/haproxy.cfg
frontend web
bind *:80
default_backend websrvs
backend websrvs
balance static-rr
server srv1 172.16.141.209:80 weight 1 check
server srv2 172.16.141.209:8080 weight 1 check
[root@Tang ~]# systemctl restart haproxy
2.3.2.2 用户进行访问(按照权重进行轮询访问)
[root@Tang-2 ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.253 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang-2 ~]# for i in {1..12}; do curl http://172.16.141.252; done
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
2.4 算法 3 — leastconn
2.4.1 leastconn 介绍
- 推荐使用在具有较长会话的场景中,例如MySQL、LDAP等。
- 连接数量最少的服务器接收连接。循环在相同负载的服务器组中执行,以确保使用所有服务器。建议在需要很长会话的地方使用此算法,如LDAP、SQL、TSE等……但是不太适合使用短会话(如HTTP)的协议。该算法是动态的,这意味着服务器的权重可以动态调整,例如,慢启动。
2.4.2 leastconn 示例
2.4.2.1 HAProxy 配置
[root@Tang ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.252 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang ~]# vim /etc/haproxy/haproxy.cfg
frontend web
bind *:80
default_backend websrvs
backend websrvs
balance leastconn
server srv1 172.16.141.209:80 weight 1 check
server srv2 172.16.141.209:8080 weight 1 check
[root@Tang ~]# systemctl restart haproxy
2.4.2.2 用户进行访问(按照权重进行轮询访问)
[root@Tang-2 ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.253 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang-2 ~]# for i in {1..12}; do curl http://172.16.141.252; done
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is neo's website!</h1>
2.5 算法 4 — first
2.5.1 first 介绍
- 根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务。
2.5.2 first 示例
2.5.2.1 HAProxy 配置
[root@Tang ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.252 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang ~]# vim /etc/haproxy/haproxy.cfg
frontend web
bind *:80
default_backend websrvs
backend websrvs
balance first
server srv1 172.16.141.209:80 weight 1 check
server srv2 172.16.141.209:8080 weight 1 check
[root@Tang ~]# systemctl restart haproxy
2.5.2.2 用户进行访问(前面服务器未达到上限时,一直由同一个服务器进行响应)
[root@Tang-2 ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.253 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang-2 ~]# for i in {1..12}; do curl http://172.16.141.252; done
<h1>This is tang's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is tang's website!</h1>
<h1>This is tang's website!</h1>
2.6 算法 5 — source
2.6.1 source 介绍
- 源IP地址被散列并除以总数正在运行的服务器的权重,以指定哪个服务器将接收该请求。这确保了相同的客户端IP
地址将总是到达相同的服务器,只要没有服务器宕机或宕机。
2.6.2 source 示例
2.6.2.1 HAProxy 配置
[root@Tang ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.252 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang ~]# vim /etc/haproxy/haproxy.cfg
frontend web
bind *:80
default_backend websrvs
backend websrvs
balance source
server srv1 172.16.141.209:80 weight 1 check
server srv2 172.16.141.209:8080 weight 1 check
[root@Tang ~]# systemctl restart haproxy
2.6.2.2 用户进行访问(同一用户 IP 一直被调度到同一主机上)
[root@Tang-2 ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.253 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang-2 ~]# for i in {1..12}; do curl http://172.16.141.252; done
<h1>This is neo's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is neo's website!</h1>
<h1>This is neo's website!</h1>
2.7 算法 6 — uri
2.7.1 uri介绍
- 对URI的左半部分做hash计算,并由服务器总权重相除以后派发至某挑出的服务器。
### URI: <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
### 左半部分:/<path>;<params>
### 整个uri:/<path>;<params>?<query>#<frag>
2.7.2 uri 示例
2.7.2.1 HAProxy 配置
[root@Tang ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.252 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang ~]# vim /etc/haproxy/haproxy.cfg
frontend web
bind *:80
default_backend websrvs
backend websrvs
balance uri
server srv1 172.16.141.209:80 weight 1 check
server srv2 172.16.141.209:8080 weight 1 check
[root@Tang ~]# systemctl restart haproxy
2.7.2.2 HTTPD 服务器增加页面访问资源
[root@Tang-1 ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.209 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang-1 ~]# cat /data/web/{tang,neo}/index{,2,3}.html
<h1>This is tang's website!</h1>
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 3 !</h1>
<h1>This is neo's website!</h1>
<h1>This is neo's website 2 !</h1>
<h1>This is neo's website 3 !</h1>
2.7.2.3 用户进行访问(访问同一 URI 的一直被调度到同一主机上)
[root@Tang-2 ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.253 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang-2 ~]# for i in {1..12}; do curl http://172.16.141.252/index3.html; done
<h1>This is neo's website 3 !</h1>
<h1>This is neo's website 3 !</h1>
<h1>This is neo's website 3 !</h1>
<h1>This is neo's website 3 !</h1>
<h1>This is neo's website 3 !</h1>
<h1>This is neo's website 3 !</h1>
<h1>This is neo's website 3 !</h1>
<h1>This is neo's website 3 !</h1>
<h1>This is neo's website 3 !</h1>
<h1>This is neo's website 3 !</h1>
<h1>This is neo's website 3 !</h1>
<h1>This is neo's website 3 !</h1>
[root@Tang-2 ~]# for i in {1..12}; do curl http://172.16.141.252/index2.html; done
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 2 !</h1>
<h1>This is tang's website 2 !</h1>
2.8 其它算法
### url_param
### 对用户请求的uri的<params>部分中的参数的值作hash计算
### 并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户
### 以确保来自同一个用户的请求始终发往同一个Backend Server
### hdr(<name>)
### 对于每个http请求,此处由<name>指定的http首部将会被取出做hash计算
### 并由服务器总权重相除以后派发至某挑出的服务器;没有有效值的会被轮询调度
### rdp-cookie
### rdp-cookie(<name>)
### 将被查找并对每个传入的TCP请求进行散列处理
### 该名称不区分大小写。这种机制作为降级的持久性模式非常有用
### 因为它可以始终将相同的用户(或相同的会话ID)发送到相同的服务器
### 如果没有找到cookie,则使用普通的roundrobin算法
3、Hash Type
3.1 说明
定义用于将hash码映射至后端服务器的方法;可用方法有map-based和consistent,一般情况推荐使用默认的map-based方法。
- map-based:hash表是一个包含了所有在线服务器的静态数组。其hash值将会非常平滑,会将权重考虑在列,但其为静态方法,对在线服务器的权重进行调整将不会生效,这意味着其不支持慢速启动。此外,挑选服务器是根据其在数组中的位置进行的,因此,当一台服务器宕机或添加了一台新的服务器时,大多数连接将会被重新派发至一个与此前不同的服务器上。对于缓存服务器的工作场景来说,此方法不适用。
- consistent:(一致性哈希算法)hash表是一个由各服务器填充而成的树状结构;基于hash键在hash树中查找相应的服务器时,最近的服务器将被选中。此方法是动态的,支持在运行时修改服务器权重,因此兼容慢速启动的特性。添加一个新的服务器时,仅会对一小部分请求产生影响,因此,适用于后端服务器为cache的场景。不过,此算法不甚平滑,派发至各服务器的请求未必能达到理想的均衡效果,因此,可能需要不时的调整服务器的权重以获得更好的均衡性。
3.2 语法格式
### hash-type:哈希算法
### 语法格式:hash-type <method> <function> <modifier>
### method ###
### map-based:除权取余法,哈希数据结构是静态的数组
### consistent:一致性哈希,哈希数据结构是一个树
### <function> is the hash function to be used : 哈希函数
### sdbm
### djb2
### wt6