負載均衡的Hash策略引發的session丟失

2021-09-22 02:19:56 字數 3083 閱讀 1076

三、session 保持的其他方案

四、各個方案的適用場景

結語負載均衡後新增機器後,發現資料庫的壓力迅速上公升,越來越多的使用者說剛登陸後沒多久,操作著就退出了,接著登陸,又退出了。

這些問題背後都是由於乙個「session 丟失」問題導致的。

相信 session 對大部分 coder 來說應該都知道。它是為了將同乙個使用者的多次訪問在系統中被識別為「同乙個使用者」而產生的概念。

除此之外,還可以基於它來減少重複往 db 或者遠端服務處獲取與該使用者相關的資訊,以起到提公升效能的作用。

在我們做了負載均衡的場景中,如果選擇的負載策略是 hash 策略,那麼會使得 session 產生乙個***。

這個***就如上面舉的案例那樣,使用者一旦由於某種原因從原先訪問伺服器 a 變成訪問伺服器 b,就會出現「登陸狀態丟失」、「快取穿透」等問題。

為什麼 hash 策略會出現這個問題呢?首先有必要先了解一下 hash 是如何進行的。

hash 策略就是下圖這樣的乙個雜湊函式。在函式不變的情況下,a 永遠對應 01,b 對應 04,c 對應 08。

以 nginx 中的 ip_hash 策略來舉個例子:因為我們認為正常情況下使用者的 ip 不會在短時間內發生變化。

所以當我們選擇使用 ip_hash 策略進行負載均衡時,意味著期望同乙個使用者能夠一直訪問到同一臺伺服器上,就像下圖這樣:

如此一來,我們只需要在這一台伺服器上將這個使用者相關的資訊快取在程序內,就能起到非常高價效比的提公升效能的效果。

這時,客戶端與服務端之間就相當於建立了乙個信任,相互認識。這個信任就是「session」。

但是,當我們加了一台伺服器之後,事情就發生變化了。

這個時候我們原先的預期就被破壞了。因為使用者與序號 0 節點的鏈結變成了與序號 3 的鏈結,所以產生了前面提到的「session丟失」問題。

與此同時,在序號 0 節點上做的程序內快取都無效了,而在序號 3 節點上又沒有使用者相關的任何快取,導致大量資料需要從下游的 db 或者遠端服務處獲取。

你要知道,一旦涉及到網路通訊,效能必然明顯下降,i/o、序列化都是耗時的工作。

更重要的是,一旦同時有大量使用者產生這個情況,由於後端的 db 和遠端服務瞬時無法承載激增的高密度請求,可能會導致它掛起。

這還沒完,如果當前程式沒有一些故障隔離或者降級策略,還會進一步產生蝴蝶效應,導致整個大系統響應緩慢。可謂「一顆老鼠屎壞了一鍋粥」。

既然以 nginx 舉例,還是從 nginx 開始聊。通過在 nginx 中引入 nginx-sticky-module 模組可以來解決這個問題。

解決的整個過程如下:

可以看到,當 client 第一次進入到 nginx 匹配節點的時候,在給它分配乙個節點的同時,會將這個節點的唯一標識進行 md5 後寫入到 cookie 中一併返回。

如果下次再發起請求的時候發現帶有這個 cookie 值,就直接**到該值所對應的節點上去。這個機制被專業的稱之為「session 保持」。

雖然可以利用 cookie 來解決這個問題,但是 cookie 也有乙個潛在的問題,如果客戶端未開啟 cookie 功能,這個機制就失效了。不過好在目前主流瀏覽器都是預設開啟 cookie 的。

**題外話:**nginx 是 2004 年發布的,在 nginx-sticky-module 出現之前的 7 年間也是 nginx 相比競品 haproxy 最大的乙個短板,因為 haproxy 支援 session 保持。

除了 cookie 之外,還有 2 種方式也可以最終達到類似的效果,分別被稱為「session 複製」、「session 共享」。

這是最簡單粗暴的方式。根據第一節的案例來看,導致問題的原因是節點 3 沒有使用者的 session。

那麼很容易想到,在節點 3 執行之前把 session 相關的 cache 資料複製過去唄。

並且在多個節點之間持續保證資料的同步,也就是說,每一台節點上都存在每個使用者的 session 資料。

實現的方案有很多,特別是不同的宿主程式都或多或少提供了一些切入點,甚至是拿來即用的方案,如 tomcat 的 delta manager 和 backup manager、tomcat 和 iis 的 filter 機制等等,這裡就不展開了。

此類方案的特點是:

我們還可以通過將 session 資訊存放到全域性共享的儲存介質中來達到一樣的效果,如資料庫、遠端快取等,這是一種中心化思想的解決方案。

此類方案的特點是:

同之前 session 保持 方案一起對比下各自的優缺點和適用場景:

分別用一句話概括一下這 3 個方案:

越大型的系統,最終都會往「session 共享」這個方案上走,因為只要再對這個共享儲存做橫向擴充套件,理論上就可以支撐無窮大的使用者了。

如 redis、一系列的 nosql 以及 newsql 等。就可以集 規模大、高可用、效果好 於一身。

現在你應該清楚了 session 丟失問題,也知道了如何去應對它。但是,我們還需要明白乙個事實:嚴格來說「session 保持」本質上是破壞了做「負載均衡」的初衷。

舉個極端點的場景:一共有 10 個會話連在了節點 a 上,並且都是活動中狀態。

那麼這個時候哪怕增加乙個節點 b 上線,只要沒有新的會話進來,節點 b 上的活動連線數永遠是 0,並沒有起到分擔壓力的作用。但是,在系統的起步時期,其實用這樣簡單的方案也是極好的。

負載均衡的策略

在集群負載均衡時,dubbo提供了多重均衡策略,預設為random隨機呼叫。當然可以根據自己的業務需求自行擴充套件一些策略。1 romdom loadbalance 1 隨機。按權重設計隨機概率。2 在乙個截面上碰撞的概率高,但呼叫越大分布越均勻,而且按概率使用權重後也比較均勻,有利於動態調整提供者...

負載均衡的策略

輪詢 預設方式。每個請求按時間順序逐一分配到不同的後端伺服器,如果後端伺服器down掉,自動剔除。使用於後台機器效能一致的情況。加權輪詢 指定輪詢機率,權重和訪問比率成正比,用於後端伺服器效能不均的情況。權重越高,在被訪問的概率越大 ip hash 每個請求按照訪問ip的hash結果分配,這樣每個訪...

常用的負載均衡策略

將請求順序迴圈地發到每個伺服器。當其中某個伺服器發生故障,ax就把其從順序迴圈佇列中拿出,不參加下一次的輪詢,直到其恢復正常 給每個伺服器分配乙個加權值為比例,根椐這個比例,把使用者的請求分配到每個伺服器。當其中某個伺服器發生故障,ax就把其從伺服器佇列中拿出,不參加下一次的使用者請求的分配,直到其...