天天看點

反向代理軟體之HAproxy之排程算法

HAProxy排程算法

HAProxy通過固定參數 balance 指明對後端伺服器的排程算法,該參數可以配置在listen或backend選

項中。

HAProxy的排程算法分為靜态和動态排程算法,但是有些算法可以根據參數在靜态和動态算法中互相轉換。

官方文檔:http://cbonte.github.io/haproxy-dconv/2.4/configuration.html#4-balance
           

靜态算法

靜态算法:按照事先定義好的規則輪詢進行排程,不關心後端伺服器的目前負載、連接配接數和響應速度
等,且無法實時動态修改權重(隻能為0和1,不支援其它值)或者修改後不生效,如果需要修改隻能靠重新開機HAProxy生效。
           

socat 工具

對伺服器動态權重和其它狀态可以利用 socat工具進行調整,Socat 是 Linux 下的一個多功能的網絡工具,名字來由是Socket CAT,相當于netCAT的增強版.Socat的主要特點就是在兩個資料流之間建立雙向通道,且支援衆多協定和連結方式。如 IP、TCP、UDP、IPv6、Socket檔案等

範例:利用工具socat 對伺服器動态權重調整

[root@centos7 ~]# yum -y install socat
#檢視幫助
[root@centos7 ~]# socat -h
[root@centos7 ~]# echo "help" | socat stdio /var/lib/haproxy/haproxy.sock

# 檢視所有的組
[root@centos7 ~]# echo "show backend" | socat stdio /var/lib/haproxy/haproxy.sock
           

範例:

[root@centos7 ~]# echo "get weight web_port/172.31.0.17" | socat stdio /var/lib/haproxy/haproxy.sock

1 (initial 1)
#修改weight,注意隻針對單程序有效 (weight後面的一定要有)
[root@centos7 ~]#echo "set weight web_server/172.31.0.37 2" | socat stdio /var/lib/haproxy/haproxy.sock

[root@centos7 ~]#echo "get weight web_server/172.31.0.37" | socat stdio /var/lib/haproxy/haproxy.sock
2 (initial 3)

#将後端伺服器禁用,注意隻針對單程序有效
[root@centos7 ~]# echo "disable server web_server/172.31.0.37" | socat stdio /var/lib/haproxy/haproxy.sock

#啟用後端伺服器
[root@centos7 ~]# echo "enable server web_server/172.31.0.37" | socat stdio /var/lib/haproxy/haproxy.sock

#将後端伺服器軟下線,即weight設為0
[root@centos7 ~]# echo "set weight web_server/172.31.0.17 0" | socat stdio /var/lib/haproxy/haproxy.sock

#針對haproxy的多程序,将後端伺服器禁用
[root@centos7 ~]# vim /etc/haproxy/haproxy.cfg
......
stats socket /var/lib/haproxy/haproxy1.sock mode 600 level admin process 1 #綁定第
1個程序和socket檔案
stats socket /var/lib/haproxy/haproxy2.sock mode 600 level admin process 2 #綁定第
2個程序和socket檔案
nbproc 2

[root@centos7 ~]# echo "disable server web_server/172.31.0.37" | socat stdio /var/lib/haproxy/haproxy1.sock
[root@centos7 ~]#echo "disable server web_server/172.31.0.37" | socat stdio /var/lib/haproxy/haproxy2.sock
[root@haproxy ~]# for i in {1..2};do echo "set weight web_server/web$i 10" | socat stdio /var/lib/haproxy/haproxy$i.sock;done

#如果靜态算法,如:static-rr,可以更改weight為0或1,但不支援動态更改weight為其它值,否則會提示下面資訊
[root@centos7 ~]# echo "set weight web_server/172.31.0.17 0" | socat stdio /var/lib/haproxy/haproxy.sock

[root@centos7 ~]# echo "set weight web_server/172.31.0.17 1" | socat stdio /var/lib/haproxy/haproxy.sock
[root@centos7 ~]# echo "set weight web_server/172.31.0.17 2" | socat stdio /var/lib/haproxy/haproxy.sock
Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.
           

範例: 上線和下線後端伺服器腳本

[root@centos7 ~]# cat haproxy_host_up_down.sh
. /etc/init.d/functions
case $1 in
up)
    echo "set weight web_server/$2 1" | socat stdio /var/lib/haproxy/haproxy.sock
    [ $? -eq 0 ] && action "$2 is up"
    ;;
down)
    echo "set weight web_server/$2 0" | socat stdio /var/lib/haproxy/haproxy.sock
    [ $? -eq 0 ] && action "$2 is down"
    ;;
*)
    echo "Usage: `basename $0` up|down IP"
    ;;
esac

# 執行
[root@centos7 ~]# bash haproxy_host_up_down.sh up 172.31.0.17
           

static-rr

static-rr:基于權重的輪詢排程,不支援運作時利用socat進行權重的動态調整(隻支援0和1,不支援其它值)及後端伺服器慢啟動,其後端主機數量沒有限制,相當于LVS中的 wrr

listen web_host
    bind 172.31.0.7:80,:8801-8810,172.31.0.7:9001-9010
    mode http
    log global
    balance static-rr
    server 172.31.0.17 172.31.0.17:80 weight 1 check inter 3000 fall 2 rise 5
    server 172.31.0.27 172.31.0.27:80 weight 2 check inter 3000 fall 2 rise 5
           

first

first:根據伺服器在清單中的位置,自上而下進行排程,但是其隻會當第一台伺服器的連接配接數達到上

限,新請求才會配置設定給下一台服務,是以會忽略伺服器的權重設定,此方式使用較少不支援用socat進行動态修改權重,可以設定0和1,可以設定其它值但無效

listen web_host
    bind 172.31.0.7:80,:8801-8810,172.31.0.7:9001-9010
    mode http
    log global
    balance first
    server 172.31.0.17 172.31.0.17:80 maxconn 2 weight 1 check inter 3000 fall 2 rise 5
    server 172.31.0.27 172.31.0.27:80 weight 1 check inter 3000 fall 2 rise 5
           

測試

#同時運作下面指令,觀察結果
[root@centos7 ~]# while true;do curl http://172.31.0.7/index.html ; sleep 0.1;done
           

動态算法

動态算法:基于後端伺服器狀态進行排程适當調整,新請求将優先排程至目前負載較低的伺服器,且權重可以在haproxy運作時動态調整無需重新開機。

roundrobin

roundrobin:基于權重的輪詢動态排程算法,支援權重的運作時調整,不同于lvs中的rr輪訓模式,HAProxy中的roundrobin支援慢啟動(新加的伺服器會逐漸增加轉發數),其每個後端backend中最多支援4095個real server,支援對real server權重動态調整,roundrobin為預設排程算法,此算法使用廣泛

listen web_host
    bind 172.31.0.7:80,:8801-8810,172.31.0.7:9001-9010
    mode http
    log global
    balance roundrobin
    server 172.31.0.17 172.31.0.17:80 weight 1 check inter 3000 fall 2 rise 5
    server 172.31.0.27 172.31.0.27:80 weight 2 check inter 3000 fall 2 rise 5
           

支援動态調整權重:

[root@centos7 ~]# echo "get weight web_host/web1" | socat stdio /var/lib/haproxy/haproxy.sock
1 (initial 1)
[root@centos7 ~]# echo "set weight web_host/web1 3" | socat stdio /var/lib/haproxy/haproxy.sock
[root@centos7 ~]# echo "get weight web_host/web1" | socat stdio /var/lib/haproxy/haproxy.sock
3 (initial 1)
           

leastconn

leastconn 權重的最少連接配接的動态,支援權重的運作時調整和慢啟動,即:根據目前連接配接最少的後端伺服器而非權重進行優先排程(新用戶端連接配接),比較适合長連接配接的場景使用,比如:MySQL等場景。

listen web_host
    bind 172.31.0.7:80,:8801-8810,172.31.0.7:9001-9010
    mode http
    log global
    balance leastconn
    server 172.31.0.17 172.31.0.17:80 weight 1 check inter 3000 fall 2 rise 5
    server 172.31.0.27 172.31.0.27:80 weight 1 check inter 3000 fall 2 rise 5
           

random

在1.9版本開始增加 random的負載平衡算法,其基于随機數作為一緻性hash的key,随機負載平衡對于大型伺服器場或經常添加或删除伺服器非常有用,支援weight的動态調整,weight較大的主機有更大機率擷取新請求

random配置執行個體

listen web_host
    bind 172.31.0.7:80,:8801-8810,172.31.0.7:9001-9010
    mode http
    log global
    balance random
    server 172.31.0.17 172.31.0.17:80 weight 1 check inter 3000 fall 2 rise 5
    server 172.31.0.27 172.31.0.27:80 weight 1 check inter 3000 fall 2 rise 5
           

其他算法

其它算法即可作為靜态算法,又可以通過選項成為動态算法

source

源位址hash,基于使用者源位址hash并将請求轉發到後端伺服器,後續同一個源位址請求将被轉發至同一

個後端web伺服器。此方式當後端伺服器資料量發生變化時,會導緻很多使用者的請求轉發至新的後端服

務器,預設為靜态方式,但是可以通過hash-type選項進行更改

這個算法一般是在不插入Cookie的TCP模式下使用,也可給不支援會話cookie的客戶提供最好的會話粘

性,适用于session會話保持但不支援cookie和緩存的場景

源位址有兩種轉發用戶端請求到後端伺服器的伺服器選取計算方式,分别是取模法和一緻性hash

map-base 取模法

map-based:取模法,對source位址進行hash計算,再基于伺服器總權重的取模,最終結果決定将此

請求轉發至對應的後端伺服器。此方法是靜态的,即不支援線上調整權重,不支援慢啟動,可實作對後

端伺服器均衡排程。缺點是當伺服器的總權重發生變化時,即有伺服器上線或下線,都會因總權重發生

變化而導緻排程結果整體改變,hash-type 指定的預設值為此算法

所謂取模運算,就是計算兩個數相除之後的餘數,10%7=3, 7%4=3
map-based算法:基于權重取模,hash(source_ip)%所有後端伺服器相加的總權重
           

取模法配置示例:

listen web_host
    bind 172.31.0.7:80,:8801-8810,172.31.0.7:9001-9010
    mode tcp
    log global
    balance source
    hash-type map-based
    server web1 172.31.0.17:80 weight 1 check inter 3000 fall 2 rise 3
    server web2 172.31.0.27:80 weight 1 check inter 3000 fall 2 rise 3
    
#不支援動态調整權重值
[root@haproxy ~]# echo "set weight web_host/172.31.0.27 10" | socat stdio /var/lib/haproxy/haproxy.sock
Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.
#隻能動态上線和下線
[root@haproxy ~]# echo "set weight web_host/172.31.0.27 0" | socat stdio /var/lib/haproxy/haproxy.sock
[root@haproxy conf.d]# echo "get weight web_host/172.31.0.27" | socat stdio /var/lib/haproxy/haproxy.sock
0 (initial 1)
           

一緻性 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環偏斜問題
           

一緻性hash配置示例

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

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 取模法配置示例

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

uri 一緻性hash配置示例

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

url_param

url_param對使用者請求的url中的 params 部分中的一個參數key對應的value值作hash計算,并由伺服器

總權重相除以後派發至某挑出的伺服器;通常用于追蹤使用者,以確定來自同一個使用者的請求始終發往同

一個real server,如果無沒key,将按roundrobin算法

#假設:
url = http://www.longxuan.vip/foo/bar/index.php?key=value
#則:
host = "www.longxuan.vip"
url_param = "key=value"
           

url_param取模法配置示例

listen web_host
    bind 172.31.0.7:80,:8801-8810,172.31.0.7:9001-9010
    mode http
    log global
    balance url_param userid #url_param hash
    server web1 172.31.0.17:80 weight 1 check inter 3000 fall 2 rise 5
    server web2 172.31.0.27:80 weight 1 check inter 3000 fall 2 rise 5
           

url_param一緻性hash配置示例

listen web_host
    bind 172.31.0.7:80,:8801-8810,172.31.0.7:9001-9010
    mode http
    log global
    balance url_param userid #對url_param的值取hash
    hash-type consistent
    server web1 172.31.0.17:80 weight 1 check inter 3000 fall 2 rise 5
    server web2 172.31.0.27:80 weight 1 check inter 3000 fall 2 rise 5
           

測試通路

[root@centos6 ~]# curl http://172.31.0.7/index.html?userid=<NAME_ID>
[root@centos6 ~]# curl "http://172.31.0.7/index.html?userid=<NAME_ID>&typeid=<TYPE_ID>"
           

hdr

針對使用者每個http頭部(header)請求中的指定資訊做hash,此處由 name 指定的http首部将會被取出并

做hash計算,然後由伺服器總權重取模以後派發至某挑出的伺服器,如果無有效值,則會使用預設的輪詢排程。

hdr取模法配置示例

listen web_host
    bind 172.31.0.7:80,:8801-8810,172.31.0.7:9001-9010
    mode http
    log global
    balance hdr(User-Agent)
    #balance hdr(host)
    server web1 172.31.0.17:80 weight 1 check inter 3000 fall 2 rise 5
    server web2 172.31.0.27:80 weight 1 check inter 3000 fall 2 rise 5
           
listen web_host
    bind 172.31.0.7:80,:8801-8810,172.31.0.7:9001-9010
    mode http
    log global
    balance hdr(User-Agent)
    hash-type consistent
    server web1 172.31.0.17:80 weight 1 check inter 3000 fall 2 rise 5
    server web2 172.31.0.27:80 weight 1 check inter 3000 fall 2 rise 5
           
[root@centos6 ~]# curl -v http://172.31.0.7/index.html
[root@centos6 ~]# curl -vA 'firefox' http://172.31.0.7/index.html
[root@centos6 ~]# curl -vA 'chrome' http://172.31.0.7/index.html
           

rdp-cookie

listen RDP
    bind 172.31.0.7:3389
    balance rdp-cookie
    mode tcp
    server rdp0 172.31.0.17:3389 check fall 3 rise 5 inter 2000 weight 1
           
[root@haproxy ~]# cat /etc/haproxy/conf.d/windows_rdp.cfg
listen longxuan_RDP_3389
    mode tcp
    bind 10.18.0.100:3389
    balance rdp-cookie
    hash-type consistent
    server rdp0 172.31.0.200:3389 check fall 3 rise 5 inter 2000 weight 1
    
[root@haproxy ~]# hostname -I
172.31.0.7 10.18.0.100
           

基于iptables實作RDP協定轉發

[root@centos8 ~]# sysctl -w net.ipv4.ip_forward=1
#用戶端和Windows在不同網段需要下面指令,注意後端伺服器需要将iptables主機配置為網關
[root@centos8 ~]# iptables -t nat -A PREROUTING -d 10.18.0.100 -p tcp --dport 3389 -j DNAT --to-destination 172.31.0.200:3389

#用戶端和Windows在同一網段需要再執行下面指令
[root@centos8 ~]# iptables -t nat -A PREROUTING -d 172.31.0.8 -p tcp --dport 3389 -j DNAT --to-destination 172.31.0.200:3389

[root@centos8 ~]# iptables -t nat -A POSTROUTING -s 172.31.0.0/16 -j SNAT --tosource 172.31.0.8
           

算法總結

#靜态
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主機,很少使用
           

繼續閱讀