Google 是如何做負載均衡的?

Google 使用的技術一般都自帶光環,吸引程序員的注意,基礎設施方面的東西就更是如此,年初 Google 發布了篇論文介紹內部的負載均衡器的實現,讓我們有機會一睹可能是全球最好的負載均衡器。

通常情況下的負載均衡要在靈活性和性能之間做權衡,用戶態軟件層面有 Haproxy 和 Nginx 這樣的老牌負載均衡軟件,他們一般配置和使用起來都比較容易,但是由于需要數據包從網卡到內核再到軟件一層層向上處理,再一層層向下轉發,堆棧比較深單機性能通常都比較一般。為了提高單機性能,減少堆棧層級就有了 Linux 里華人之光的 LVS,工作在內核層的負載均衡器,性能有著數量級的提高,然而配置起來相對也比較復雜而且對網絡條件要求也有特殊要求。那 Google 有什么秘密的配方來達到高性能呢?

一般來說負載均衡器本身就是后端服務橫向擴展的一個接入點,對于一般站點一個負載均衡器就夠了,然而應對 Google 這種級別的流量,負載均衡器本身也要能橫向擴展,還要處理負載均衡器的高可用,Google 又是如何做到的呢?

以我們訪問 www.google.com 為例,第一步 DNS 服務器會根據請求的位置返回一個離請求地理位置最近的 VIP 地址,先在 DNS 這一層做一個橫向擴展。接下來請求達到 VIP 對應的路由器,路由器通過 ECMP 協議,可以將請求平均分配到下面對等的多個負載均衡器上,這樣在路由器這一層做了個負載均衡,讓后面的負載均衡器也實現了橫向擴展。再往下是一個類似于 LVS 中 DR 模式的分發,負載均衡器將請求包轉發給服務器同時將源地址改為客戶請求時的地址,服務器響應時將響應包的源地址改為 VIP 的地址直接打給路由器而不通過負載均衡器來降低負載均衡器壓力。流程圖如下

對了,Google 的這個負載均衡器叫 Maglev,磁懸浮列車的意思。自然是要做到極致的性能,只看流程似乎和 LVS 中 DR 模式很類似,但內部就完全不一樣了。

簡單的說雖然 LVS 已經做到 Linux 內核里了,但是在 Google 看來 Linux 是性能的瓶頸,到 LVS 之前還要經過完整的 TCP/IP 協議棧以及內核的一系列 filter 模塊,而這些對于轉發來說是沒有必要的。于是 Google 的做法就是簡單粗暴的繞過內核,把 Maglev 直接架在網卡上對接網卡的輸入和輸出隊列,來一個數據包也不需要完整的 TCP/IP 協議棧的解析,進來的包只要分析前幾個字節,拿出源地址,源端口,目標地址,目標端口和協議號這個五元組對于轉發來說就已經足夠了。剩下的諸如 payload,序列號之類的東西統統不關心直接塞到網卡輸出口給后面就行了。

前幾天聽美團的介紹他們的負載均衡器是用的類似的思路用 DPDK 直接在網卡上編寫應用,性能相對 LVS 就有數倍的提升。看 Maglev 的實現為了榨干性能是直接寫在網卡上的,都沒有 DPDK 之類的封裝。繞過內核就可以自己分配內存管理內存就可以進一步的壓榨性能。論文中可以看到 Maglev 是直接和網卡共享內存的,這樣就不需要將數據包再從網卡進行一次復制到負載均衡器中,也不需要把數據包再從負載均衡器復制到網卡,網卡入口隊列,負載均衡器,網卡出口隊列共享一個數據池空間,三個指針不斷的移動處理數據包,可謂是在內存這里做到了極致。

當然諸如 CPU 綁定,每個 CPU 專職處理一個線程來避免 cache miss,memory contention 這種常規優化也是都有的。最終的效果就是處理一個數據包平均需要 350ns,而性能發生抖動的情況一般是由于網卡發數據包是批量的或者要等待一個 timer 的中斷,而這個中斷的時間是 50us 所以當流量小的時候這個延遲可能會達到 50us。(我覺得 Google 這么寫其實是在炫耀自己性能好,瓶頸在網卡刷新速度上,而不在負載均衡器上)

通常的負載均衡器都是一個單點,而 Maglev 是一個集群,集群就會碰到很多的問題。嚴格來說負載均衡器不能算是一個無狀態的服務,因為 TCP 連接本身是有狀態的,一組會話內的請求包必須轉發到相同的后端服務器,不然服務器端的 TCP 會話就亂套了。對于單點的負載均衡器來說很好解決,記錄個轉發表里面有每個數據包的五元組和它第一轉發到哪臺機器,來一個新的數據包查這個表就知道給誰了。而像 Maglev 這樣的集群數據包是通過路由器 ECMP 隨機分發的,第一個數據包是這個 Maglev node 處理,下一個就不知道去哪個 Maglev node 了。而且集群就會涉及滾動式的更新和隨機的故障,這樣本機的轉發表也就很可能會丟失。

之前聽美團的介紹,他們的做法是在多臺機器之間做內存的同步每次更新都要進行一次同步來保證所有機器轉發表的一致。而 Google 一幫人不愧是搞研究出身的,直接就上了一致性哈希這個大殺器。這樣的話可以直接通過五元組散列到后端的一臺固定服務器,這樣硬生生的把有狀態服務做成了無狀態,如此一來 Maglev 層面個就可以隨意的更新,上線下線了。順便的一個好處就是后端增加下線服務器都只會影響到當前這臺機器所處理的連接不會造成所有連接的 rehash。當然只用一個普通的一致性哈希算法也沒啥意思,Google 為了自己的需求專門寫了個 Maglev Hashing

論文里還介紹了很多負載均衡器運維方面的經驗以及設計的過程和經驗,還說了下一些新的發展方向,感興趣的可以點擊閱讀原文看一下論文原文,當然你要翻下墻(逃

 

來自:http://mp.weixin.qq.com/s/2NQcwukKoHR4eFXZNtIb1w

 

 本文由用戶 gyfinjava 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!