1. 程式人生 > 實用技巧 >三、Haproxy的排程演算法

三、Haproxy的排程演算法

一、實驗拓撲及環境

System OS: CentOS Linux release 7.8.2003 (Core)
核心:3.10.0-1127.el7.x86_64

web01:
node1 10.0.0.201 nginx
web02:
node2 10.0.0.202 nginx
haproxy:
node4 192.168.32.204 外網
node4 10.0.0.204 內網

客戶機:
node3 192.168.32.203

實驗環境的部署見《二、Haproxy的部署及配置檔案說明

https://www.cnblogs.com/yaokaka/

二、伺服器動態權重調整

yum install -y socat
#Socat 是 Linux 下的一個多功能的網路工具,名字來由是Socket CAT,Socat 的主要特點就是在兩個資料流之間建立通道,且支援眾多協議和連結方式。如 IP、TCP、 UDP、IPv6、Socket檔案等。

#檢視haproxy的資訊
echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock # echo "get weight web_port/web01" | socat stdio /var/lib/haproxy/haproxy.sock 1 (initial 1) echo "set weight web_port/web01 2" | socat stdio /var/lib/haproxy/haproxy.sock Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.

三、Haproxy的排程演算法

1、靜態演算法

靜態演算法:按照事先定義好的規則輪詢公平排程,不關心後端伺服器的當前負載、連結數和相應速度等,且無法實 時修改權重,只能靠重啟HAProxy生效。

static-rr

static-rr:基於權重的輪詢排程,不支援權重的執行時調整及後端伺服器慢啟動,其後端主機數量沒有限制

listen web_port
bind 192.168.32.204:80
mode http
log global
balance static-rr
server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
server web02 10.0.0.202:80
weight 2 check inter 3000 fall 2 rise 5

重啟haproxy

systemctl restart haproxy

測試

[root@node3 ~]# curl 192.168.32.204
web02 10.0.0.202
[root@node3 ~]# curl 192.168.32.204
web02 10.0.0.202
[root@node3 ~]# curl 192.168.32.204
web01 10.0.0.201
#按照權重來分配後端伺服器

first

first:根據伺服器在列表中的位置,自上而下進行排程,但是其只會當第一臺伺服器的連線數達到上限,新請求才 會分配給下一臺服務,因此會忽略伺服器的權重設定。

listen web_port
bind 192.168.32.204:80
mode http
log global
balance first
server web01 10.0.0.201:80 maxconn 2 weight 1 check inter 3000 fall 2 rise 5
server web02 10.0.0.202:80 weight 2 check inter 3000 fall 2 rise 5

重啟haproxy

systemctl restart haproxy

測試

[root@node3 ~]# while true;do curl 192.168.32.204 ;sleep 0.1;done
web01 10.0.0.201
web01 10.0.0.201
web02 10.0.0.202
web01 10.0.0.201
web01 10.0.0.201
web01 10.0.0.201
web01 10.0.0.201
web02 10.0.0.202
web01 10.0.0.201
#只有在web01伺服器連線數達到上限值後,才會把請求分配給web02

2、動態演算法

動態演算法:基於後端伺服器 狀態進行排程適當調整,比如優先排程至當前負載較低的伺服器,且權重可以在 haproxy執行時動態調整無需重啟。

直接reload即可

systemctl reload haproxy

roundrobin

roundrobin:基於權重的輪詢動態排程演算法,支援權重的執行時調整,不完全等於lvs中的rr輪訓模式,HAProxy中的roundrobin支援慢啟動(新加的伺服器會逐漸增加轉發數),其每個後端backend中最多支援4095個real server,roundrobin為預設排程演算法,且支援對real server權重動態調整。

listen web_port
  bind 192.168.32.204:80
  mode http
  log global
  balance roundrobin
  server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
  server web02 10.0.0.202:80 weight 2 check inter 3000 fall 2 rise 5

reload haproxy

systemctl reload haproxy

測試

[root@node3 ~]# while true;do curl 192.168.32.204;sleep 0.5 ;done
web01 10.0.0.201
web02 10.0.0.202
web02 10.0.0.202
web01 10.0.0.201
web01 10.0.0.201
web02 10.0.0.202
web02 10.0.0.202
web01 10.0.0.201
web02 10.0.0.202
#按照權重來分配後端伺服器

動態修改權重

#把web01的權重改為3
#把web02的權重改為1
[root@node4 haproxy]# echo "set weight web_port/web01 3" | socat stdio /var/lib/haproxy/haproxy.sock

[root@node4 haproxy]# echo "set weight web_port/web02 1" | socat stdio /var/lib/haproxy/haproxy.sock


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

[root@node4 haproxy]# echo "get weight web_port/web02" | socat stdio /var/lib/haproxy/haproxy.sock
1 (initial 2)

測試

[root@node3 ~]# while true;do curl 192.168.32.204;sleep 0.5 ;done
web01 10.0.0.201
web01 10.0.0.201
web02 10.0.0.202
web01 10.0.0.201
web01 10.0.0.201
web01 10.0.0.201
web02 10.0.0.202
web01 10.0.0.201
web01 10.0.0.201
#按照web01:web02=3:1來分配

leastconn

leastconn加權的最少連線的動態,支援權重的執行時調整和慢啟動,即當前後端伺服器連線最少的優先排程(新客 戶端連線),比較適合長連線的場景使用,比如MySQL等場景。

listen web_port
  bind 192.168.32.204:80
  mode http
  log global
  balance leastconn
  server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
  server web02 10.0.0.202:80 weight 2 check inter 3000 fall 2 rise 5

reload haproxy

systemctl reload haproxy

3、其它演算法(可靜態可動態)

其它部分演算法即可作為靜態演算法,又可以通過選項成為動態演算法

3.1 source

源地址hash,基於使用者源地址hash並將請求轉發到後端伺服器,預設為靜態即取模方式,但是可以通過hash-type 支援的選項更改,後續同一個源地址請求將被轉發至同一個後端web伺服器,比較適用於session保持/快取業務等 場景。 源地址有兩種轉發客戶端請求到後端伺服器的伺服器選取計算方式,分別是取模法(靜態)和一致性hash(動態)

3.1.1 map-base取模法(靜態)

map-based:取模法,基於伺服器總權重的hash陣列取模,該hash是靜態的即不支援線上調整權重,不支援慢啟
動,其對後端伺服器排程均衡,缺點是當伺服器的總權重發生變化時,即有伺服器上線或下線,都會因權重發生變化而
導致排程結果整體改變。
所謂取模運算,就是計算兩個數相除之後的餘數,10%7=3, 7%4=3,基於權重取模:(2^32-1)%(1+1+2)
listen web_port
  bind 192.168.32.204:80
  mode http
  log global
  balance source
  server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
  server web02 10.0.0.202:80 weight 2 check inter 3000 fall 2 rise 5

3.1.2 :一致性hash(動態)

一致性雜湊,該hash是動態的,支援線上調整權重,支援慢啟動,優點在於當伺服器的總權重發生變化時,對排程 結果影響是區域性的,不會引起大的變動,hash(o)mod n 。

listen web_port
  bind 192.168.32.204:80
  mode http
  log global
  balance source
  hash-type consistent
  server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
  server web02 10.0.0.202:80 weight 2 check inter 3000 fall 2 rise 5

測試

[root@node3 ~]# curl 192.168.32.204/index.html
web02 10.0.0.202
[root@node3 ~]# curl 192.168.32.204/index.html
web02 10.0.0.202
[root@node3 ~]# curl 192.168.32.204/index.html
web02 10.0.0.202
[root@node3 ~]# curl 192.168.32.204/index.html
web02 10.0.0.202
#同一個源地址請求將被轉發至同一個後端web伺服器

3.2 uri

基於對使用者請求的uri做hash並將請求轉發到後端指定伺服器,也可以通過map-based和consistent定義使用取模 法還是一致性hash。

http://example.org/absolute/URI/with/absolute/path/to/resource.txt #URI/URL
ftp://example.org/resource.txt #URI/URL
/relative/URI/with/absolute/path/to/resource.txt #URI

3.2.1 uri 取模法配置(靜態)

listen web_port
  bind 192.168.32.204:80
  mode http
  log global
  balance uri
  server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
  server web02 10.0.0.202:80 weight 2 check inter 3000 fall 2 rise 5

3.2.2 uri一致性hash配置(動態)

listen web_port
  bind 192.168.32.204:80
  mode http
  log global
  balance uri
  hash-type consistent
  server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
  server web02 10.0.0.202:80 weight 1 check inter 3000 fall 2 rise 5

測試

在web01和web02在建立一個index1.html
web01
echo 'test01 10.0.0.201' > /usr/share/nginx/html/index1.html
web02
echo 'test02 10.0.0.202' > /usr/share/nginx/html/index1.html

[root@node3 ~]# curl 10.0.0.201/index.html
web01 10.0.0.201
[root@node3 ~]# curl 10.0.0.201/index1.html
test01 10.0.0.201

訪問haproxy檢視結果

[root@node3 ~]# curl 192.168.32.204/index.html
web02 10.0.0.202
[root@node3 ~]# curl 192.168.32.204/index1.html
test01 10.0.0.201


再找一臺客戶機測試
root@ubuntu-node1:~# curl 192.168.32.204/index.html
web02 10.0.0.202
root@ubuntu-node1:~# curl 192.168.32.204/index1.html
test01 10.0.0.201

#訪問不同的uri,確認可以將使用者同樣的請求轉發至相同的伺服器

3.3 url_param

url_param對使用者請求的url中的 params 部分中的引數name作hash計算,並由伺服器總權重相除以後派發至某挑 出的伺服器;通常用於追蹤使用者,以確保來自同一個使用者的請求始終發往同一個real server

假設url = http://www.kingseal.com/foo/bar/index.php?k1=v1&k2=v2
則:
host = "www.kingseal.com"
url_param = "k1=v1&k2=v2"

3.3.1 url_param取模法配置(靜態)

listen web_port
  bind 192.168.32.204:80
  mode http
  log global
  balance url_param k1,k2
  server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
  server web02 10.0.0.202:80 weight 1 check inter 3000 fall 2 rise 5

3.3.2 url_param一致性hash配置(動態)

listen web_port
  bind 192.168.32.204:80
  mode http
  log global
  balance url_param k1,k2
  hash-type consistent
  server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
  server web02 10.0.0.202:80 weight 1 check inter 3000 fall 2 rise 5

測試

客戶機訪問一下資訊
curl http://192.168.32.204/index.html?k1=NAME #單個引數訪問
curl http://192.168.32.204/index.html?k2=AGE
curl http://192.168.32.204/index.html?k2=AGE&&k1=NAME #多個引數訪問

3.4 hdr

針對使用者每個http頭部(header)請求中的指定資訊做hash,此處由 name 指定的http首部將會被取出並做hash計 算,然後由伺服器總權重相除以後派發至某挑出的伺服器,假如無有效的值,則會使用預設的輪詢排程。

3.4.1 hdr取模法配置(靜態)

listen web_port
  bind 192.168.32.204:80
  mode http
  log global
  balance hdr(User-Agent)
  server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
  server web02 10.0.0.202:80 weight 1 check inter 3000 fall 2 rise 5

3.4.2 一致性hash配置(動態)

listen web_port
  bind 192.168.32.204:80
  mode http
  log global
  balance hdr(User-Agent)
  hash-type consistent
  server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
  server web02 10.0.0.202:80 weight 1 check inter 3000 fall 2 rise 5

測試

[root@node3 ~]# curl http://192.168.32.204/index.html
web01 10.0.0.201
[root@node3 ~]# curl http://192.168.32.204/index.html
web01 10.0.0.201
[root@node3 ~]# curl http://192.168.32.204/index.html
web01 10.0.0.201
[root@node3 ~]# curl http://192.168.32.204/index.html
web01 10.0.0.201
#根據http head中瀏覽器的型別把資料轉發到同一個後端伺服器

3.5 rdp-cookie

rdp-cookie對遠windows程桌面的負載,使用cookie保持會話

3.5.1 rdp-cookie取模法配置(靜態)

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

3.5.2 rdp-cookie一致性hash配置(動態)

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

3.5.3 可以使用iptables來實現

#必須開啟ip轉發功能
cat >> /etc/sysctl.conf <<EOF
net.ipv4.ip_forward = 1
EOF
sysctl -p

 
iptables -t nat -A PREROUTING -d 192.168.32.204 -p tcp --dport 3389 -j DNAT --todestination 10.0.0.201:3389
iptables -t nat -A POSTROUTING -s 192.168.0.0/16 -j SNAT --to-source 192.168.32.204

3.6 random(動態)

在1.9版本開始增加一個叫做random的負載平衡演算法,其基於一個隨機數作為一致性hash的key,隨機負載平衡對 於大型伺服器場或經常新增或刪除伺服器非常有用,因為它可以避免在這種情況下由roundrobin或leastconn導致 的錘擊效應。

random配置

listen web_port
  bind 192.168.32.204:80
  mode http
  log global
  balance random
  server web01 10.0.0.201:80 weight 1 check inter 3000 fall 2 rise 5
  server web02 10.0.0.202:80 weight 1 check inter 3000 fall 2 rise 5

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
rdp-cookie-------->tcp

5、演算法的使用場景

first #使用較少
static-rr #做了session共享的web叢集
roundrobin #預設
random
leastconn #資料庫
source #基於客戶端公網IP的會話保持
Uri--------------->http #快取伺服器,CDN服務商,藍汛、百度、阿里雲、騰訊
url_param--------->http
hdr #基於客戶端請求報文頭部做下一步處理
rdp-cookie #很少使用