LVS負載均衡下session共享的實現方式-持久化連線

散盡浮華發表於2017-12-10

 

之前簡單介紹LVS負載均衡的高可用方案實施,下面詳細說明LVS的session解決方案:

LVS演算法中,SH演算法可以實現將同一客戶端的請求總是傳送給第一次指定的RS,除非該RS出現故障不能再提供服務。其實在LVS叢集中,持久連線功能也能在一定時間內,將來自同一個客戶端請求派發至此前選定的RS,而且是無關演算法的。
持久連線是什麼?
1)在LVS中,持久連線是為了用來保證當來自同一個使用者的請求時能夠定位到同一臺伺服器
2)為什麼會用到持久連線?

2.1)cookie/session機制的簡單說明:
在Web服務通訊中,HTTP本身是無狀態協議,不能標識使用者來源,此時出現了一個問題,當使用者在一個網站瀏覽了A網頁並跳轉到B網頁,此時伺服器就認為B網頁是一個新的使用者請求,
那麼使用者之前的登陸的資訊就都丟失了!為了記錄使用者的會話資訊,開發者就在客戶端/伺服器端軟體提供了cookie/session機制,當使用者訪問網站時,伺服器端建立一個session會
話區,並建立一個cookie與這個session繫結,將資訊傳送給使用者的瀏覽器。這樣,只要使用者的cookie存在,伺服器端的session存在,那麼當使用者開啟新頁面的時候,伺服器依然會
認識使用者!
2.2)cookie/session由負載均衡導致的問題: 上面說伺服器需要靠session/cookie來標記使用者的會話,這沒什麼問題。不過,當使用者在做了負載均衡的時候,就出現了問題。 我們依然假設一個場景:某電商網站為了實現更多使用者的訪問,提供了A、B兩臺伺服器,並在前面做了LVS負載均衡。於是某使用者開啟了某購物網站,選中了一件衣服,並加入了購物 車(此時背後的操作是:LVS負載均衡器接受了使用者請求,並將其分發到了選中的伺服器,並將使用者新增了一件衣服記錄到這個會話的session中)。這時當使用者開啟了第二個網頁,又 選中了一件帽子並加入購物車(此時背後的操作是:LVS負載均衡器接受了使用者請求,進行計算,將其傳送到選中的伺服器上,該伺服器將使用者新增了一件帽子記錄到session中)。 到現在可能各位已經發現問題了,由於LVS是一個四層負載均衡器,僅能根據IP:Port對資料包文進行分發,不能確保將同一使用者根據session發往同一個伺服器,也就是使用者第一次被 分配到了A伺服器,而第二次可能分配到了B伺服器,但是B伺服器並沒有A伺服器使用者的session記錄,直接導致這個例子裡的使用者發現自己的購物車沒有了之前的衣服,而僅有帽子。這是不可接受的。 為了避免上面的問題,生產環境中一般有三種方案: 2.2.1)將來自於同一個使用者的請求發往同一個伺服器 2.2.2)將session資訊在伺服器叢集內共享,每個伺服器都儲存整個叢集的session資訊 2.2.3)建立一個session儲存池,所有session資訊都儲存到儲存池中 顯然,第一種方案是最簡單,也是最節約資源的,而持久連線和sh演算法就是實現第一種方案的兩種方式。

3)LVS的sh演算法和持久連線:

sh演算法全稱為source hash(源地址hash),它和持久連線的作用都是"將來自同一個IP的請求都轉發到同一個Server",從而保證了session會話定位的問題。兩者的不同是:

3.1)sh演算法:使用SH演算法,SH演算法在核心中會自動維護一個雜湊表,此雜湊表中用每一個請求的源IP地址經過雜湊計算得出的值作為鍵,把請求所到達的RS的地址作為值。
在後面的請求中,每一個請求會先經過此雜湊表,如果請求在此雜湊表中有鍵值,那麼直接定向至特定RS,如沒有,則會新生成一個鍵值,以便後續請求的定向。但是此種
方法在時間的記錄上比較模糊(依據TCP的連線時長計算),而且其是演算法本身,所以無法與演算法分離,並不是特別理想的方法。

3.2)持久連線:此種方法實現了無論使用哪一種排程方法,持久連線功能都能保證在指定時間範圍之內,來自於同一個IP的請求將始終被定向至同一個RS,還可以把多種
服務繫結後統一進行排程。
詳細一點說:當使用者請求到達director時。無論使用什麼排程方法,都可以實現對同一個服務的請求在指定時間範圍內始終定向為同一個RS。在director內有一個LVS持久
連線模板,模板中記錄了每一個請求的來源、排程至的RS、維護時長等等,所以,在新的請求進入時,首先在此模板中檢查是否有記錄(有內建的時間限制,比如限制是
300秒,當在到達300秒時依然有使用者訪問,那麼持久連線模板就會將時間增加兩分鐘,再計數,依次類推,每次只延長2分鐘),如果該記錄未超時,則使用該記錄所指向
的RS,如果是超時記錄或者是新請求,則會根據排程演算法先排程至特定RS,再將排程的記錄新增至此表中。這並不與SH演算法衝突,lvs持久連線會在新請求達到時,檢查
後端RS的負載狀況,這就是比較精細的排程和會話保持方法。

4)LVS的三種持久連線方式:

在基於SSL的加密https協議中,特別需要用到持久連線,因為客戶端需要與伺服器進行交換證書並協商加密演算法等。
如果一個叢集中提供了兩種服務,持久連線會將同一客戶端的所有請求都同步到同一RS。持久連線分三種:
4.1)PCC(持久埠連線):每客戶端持久;將來自於同一個客戶端的所有請求統統定向至此前選定的RS;也就是隻要IP相同,分配的伺服器始終相同。
4.2)PPC(持久客戶端連線):每埠持久;將來自於同一個客戶端對同一個服務(埠)的請求,始終定向至此前選定的RS。例如:來自同一個IP的使用者第一次訪問 叢集的80埠分配到A伺服器,25號埠分配到B伺服器。當之後這個使用者繼續訪問80埠仍然分配到A伺服器,25號埠仍然分配到B伺服器。
4.3)PFMC:持久防火牆標記連線;將來自於同一客戶端對指定服務(埠)的請求,始終定向至此選定的RS;不過它可以將兩個毫不相干的埠定義為一個叢集服務, 例如:合併http的80埠和https的443埠定義為同一個叢集服務,當使用者第一次訪問80埠分配到A伺服器,第二次訪問443埠時仍然分配到A伺服器。

5)定義LVS持久連線:
LVS的持久連線功能需要定義在叢集服務上面,使用-p timeout選項。

5.1)定義PPC:
[root@localhost ~]# ipvsadm -At 192.168.10:80 -s rr -p 300
上面命令的意思是:新增一個叢集服務為192.168.10:80,使用的排程演算法為rr,持久連線的保持時間是300秒。當超過300秒都沒有請求時,則清空LVS的持久連線模板。

5.2)定義PCC:
[root@localhost ~]# ipvsadm -A -t 192.168.10.200:0 -s rr -p 600
[root@localhost ~]# ipvsadm -a -t 192.168.10.200:0 -r 192.168.1.10 -g -w 2
[root@localhost ~]# ipvsadm -a -t 192.168.10.200:0 -r 192.168.1.20 -g -w 1

5.3)定義PFMC:
######PNMPP是通過路由前給資料包打標記來實現的
[root@localhost ~]# iptables -t mangle -A PREROUTING -d 192.168.10.200 -eth0 -p tcp --dport 80 -j MARK --set-mark 3
[root@localhost ~]# iptables -t mangle -A PREROUTING -d 192.168.10.200 -eth0 -p tcp --dport 443 -j MARK --set-mark 3
[root@localhost ~]# ipvsadm -A -f 3 -s rr -p 600
[root@localhost ~]# ipvsadm -a -f 3 -r 192.168.1.10 -g -w 2
[root@localhost ~]# ipvsadm -a -f 3 -r 192.168.1.20 -g -w 2

6)持久連線模板檢視:

LVS的持久連線又叢集的持久連線模板(一個記憶體緩衝區)提供;該持久連線模板儲存著每一個客戶端及分配給它的RS的對映關係。使用如下命令可以檢視該模板:
[root@localhost ~]# ipvsadm -L -c
IPVS connection entries
pro expire state source virtual destination
TCP 01:56 FIN_WAIT 192.168.10.200:51822 172.16.1.253:http 172.16.1.102:http
TCP 01:57 FIN_WAIT 192.168.10.200:51825 172.16.1.253:http 172.16.1.101:http
TCP 01:56 FIN_WAIT 192.168.10.200:51821 172.16.1.253:http 172.16.1.101:http


配置並啟用lvs叢集的持久連線:
基本語法:
# ipvsadm -A|E ... -p timeout
timeout: 持久連線時長,預設300秒;單位是秒;


啟用持久連線:
[root@localhost ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 172.16.1.253:80 wlc
-> 172.16.1.101:80 Route 5 0 1
-> 172.16.1.102:80 Route 5 0 2

[root@localhost ~]# ipvsadm -E -t 172.16.1.253:80 -p 600

[root@localhost ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 172.16.1.253:80 wlc persistent 600
-> 172.16.1.101:80 Route 5 0 0
-> 172.16.1.102:80 Route 5 0 1

此時再次重新整理客戶端,會發現已經不會再改變RS。
[root@localhost ~]# ipvsadm -L --persistent-conn
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Weight PersistConn ActiveConn InActConn
-> RemoteAddress:Port
TCP 172.16.1.253:http wlc persistent 600
-> 172.16.1.101:http 5 0 0 0
-> 172.16.1.102:http 5 1 0 14

相關文章