5 分布式快取中的一致性Hash 演算法

2021-07-25 20:12:51 字數 3087 閱讀 1816

在分布式快取伺服器集群中,所有的快取伺服器中快取的資料各不相同,這時路由演算法就至關重要了,路由演算法負責根據應用程式輸入的快取資料key計算得到應該將資料寫入到哪台快取伺服器(寫快取) 或則 應該從哪台快取伺服器讀取資料(讀快取)。也就是說根據key存入某台快取伺服器s1,當應用使用同樣的key時能從這台快取伺服器s1中讀出快取。

這時的路由演算法和負載均衡演算法一樣至關重要,路由演算法決定著究竟該訪問集群中的哪台伺服器,先看乙個簡單的路由演算法。

比方說,字串str對應的hashcode是51、伺服器的數目是3,取餘數得到0,str對應節點node0,所以路由演算法把str路由到node0伺服器上。由於hashcode隨機性比較強,所以使用餘數hash路由演算法就可以保證快取資料在整個快取伺服器集群中有比較均衡的分布。

如果不考慮伺服器集群的伸縮性,那麼餘數hash演算法幾乎可以滿足絕大多數的快取路由需求,但是當分布式快取集群需要擴容的時候,就會出現很嚴重的問題

就假設快取伺服器集群由3臺變為4臺吧,更改伺服器列表,仍然使用餘數hash,51對4的餘數是3,對應node3,但是str原來是存在node0上的,這就導致了快取沒有命中。如果這麼說不夠明白,那麼不妨舉個例子,原來有hashcode為0~19的20個資料,那麼:

hashcode01

2345

6789

1011

1213

1415

1617

1819

路由到的伺服器01

2012

0120

1201

2012

01現在我擴容到4臺,加粗標紅的表示命中:

hashcode01

2345

6789

1011

1213

1415

1617

1819

路由到的伺服器

0 1 23

0123

0123

0123

0123

這時就是只有6個命中了;比例也就是6/20。

如果我擴容到20+的台數,只有前三個hashcode對應的key是命中的,也就是15%。當然這只是個簡單例子,現實情況肯定比這個複雜得多,不過足以說明,使用餘數hash的路由演算法,在擴容的時候會造成大量的資料無法正確命中(其實不僅僅是無法命中,那些大量的無法命中的資料還在原快取中在被移除前佔據著記憶體)。這個結果顯然是無法接受的,在**業務中,大部分的業務資料度操作請求上事實上是通過快取獲取的,只有少量讀操作會訪問資料庫,因此資料庫的負載能力是以有快取為前提而設計的。當大部分被快取了的資料因為伺服器擴容而不能正確讀取時,這些資料訪問的壓力就落在了資料庫的身上,這將大大超過資料庫的負載能力,嚴重的可能會導致資料庫宕機。

這個問題有解決方案,解決步驟為:

(1)在**訪問量低谷,通常是深夜,技術團隊加班,擴容、重啟伺服器。

(2)通過模擬請求的方式逐漸預熱快取,使快取伺服器中的資料重新分布。

下面介紹乙個更加優秀的路由演算法:一致性hash演算法。

一致性hash演算法通過乙個叫做一致性hash環的資料結構實現key到快取伺服器的hash對映,下面看一下乙個示意圖:

具體演算法過程為:先構造乙個長度為2^32的整數環(這個環被稱為一致性hash環),根據節點名稱的hash值(其分布為[0, 2^32-1])將快取伺服器節點放置在這個hash環上,然後根據需要快取的資料的key值計算得到其hash值(其分布也為[0, 2^32-1]),然後在hash環上順時針查詢距離這個key值的hash值最近的伺服器節點,完成key到伺服器的對映查詢。

就如同圖上所示,三個node點分別位於hash環上的三個位置,然後key值根據其hashcode,在hash環上有乙個固定位置,位置固定下之後,key就會順時針去尋找離它最近的乙個node,把資料儲存在這個node的快取伺服器中。使用hash環如果加了乙個節點會怎麼樣,看一下:

看到我加了乙個node4節點,只影響到了乙個key值的資料,本來這個key值應該是在node1伺服器上的,現在要去node4了。採用一致性hash演算法,的確也會影響到整個集群,但是影響的只是加粗的那一段而已,相比餘數hash演算法影響了遠超一半的影響率,這種影響要小得多。更重要的是,集群中快取伺服器節點越多,增加節點帶來的影響越小,很好理解。換句話說,隨著集群規模的增大,繼續命中原有快取資料的概率會越來越大,雖然仍然有小部分資料快取在伺服器中不能被讀到,但是這個比例足夠小,即使訪問資料庫,也不會對資料庫造成致命的負載壓力。

對於具體應用,這個長度為2^32的一致性hash環通常使用二叉查詢樹實現,至於二叉查詢樹,就是演算法的問題了。

但是:上面的演算法還有乙個小問題:帶來了快取伺服器負載不均衡。

新加入的node4只影響到了它的下乙個節點,並沒有影響到其他的兩個節點,導致4臺機器的負載壓力不一樣。比如說有hash環上有a、b、c三個伺服器節點,分別有100個請求會被路由到相應伺服器上。現在在a與b之間增加了乙個節點d,這導致了原來會路由到b上的部分節點被路由到了d上,這樣a、c上被路由到的請求明顯多於b、d上的,原來三個伺服器節點上均衡的負載被打破了。某種程度上來說,這失去了負載均衡的意義,因為負載均衡的目的本身就是為了使得目標伺服器均分所有的請求。

在計算機領域有句名言:計算機的任何問題都可以通過增加乙個虛擬層來解決。

解決上訴的一致性hash 演算法帶來的負載不均衡也可以通過加乙個虛擬曾來解決。其工作原理是:將乙個物理節點拆分為多個虛擬節點,並且同乙個物理節點的虛擬節點盡量均勻分布在hash環上。採取這樣的方式,就可以有效地解決增加或減少節點時候的負載不均衡的問題。

至於乙個物理節點應該拆分為多少虛擬節點,下面可以先看一張圖:

橫軸表示需要為每台福利伺服器擴充套件的虛擬節點倍數,縱軸表示的是實際物理伺服器數。可以看出,物理伺服器很少,需要更大的虛擬節點;反之物理伺服器比較多,虛擬節點就可以少一些。比如有10臺物理伺服器,那麼差不多需要為每台伺服器增加100~200個虛擬節點才可以達到真正的負載均衡。

分布式快取的一致性Hash演算法

具體過程 1 先構造乙個長度為0 2 32的整數環,根據節點名稱的hash值,將快取伺服器節點放置在這個hash環上。2 根據需要快取的資料的key值計算得到其hash值,然後在hash環上順時針查詢距離這個key值的hash值最近的快取伺服器節點,完成key到伺服器的hash對映查詢。補充 這個一...

分布式快取的一致性 Hash 演算法

簡單的路由演算法可以使用餘數 hash 用伺服器資料除快取資料 key 的 hash 值,餘數為伺服器列表下標編碼。這種演算法可以滿足大多數的快取路由需求。但是,當分布式快取集群需要擴容的時候,事情就變得棘手了。舉個例子 很容易可以計算出,3臺快取伺服器擴容至4臺伺服器,大約有 75 3 4 被快取...

分布式一致性Hash演算法

介紹一致性hash演算法之前,先簡單回顧一下分布式以及hash演算法,便於理解為什麼要有一致性hash演算法。當我們也無需求很複雜時,單台機器io以及頻寬等都會成為瓶頸,所以對業務進行拆分,部署在不同的機器上,當有請求訪問時,根據某些特點將這些請求分散到各個伺服器上,這所有的伺服器組成的網路,我們稱...