Google研究 | 使用一致的雜湊演算法分配臨界負載

谷歌開發者_發表於2017-04-18

640?wx_fmt=gif


文 | NYC 演算法團隊首席科學家 Vahab Mirrokni 和研究員 Morteza Zadimoghaddam


執行大規模網路服務(例如內容託管)離不開負載平衡,也就是將客戶端均勻地分配到多個伺服器上,使得每個伺服器都不至於過載。此外,在隨時可以新增或移除客戶端和伺服器的動態環境中,較為理想的做法是找到一種不會隨時間而大幅改變的分配方案。換而言之,我們需要在一段時間內一致地將客戶端分配到伺服器。

通過與哥本哈根大學客座研究員 Mikkel Thorup 合作,我們開發了一種全新而有效的分配演算法來解決這一問題,能夠嚴格保證每臺伺服器的最大負載,並從理論和實踐上研究了這一演算法。隨後,我們與我們的雲團隊合作,在 Google Cloud Pub/Sub 這一可擴充套件的事件流服務中實現了該演算法,我們發現,在符合一致性和穩定性目標的同時,還顯著改善了負載分配的均勻性(以伺服器分配到的最大負載來衡量)。2016 年 8 月,我們在“使用一致的雜湊演算法分配臨界負載”(Consistent Hashing with Bounded Loads) 論文中介紹了我們的演算法,並在 ArXiv 中分享了這一演算法,以供更廣泛的研究社群使用。

三個月以後,來自 Vimeo 的 Andrew Rodland 通知我們,他發現了該論文,隨後在 haproxy(一段廣泛使用的開放原始碼軟體)中實現了該演算法並將其用於 Vimeo 的負載平衡專案。結果非常引人注目:應用這些演算法幫助他們幾乎將快取頻寬降低到原來的 1/8,從而消除了擴充套件瓶頸。他最近在一篇博文中概述了這一案例,詳細介紹了他的用例。毋庸贅言,我們非常興奮地瞭解到,我們的理論研究成果不僅被投入應用,還體現出使用價值,並且還開放原始碼。



背景

儘管過去已經研發出一致的雜湊演算法理念來解決動態環境中的負載平衡問題,但所有之前開發的方案都存在一個根本性的問題:在特定的場景下,它們可能導致許多伺服器上的負載平衡不能達到最佳狀態。

此外,由於可能隨時新增或移除客戶端和伺服器,在做出此類改動時,我們不希望移動太多的客戶端。因此,動態分配演算法不僅必須始終確保正確的負載平衡,還應儘量減少每次對系統做出改動之後所移動的客戶端數量。當每臺伺服器的容量存在嚴格的限制時,也就是說,每臺伺服器都有嚴格的容量限制,負載不得超過此限制之時,此類分配問題會變得更為嚴峻。通常,我們希望容量接近於平均負載。

換而言之,我們希望在最終的分配中同時實現均勻性和一致性這兩大目標。對於伺服器集固定不變、只有客戶端集會更新這種簡單很多的情形,有大量的文獻介紹了相關的解決方案,但在本文中,我們討論的解決方案針對的是客戶端和伺服器均可隨時新增和移除的完全動態的情形。



演算法

我們可以將伺服器比作垃圾桶,將客戶端比作球,並借鑑將球隨機投入垃圾桶的過程 (balls-to-bins stochastic processes) 這一經過深入研究的模型,採用與之類似的抽象方法。均勻性目標要求所有垃圾桶所裝的球數量大致等於平均密度(球數除以箱子數)。對於引數 ε,我們將每個垃圾桶的容量設定為平均負載的最低或最高倍數 (1+ε)。這一額外的容量讓我們可以設計出一種能夠同時滿足均勻性目標和一致性目標的分配演算法。

設想給定範圍的一組數字,將其分佈到一個圓圈上。我們對球應用一個雜湊函式,對垃圾桶應用另一個不同的雜湊函式,以獲取該範圍內、與該圓圈上不同位置對應的數字。隨後,我們開始按特定的順序分配球,此順序與其雜湊值無關(假設基於其 ID)。然後,按順時針移動每個球並將其分配到第一個有空閒容量的垃圾桶。


640?wx_fmt=png


我們分析一下上面的例子,我們使用兩種不同的雜湊函式,將 6 個球和 3 個垃圾桶隨機分配到圓圈上的不同位置。對於本例,我們假設每個垃圾桶的容量設定為 2。我們開始按 ID 值的升序分配球。1 號球按順時針移動,進入垃圾桶 C。2 號球進入垃圾桶 A。3 號和 4 號球進入垃圾桶 B。5 號球進入垃圾桶 C。6 號球順時針移動,首先命中垃圾桶 B。然而,垃圾桶 B 的容量為 2,而其中已經裝有 3 號和 4 號球。因此,6 號球繼續向前移動,直至到達垃圾桶 C,但該垃圾桶也已滿。最後,6 號球進入仍有空餘位置的垃圾桶 A。

如對系統進行任何更新(插入/刪除球或垃圾桶),則會重新計算分配,以保持均勻性目標。分析表明小幅更新(插入和刪除少量的球或垃圾桶)會導致分配狀態的小幅改變,因此,可滿足一致性目標。在我們的論文中,我們展示了在該系統中,每插入或移除一個球將會導致其他球進行 O(1/ε2) 次運動。最重要的是,此上限與系統中球或垃圾桶的總數無關。因此,如果球或垃圾桶的數量加倍,此上限不會改變。上限與球或垃圾桶的數量無關,為可伸縮性帶來了巨大的空間,因為我們將其搬到更大的例項中,仍然可以滿足一致性目標。下面顯示了更新某個垃圾桶/伺服器時,每次更新所導致的移動(重新分配)次數模擬結果。


640?wx_fmt=png


紅色曲線代表移動的平均次數,藍色柱線代表不同 ε 值(X 軸)的方差。虛線代表我們的理論結果所建議的上限,其非常適合用於預測實際的移動次數。此外,對於任何 ε 值,我們知道,每個垃圾桶的負載至多是平均負載的 (1+ε) 倍。下面,我們看到不同值 ε=0.1、ε=0.3 和 ε=0.9 條件下垃圾桶的負載分佈情況。


640?wx_fmt=png

▲ 不同 ε 值下的負載分佈。對於所有範圍的負載(從 0 到 (1+ε) 倍於平均負載),負載分佈均接近均勻,許多垃圾桶的負載等於平均負載的 (1+ε) 倍。    


我們可以看到,這裡需要折中考慮,較低的 ε 值有利於確保均勻性,但不利於確保一致性,而較大的 ε 值則有利於確保一致性。較低的 ε 值可確保許多負載等於平均負載的 (1+ε) 倍這一硬性容量限制,而其他負載則為遞減分佈。

在提供內容託管服務時,必須做好應對許多不同特性的例項的準備。這種一致的雜湊方案非常適合此類情形,因為即便是最糟糕的情形下,它也能有不錯的表現。

我們的內部研究結果激動人心,我們更欣慰的是,更廣大的社群發現我們的解決方案非常有用,足以列入開放原始碼,讓任何人都可以使用該演算法:

https://github.com/arodland/haproxy


如果您有興趣進一步瞭解本研究的詳細情況,請在 ArXiv 上查閱此論文,並請務必關注,NYC 演算法團隊將公佈更多的研究成果:

https://arxiv.org/abs/1608.01350



致謝:

我們想感謝來自 Google Cloud Pub/Sub 團隊的 Alex Totok、Matt Gruskin、Sergey Kondratyev 和 Haakon Ringberg,當然還要感謝 Mikkel Thorup 對此論文做出的寶貴貢獻。


瞭解更多細節,檢視文內所有連結,請點選文末“閱讀原文”。


640?wx_fmt=gif


點選「閱讀原文」,檢視文內連結640?wx_fmt=gif

相關文章