Maglev 是谷歌搞的一個工做在三層(IP層)的網絡負載均衡器, 它是一個運行在普通的 Linux 系統上的巨大的分佈式系統, 而且能夠簡單平滑的伸縮後端服務器數量, 谷歌在本身的數據中心便使用該方案作負載均衡, 後面又以論文的形式將 Maglev 的負載均衡方案分享了出來.算法
剛說 Maglev 是一個三層的負載均衡, 那麼什麼是三層的負載均衡呢?後端
就是當你訪問一個負載均衡的 IP 的時候, 這個 IP 的後面是一個服務器組, 而不是單個服務器, 而這個服務器組中的任意一個服務器上面均可以監聽該 IP 來提供對外服務, 這樣達到的一個效果是不存在 IP 單點故障的問題, 而且該 IP 的服務能力能夠經過增長機器來進行擴展.服務器
它達到的效果如圖所示:網絡
首先, 咱們來看一下 maglev 的數據包的流向圖:負載均衡
如圖, 當一個用戶訪問一個帶有 Maglev 負載均衡的服務的 VIP 的時候, 用戶的請求首先經過 Internet 到達真實的服務節點所在的物理機房的核心交換機上, 也就是上圖的 Router, 這個時候核心交換機經過 ECMP 的功能將請求該 VIP 的數據包均衡的發送給後面的 N 個 Maglev 節點(藍色線1).分佈式
請求該 VIP 的數據包到達 Maglev 節點以後, Maglev 會知道該 VIP 對應哪些 Service Endpoint, 而後經過一種牛逼的一致性哈希算法選擇一個 Service Endpoint 將數據包發過去(紫色線2), 而要返回給用戶的數據包會由 Service Endpoint 直接返回到核心交換機上, 而後經過 Internet 返回給用戶(紅色線3).性能
以上簡要的歸納了數據包的是如何傳輸的, 看起來很簡單, 那麼整套體系要如何實現呢? 下面挑最重要的幾個技術細節來詳細講解一下.spa
首先是 ECMP 等價路由功能, 它可讓交換機或者路由器使用多條不一樣鏈路而達到相同的目的地址, 通常的物理交換機都是支持該協議的, 只要打開該選項便可.code
在物理交換機打開了 ECMP 的狀況下, 對於同一個 VIP 地址, 只要有多個不一樣鏈路的路由信息, 交換機即可以工做, 那麼這個路由信息是從哪裏來的呢?ip
這個時候就輪到 Maglev 上場了, 首先每個 Maglev 節點都會和核心交換機創建 BGP 鏈接, BGP 鏈接創建以後, Maglev 會經過該鏈接告訴交換機某某某 IP 我是可達的, 若是多個 Maglev 都告訴交換機說某某某 IP 我是可達的, 交換機上面便會記錄多條相似於下面的路由條目:
<vip> via <Maglev1_IP> dev eth0 <vip> via <Maglev2_IP> dev eth0 <vip> via <Maglev3_IP> dev eth0 ....
這個時候交換機在啓用 ECMP 路由功能的狀況下, 會根據上述的路由信息將數據包均衡的發送給多個 Maglev 節點, 好了, 這個時候數據包到了 Maglev 節點, 那麼 Maglev 節點自己是如何處理這些數據包的呢? 以下圖是數據包在 Maglev 節點上面的處理過程:
上面簡要的說過, Maglev 要挑選一個 Service Endpoint 而後將數據包發給選中的 Service Endpoint, 那麼兩個問題, 如何挑? 如何發?
先說 Maglev 是如何挑選 Service Endpoint 的, 首先交換機會經過簡單的一致性哈希算法將擁有相同5元組的 packet 發送給同一臺 Maglev 節點, 而後 Maglev 經過 packet 目標 IP, 也就是 VIP 來選擇對應的後端節點, 一樣的在選擇後端的時候 Maglev 也使用了一種一致性哈希算法, 這樣即可以保證同一 TCP 鏈接上的全部的 packet 會打到相同的 Service Endpoint 上. 選擇好後端以後, Maglev 會將該5元組對應的後端記錄在本身的 connection tracking 表中, 等到下個數據包來的時候, 只要根據包的5元組直接查詢這個 connection tracking 表便可. 那爲何有了一致性哈希選擇後端, 還要有 connection tracking 呢? 這是由於當一個 VIP 對應的 Service Endpoint 擴容或者縮容的時候, 一致性哈希選擇的結果會發生變化, 這樣會致使同一鏈接上的包選擇的後端不一致, 形成網絡錯誤.
而後在說說 Maglev 是如何將數據包發送給挑好的 Service Endpoint 的, 從原理上來講, Maglev 會將收到的數據包封一層 GRE/IP 頭而後發給 Service Endpoint, 相應的 Service Endpoint 端須要對收到的 packet 進行解包, 還有一種比較簡單的修改方式, 若是 Maglev 節點和 Service Endpoint 是在一個二層網絡裏的話, 那麼只要修改數據包的目標 mac 地址爲選中的 Service Endpoint 的 mac 地址即可以將數據包發送過去, 後端也不須要進行解包. 修改好數據包以後, Maglev 只要把修改好的包從相應的網卡上發出去便可. 這裏涉及到了讀包寫包的問題, 若是直接使用 Linux Kernel 提供的方法來直接讀寫 packet, 會發現性能不能知足需求, 在這裏可使用一些 Kernel Bypass 的技術來作, 好比 dpdk 或者其餘 Kernel Bypass 的技術.
至此, Maglev 最重要的原理已經講清楚了, 固然還有更細節的, 好比 Maglev 的一致性哈希算法是如何實現的等等, 這裏再也不贅述, 若是你想更加深刻的瞭解能夠看看 Maglev 的論文. 本文也是對 Maglev 論文的一個簡單總結, 其中若是有理解錯誤或者不許確的地方也歡迎指正.