Maglev -- 谷歌的負載均衡器(一)

Maglev 是谷歌的軟件負載均衡器 (Software Load Balancer)。

Maglev 從 2008 年以來就作爲谷歌各項服務的負載均衡器部署在生產環境中,那些擁有全球級流量的服務(Search,YouTube,Gmail)的背後,都是由 Maglev 負責把全球數十億用戶每天發出的每一次 http request 轉發到實際的服務後端上。

**負載均衡器
**

負載均衡就是把任務能夠儘可能地平均分配到每一個操作單元的這麼一個過程。

打個比方就是:現在有多個技能一樣出色的工人(server),然後把工作 (workload) 儘可能地平均分配到他們每個人的身上,保證整個項目的工作效率最高的這麼一個過程就叫負載均衡。

那負載均衡器顧名思義就是完成負載均衡這個功能的機器。

負載均衡器分爲硬件負載均衡器(以 F5 爲代表)和軟件負載均衡器 (LVS, HA Proxy, Nginx, AVI LB, Maglev)。

硬件負載均衡是指用專門的硬件設備來完成負載均衡這樣的一種技術,它的優點是性能非常強悍,吞吐能力強,而且很容易擴充(無腦堆疊硬件即可)。但是它的缺點也非常明顯,首先是太貴了,具體價格可參見下圖。其次是這樣負載均衡對於用戶來說就是完全黑盒的一個技術,如果出現了問題就需要提供負載均衡的廠家來維修。

硬件負載均衡器價格

軟件負載均衡是指使用軟件編寫來實現負載均衡的技術,它的優點是相對於硬件負載均衡價格顯著降低,而且可以針對自己的應用場景更靈活地調配負載均衡的資源和策略,還有就是整個系統完全在自己的掌控之內,不需要依賴於第三方來支持。但是,同樣的,軟件負載均衡也有自己的缺點,首先就是軟件負載均衡的性能很難超越硬件,其次就是當需要擴容的時候,軟件負載均衡不能夠無腦堆疊,而需要自己實現 scale 策略才能保證負載均衡的性能能夠得到提升。

總而言之,硬件策略的性能強悍而不需要操心,軟件策略更加便宜而且靈活可控。

**動機——爲什麼設計 Maglev?
**

市面上已經有各種各樣成熟的硬件和軟件負載均衡器,那麼爲什麼谷歌還要自己設計 maglev 作爲自己的負載均衡設備呢?

簡單來說,因爲無論是軟件還是硬件負載均衡器,都無法滿足谷歌的需求。

如果採用硬件負載均衡器,面對谷歌搜索、YouTube 和 Gmail 郵箱這樣龐大的流量,需要的價格已經高到連谷歌都無法承受得住。而如果採用軟件負載均衡器,它們的性能卻又無法很好地支撐起上面所說的這樣龐大的流量,於是就催化了谷歌的 “磁懸浮” maglev load balancer 的誕生。

**Maglev Structure
**

一個 Maglev 的架構如上圖所示,它由 Controller 和 Forwarder 兩部分組成。Controller 和 Forwarder 都由 Config Objects 負責提供具體的配置,尤其是 VIP(virtual IP)的配置信息。

Controller 主要負責對 Forwarder 進行 health check,如果 Forwarder 依然很健康就會通過 BGP 協議對外廣播自己擁有的 VIP,否則就對外廣播撤回自己擁有的 VIP。這樣就保證了所有通過路由器流進來的流量都會被流入一個處於健康狀態的 maglev 上,防止 maglev 宕機導致服務不可用。

Forwarder 則負責具體地把發送到 maglev 上的所有網絡包均勻地發送到對應的後端服務上。它具體的結構如下圖:

當 packets 從網卡 (NIC) 流入 Maglev 時:

  1. Forwarder 會直接從網卡處拿到數據包而不經過內核處理。(kernel bypassing)

  2. 然後進入 steering 階段,Forwarder 會通過一個哈希函數 (hash function) 使用網絡包的 7 元組來計算這個包的一個哈希值並根據這個哈希值把它發送到一個專門處理包的隊列 (Queue) 裏面去。

  3. 每一個隊列會綁定一個專門的線程,這樣可以儘可能地減少 Context-Switch 浪費的時間。

  4. 在隊列裏時,Forwarder 首先會看一下這個 VIP 在不在當前這個 Maglev 聲明的 VIP 裏面,如果不在的話就直接把這個網絡包 drop 掉。

  5. 然後 Forwarder 會重新計算這個網絡包的哈希值,再去 connection tracking table 中找相對應的哈希值。

  6. 如果找到,立刻使用這個已經找到的後端。

  7. 如果沒找到就調用一致性哈希算法來給這個包找到一個後端,並且把這次的結果緩存在 connection tracking table 中。

  8. 找到對應的後端服務之後,會使用 GRE 將網絡包重新封裝,把實際對應的後端 IP 地址寫入 destination IP 中。

  9. 然後進入多路複用 (Muxing) 模塊,它會輪詢所有的隊列,並且把所用封裝好的包裹傳回網卡(NIC)。

爲了能夠高效地實現和網卡的交互,Google 的程序員們設計了一個網絡包池 (Packet Pool) 和環形鏈表 (Ring LinkedList) 的數據結構,如下圖所示:

Maglev 和網卡 (NIC) 共享這樣的一個資源池 (Packet Pool),並且通過鏈表指針(Pointer) 操縱池裏的包,這樣保證了整個過程中不需要進行任何多於的複製 (Copy) 過程,極致地提升了效率。

在這個鏈表結構中,根據 steering 和 muxing 兩個階段,每個階段各有三個指針,它們分別代表:

Steering:

  1. Received: NIC 接受到的包裹

  2. Processed:已經分發給線程的包裹

  3. Reserved:還沒有被使用的空間

Muxing:

  1. Sent:NIC 已經發送的包裹

  2. Ready: 已經處理好等到發送的包裹

  3. Recycled:已經發送包裹的空間

這樣,三個指針互相追逐 (Chasing),環形前進,完美地和網卡協作在一起。

****Maglev Advantages


Maglev 作爲一款軟件負載均衡器,卻能夠達到媲美硬件負載均衡的效率,並且還兼具軟件負載均衡器的便宜,靈活部署的特點,主要得益於:

本文介紹了 Maglev 內部的具體組成部分,那麼它到底是怎麼實現能夠把網絡流量平均地分配到每一個後端服務上的呢?下週的 “Maglev Hashing” 將解答這個問題。

Reference:

Maglev: A Fast and Reliable Software Network Load Balancer:

https://storage.googleapis.com/pub-tools-public-publication-data/pdf/44824.pdf

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/hGh3PFgnvV9-K1Eshhz9SA