在集群中,假設有五台服務器,他們之間的地位相同(主備模式不是我們要討論的內容),都對外提供服務。當瀏覽器大量請求到達時,如何決定哪個請求到達哪個服務器上,這就是我們這次討論的核心內容。
負載均衡的策略分為應用服務器和分布式緩存集群兩種適應場景。
為什么這么分呢?簡單的說,應用服務器只需要轉發請求就可以了。但分布式緩存集群,比如redis、Memcached等,更多的是需要再次讀取數據的。也正是因為這樣,當新加入一台機器后,要盡量對整個集群的影響小。
1、應用服務器
NO.1—— Random 隨機
這是最簡單的一種,使用隨機數來決定轉發到哪台機器上。
優點:簡單使用,不需要額外的配置和算法。
缺點:隨機數的特點是在數據量大到一定量時才能保證均衡,所以如果請求量有限的話,可能會達不到均衡負載的要求。
NO.2—— Round Robin 輪詢
這個也很簡單,請求到達后,依次轉發,不偏不向。每個服務器的請求數量很平均。
缺點:當集群中服務器硬件配置不同、性能差別大時,無法區別對待。引出下面的算法。
NO.3—— Weighted Round Robin 加權輪詢
這種算法的出現就是為了解決簡單輪詢策略中的不足。在實際項目中,經常會遇到這樣的情況。
比如有5台機器,兩台新買入的性能等各方面都特別好,剩下三台老古董。這時候我們設置一個權重,讓新機器接收更多的請求。物盡其用、能者多勞嘛!
這種情況下,“均衡“就比較相對了,也沒必要做到百分百的平均。
NO.4—— Least Connections 最少連接
這是最符合負載均衡算法的一個。需要記錄每個應用服務器正在處理的連接數,然后將新來的請求轉發到最少的那台上。
NO.5—— Source Hashing 源地址散列
根據請求的來源ip進行hash計算,然后對應到一個服務器上。之后所有來自這個ip的請求都由同一台服務器處理。
2、分布式緩存集群
好了,有了前面的基礎,再看分布式緩存集群就簡單多了。我們只需要多考慮兩點就夠了。
NO.1—— 取模
這是最簡單但最不實用的一個。
以redis為例,假設我們有5台機器,要想取模肯定先得轉換為數字,我們將一個請求的key轉成數字(比如CRC16算法那),比如現在五個請求轉換成的數字后對5取模分別為0、1、2、3、4,正好轉發到五台機器上。
這時意外來了,其中一台宕機了,現在集群中還有4台。之后再來請求只能對4取模。問題就暴露出來了,那之前按照5取模的數據命中的機率大大降低了,相當於每宕機一台,之前存入的數據幾乎都不能用了。
因此,不推薦此種做法。
NO.2—— 哈希
這種算法叫哈希有些籠統了,具體可以分為ip哈希和url哈希(類似原地址散列)。這里就不多說了。重點說下redis中的設計。
redis中引入了哈希槽來解決這一問題。16384個哈希槽,每次不再對集群中服務器的總數取模,而是16384這個固定的數字。然后將請求分發。這樣就可以避免其中一台服務器宕機,原有數據無法命中的問題。
NO.3—— 一致性哈希
終於到重頭戲了,不過有了前面的介紹,這個也就不難理解了。
一致性哈希在memcached中有使用,通過一個hash環來實現key到緩存服務器的映射。
這個環的長度為2^32,根據節點名稱的hash值將緩存服務器節點放在這個hash環上。如下圖中的node1、node2等。
這時要保存的數據key仍舊進行hash運算,運算之后的值會落在這個hash環上的某一處(圖中粉色的節點),當然這還沒結束,因為他還沒有落到node上。之后這個粉色的節點會沿順時針落到離他最近的node上,over。
改進
當其中某個結點宕機后,比如node4,這時如果有結點落在了node2和node4之間,本來應該歸為node4的,但這時候他宕機了,就都放在了下一個node3中。
這時,每個結點的數據量就會有很大出入了,平衡性很難保證。因此,引入“虛擬結點”。
虛擬結點是實際結點在hash空間的復制品,為了保證平衡性,一個實際node被划分成了若干個虛擬node。
如下圖所示:
服務器之間的交錯關系會改變,每個虛擬node之間的相對關系是不一定的,比如每個node1的虛擬節點后面可以是node2的也可以跟node3的。
此時,如果紅色的node宕機了,那么將要落在這台機器上的數據可能落到藍色,也可能是綠色的。這就保證了一定程度的平衡性。