圖解什麼是一致性哈希算法

2021-02-25 碼海
1. 寫在前面

周末就像太陽,總會到來,也總會離開。

此刻,沒錯,是周六呀!還是雙休那種!

昨晚在B站看了幾個長視頻,導致2點才睡覺,早上一覺醒來已經10點了。

在這裡溫馨提示各位盆友們,雖然我們都是年輕人,但還是要規律作息,早睡早起。


廢話不多說了,開始今天的話題:

什麼是一致性哈希算法。

2. 蒙圈的字面含義

第一次聽這個術語時候困惑於是個啥意思?

一致性,咱懂
哈希算法,咱也懂
一致性+哈希算法  什麼鬼?

雖然我大白腦袋比較空,但是我不信所有的網友都知道這個術語,於是在知乎找到個問題,還以為是我寫的呢:

看來還真是有像大白這樣,腦袋不靈光但是充滿好奇的年輕人呀!

於是我決定上路,搞它!

3.分布式系統和一致性哈希

要理解一致性哈希算法就需要知道分布式系統的一些特點。

年輕人你肯定會問:為啥呢?

因為,一致性哈希算法就是為了解決分布式系統中的一些關鍵問題。

3.1 分布式系統概覽

高並發和海量數據處理等場景越來越多,實現服務應用的高可用、易擴展、短延時等成為必然。

在此情況下分布式系統應運而生,網際網路的場景無外乎存儲和計算,因此分布式系統可以簡單地分為:

可以簡單認為分布式系統就是一批物理不相鄰的計算機組合起來共同對外提供服務。

對於用戶來說具體有多少規模的計算機完成了這次請求,完全是無感知的。

分布式系統中的計算機越多,意味著計算和存儲資源等也就越多,能夠處理的並發訪問量也就越大,響應速度也越快。

如圖為簡單整體架構:

3.2 分布式和集群化

集群是從原來的單機演變來的,單臺機器扛不住就加機器,直到服務負載、穩定性、延時等指標都滿足。

集群中的N臺機器上部署一樣的程序,就像一臺機器被複製多份一樣,這種形式就是集群化。

分布式是將一個完整的系統,按照業務功能拆分成一個個獨立的子系統,這些服務之間使用更高效的通信協議比如RPC來完成調度,各個子服務就像在一臺機器上一樣,實現了業務解耦,同時提高了並發能力確實不賴。

一個大的分布式系統可以理解拆分之後的子服務使用集群化,一個個子服務之間使用類似於RPC的協議串聯,組成一個龐大的存儲和計算網絡。

如圖為簡單的分布式系統結構:

3.3 集群化遇到的問題

我們以分布式存儲系統為例子,來說明一致性哈希算法的用武之地。

對於集群來說,機器多了就不好管理,必然會有機器物理故障,業務擴縮容也非常正常,機器的調整必然帶來數據的遷移。

如果存儲集群中有5臺機器,如果這時有讀寫請求,就需要考慮從哪臺機器操作數據,一般有幾種方法:

各種方法都有各自的優缺點:

輪詢策略請求均勻分配,但當伺服器有性能差異,無法按性能分發;哈希取模如果機器動態變化會導致路由產生變化,數據產生大量遷移。

實際中對於規模較小的系統來說,哈希取模策略應用很廣泛,接下來重點介紹hash取模和一致性哈希的區別與聯繫

4. 哈希取模的原理和優缺點

Hash取模策略是其中常用的一種做法,它可以保證相同請求相同機器處理,這是一種並行轉串行的方法,工程中非常常見。

如果數據相對獨立,就避免了線程間的通信和同步,實現了無鎖化處理,所以還是很有用的。

index = hash_fun(key) % N

從上面的普通hash取模公式可以看到,如果N不變或者可以自己主動控制,就可以實現數據的負載均衡和無鎖化處理,但是一旦N的變化不被控制,那麼就會出現問題。

來看看哈希取模策略是如何應對擴縮容問題的,特別注意,為了簡化問題模型,接下來的例子不考慮實例的主從配置。

目前有N=4臺機器S1-S4,請求拼接key通過hash函數%N,獲取指定的機器序號,並將請求轉發至該機器。

S3機器因為磁碟故障而宕機,這時代理層獲得故障報警調整N=3,這時就出現了問題,如果作為緩存使用,S3機器上的所有key都將出現CacheMiss。

原來存放在S1的key=abc使用新的N,被調整到S4,這樣abc也出現CacheMiss,因為在S4上找不到abc的數據。

這種場景就是牽一髮而動全身,在緩存場景中會造成緩存擊穿,如果量很大會造成緩存雪崩。

由於S3宕機了,因此管理員增加了一臺機器S5,代理層再次調整N=4,此時又將出現類似於階段二的數據遷移,仍然會出現CacheMiss的情況。

5.一致性哈希算法

先來看看維基百科的英文定義:

in computer science, consistent hashing is a special kind of hashing such that when a hash table is resized, only  K/n keys need to be remapped on average, where K is the number of keys, and n is the number of slots.

簡單翻譯一下:

一致哈希 是一種特殊的哈希算法。  

在使用一致哈希算法後,哈希表槽位數(大小)的改變平均只需要對K/n 個關鍵字重新映射,其中 K是關鍵字的數量,n是槽位數量。  

在傳統的哈希表中,添加或刪除一個槽位的幾乎需要對所有關鍵字進行重新映射。

從定義可以知道,一致性哈希是一種特殊的哈希算法,區別於哈希取模,這種特殊的哈希算法實現了少量數據的遷移,避免了幾乎全部數據的移動,這樣就解決了普通hash取模的動態調整帶來的全量數據變動。

這個有點厲害了,趕緊看看是咋實現的。

5.1 一致性哈希算法思想

先不看算法的具體實現,先想想普通hash取模的問題根源是什麼?

沒錯!根源就在於N的變動和數據歸屬問題。

那麼如果N被固定住呢?

如果讓N很大,那麼每次被移動的key數就是K_all/Slot_n,也就是有槽位的概念,或者說是小分片的概念,直白一點就是雞蛋放到了很多很多的固定數量的籃子裡:

Key_all 存儲的全部key的數量
Slot_n 總的槽位或者分片數
Min_Change 為最小移動數量 
Min_change = Key_all/Slot_n
Min_change 也是數據的最小分片Shard

這裡還有一個問題要解決,將N固定且設置很大之後,數據分片shard變得非常小了,這時就有shard的所屬問題。

也就是比如N=100w,此時集群有10臺,那麼每臺機器上理論上平均有10w,當然可以根據機器的性能來做差異化的歸屬配置,性能強的多分一些shard,性能差的少分一些shard。

問題到這裡,基本上已經守得雲開見月明了,不過還是來看看1997年麻省理工發明的一致性哈希算法原理吧。

5.2 Karger的一致性哈希算法

一致性哈希算法在1997年由麻省理工學院的Karger等人在解決分布式Cache中提出的,設計目標是為了解決網際網路中的熱點(Hot spot)問題,初衷和CARP十分類似。

一致性哈希修正了CARP使用的簡單哈希算法帶來的問題,使得DHT可以在P2P環境中真正得到應用。

一起看看Karger的一致性哈希算法的基本原理以及如何應對擴縮容問題的。

正如我們前面的思考,Karger的一致性哈希算法將N設置為2^32,形成了一個0~(2^32-1)的哈希環,也就是相當於普通Hash取模時N=2^32。

在將數據key進行hash計算時就落在了0~(2^32-1的哈希環上,如果總的key數量為Sum,那麼單個哈希環的最小單位上的key數就是:

Unit_keys = Sum/2^32

由於N非常大所以哈希環最小單位的數據量unit_keys小了很多。

將伺服器結點也作為一種key分發到哈希環上:

con_hash(ip_key)%2^32

一致性哈希算法使用順時針方法實現結點對哈希環shard的歸屬,但是由於伺服器結點的數量相比2^32會少非常多,因此很稀疏,就像宇宙空間中的天體,你以為天體很多,但是相比浩渺的宇宙還是空空如也。

實體伺服器結點少量相比哈希環分片數據很少,這種特性決定了一致性哈希的數據傾斜,由於數量少導致服務節點分布不均,造成機器負載失衡。

如圖所示,伺服器1的負載遠大於其他機器:

這個說白了伺服器結點不夠,就讓伺服器的磁碟、內存、CPU全去佔位置,現實生活中也這樣:12306出來之前,火車站連夜排隊買票,這時什麼書包、水杯、眼鏡都代表了張三、李四、王二麻子。

同樣的道理,將伺服器結點根據某種規則來虛擬出更多結點,但是這些虛擬節點就相當於伺服器的分身。

比如採用如下規則在ip後綴增加#index,來實現虛擬節點的定位:

vnode_A_index = con_hash(ip_key_#A)%2^32
vnode_B_index = con_hash(ip_key_#B)%2^32
...
vnode_k_index = con_hash(ip_key_#k)%2^32

這是由於引入了虛擬節點,因此虛擬節點的分片都要實際歸屬到真實的服務節點上,因此在實際中涉及到虛擬節點和實體結點的映射問題。

當管理員新增了伺服器4時,原來在伺服器3和伺服器1之間分布的哈希環單元上的數據,將有一部分遷移到伺服器4,當然由於虛擬節點的引入,這部分數據遷移不會很大。

並不是伺服器4和伺服器1之間的數據都要順時針遷移,因此這樣就實現了增加機器時,只移動少量數據即可。

當伺服器結點2發生宕機,此時需要被摘除進行故障轉移,原來S2以及其虛擬節點上的數據都將進行順時針遷移到下一個實體結點或者虛擬結點。

6. Redis的一致性哈希實現

Redis cluster 擁有固定的16384個slot,slot是虛擬的且被分布到各個master中,當key 映射到某個master 負責slot時,就由對應的master為key 提供服務。

每個Master節點都維護著一個位序列bitmap為16384/8位元組,也就是Master使用bitmap的原理來表徵slot的下標,Master 節點通過 bit 來標識哪些槽自己是否擁有,比如對於編號為1的槽,Master只要判斷序列的第二位是不是為1即可。

這樣就建立了分片和服務結點的所屬關係,所以整個過程也是兩個原則,符合上文的一致性哈希的思想。

hash_slot_index =CRC16(key) mod 16384

7. 思考和總結

通過前面的對比和理解,我們有必要思考一下,一致性哈希算法的精髓。

7.1 一致性哈希算法的兩個關鍵點

一致性哈希算法是一種特殊的哈希算法,特殊之處在於將普通哈希取模的N進行固定,從而確保了相同的key必然是相同的位置,從而避免了牽一髮而動全身的問題,這是理解一致性哈希的關鍵。

一致性哈希算法的另外一個要點就是將N固定且設置很大之後,實際上就是進行數據分片Sharding,分布的小片就要和實際的機器產生關聯關係,也就是哪臺機器負責哪些小分片。

但是一致性哈希算法並不是從徹底解決了由於動態調整伺服器數據產生的數據遷移問題,而是將原來普通哈希取模造成的幾乎全部遷移,降低為小部分數據的移動,是一種非常大的優化。

個人認為,一致性哈希算法的關鍵有兩點:

7.2 算法的其他工程版本

像Redis並沒有使用2^32這種哈希環,而是採用了16384個固定slot來實現的,然後每個伺服器Master使用bitmap來確定自己的管轄slot。

管理員可以根據機器的配置和負載情況進行slot的動態調整,基本上解決了最開始的幾種負載均衡策略的不足。

所以假如讓你設計一個一致性哈希算法,只要把握兩個原則即可,並不是只有麻省理工Karger的一種哈希算法,它只是提供了一種思想和方向。

7.3 關於一致性哈希算法的命名

回到最初的疑問:為什麼要用"一致性哈希算法" 這個名字。

英文原文是Consistent hashing,其中Consistent譯為"一致的,連貫的",我覺得連貫的更貼切一些,以為這種特殊的哈希算法實現了普通哈希取模算法的平滑連貫版本,稱為連貫性哈希算法,好像更合適,一點愚見,水平有限,看看就完事了。

相關焦點

  • 什麼是一致性哈希算法
    這裡主要記錄一致性Hash算法如何將數據分配到各個機器中去。2,衡量一致性哈希算法好處的四個標準①平衡性。平衡性是指哈希的結果能夠儘可能分布到所有的緩衝中去,這樣可以使得所有的緩衝空間都得到利用。②單調性。
  • 10分鐘了解一致性哈希算法,全網(小區區域網)(建議收藏)
    很多同學應該都知道什麼是哈希函數,在後端面試和開發中會遇到「一致性哈希」,那麼什麼是一致性哈希呢?名字聽起來很厲害的樣子,其實原理並不複雜,這篇文章帶你徹底搞懂一致性哈希!進入主題前,先來一場緊張刺激的模擬面試吧。
  • 一文搞懂負載均衡中的一致性哈希算法
    不同領域場景不同,需要顧及的因素也有所差異,本文主要討論在負載均衡中一致性哈希算法的設計。在介紹一致性哈希算法之前,我將會介紹一些哈希算法,討論它們的區別和使用場景。也會給出一致性哈希算法的 Java 通用實現,可以直接引用,文末會給出 github 地址。
  • 面試時遇到一致性哈希算法這樣回答會讓面試官眼前一亮
    面試中一致性哈希算法被問到的概率非常大,本文將從如下三個方面探探一致性哈希算法,讓大家輕鬆應對面試,並且說出與眾不同的答案。一致性哈希算法經典實用場景一致性哈希算法通常不適合用於服務類負載均衡面試應對之策1、一致性哈希算法經典使用場景在資料庫存儲領域如果單表數據量很大,通常會採用分庫分表,在緩存領域同樣需要分庫,下面以一個非常常見的Redis分庫架構為例進行闡述。
  • Ceph殺手鐧CRUSH和主流分布式存儲一致性哈希算法
    PG:相當於一致性哈希算法裡的虛擬節點,做為Object的歸置組。OSD:真正的存儲組件,OSD一般和磁碟一一對應,處理存儲磁碟上的讀/寫操作。一致性哈希算法(Consistent Hashing)先簡單了解下一致性哈希算法(ConsistentHashing),和CRUSH算法有共同之處。
  • 面試必備:什麼是一致性Hash算法?
    ,問我有沒有相應的學習資料推薦,當時上班,沒時間回復,晚上回去了就忘了這件事,今天突然看到這個,加班為大家整理一下什麼是Hash一致性算法,希望對大家有幫助!也就是為什麼要有Hash一致性算法?就像以前介紹為什麼要有Spring一樣,首先會以歷史的角度或者項目發展的角度來分析,今天的分享還是一樣的套路,先從歷史的角度來一步步分析,探討一下到底什麼是Hash一致性算法!
  • 什麼是哈希算法
    這些算法可以分成普通哈希和加密哈希算法,兩種算法之間沒有特別明顯的區別。例如本來 MD5 就是設計出來做加密哈希的,但是後來由於計算機的發展 MD5 出現碰撞的可能性就很大了,所以目前 MD5 只能當普通哈希用,用來做數據校驗。
  • 圖解:什麼是哈希?
    哈希是對直接訪問表的改進。使用哈希函數將給定的電話號碼或任何其他鍵轉換為較小的數字,將該較小的數字稱為哈希表的索引(哈希值)什麼是哈希表?哈希表和直接訪問表很類似,同樣是一個用於存儲指向給定電話號碼對應記錄的指針的數組,只不過,此時的數組下標不再是電話號碼,而是經過哈希函數映射後的輸出值。什麼是哈希函數?
  • 和你聊聊哈希算法
    和你聊聊哈希算法1.1 引言哈希算法又稱散列函數算法,是一種查找算法,應該說哈希算法是最快的查找算法,沒有之一。對於查找問題,哈希算法一直是首選算法。那麼,為什麼名字起的這麼「嘻哈」的算法會如此強大,本文將為你揭開謎底。
  • 哈希算法現狀——原因、方法及未來
    多樣性和哈希算法的進化 開端:SHA1 & SHA2 美國國家安全局(NSA)一直都是哈希算法標準方面的先驅,他們最早提出安全哈希算法,也就是SHA1,這個算法輸出的是160位固定長度的字符串。
  • 五分鐘帶你了解哈希算法
    >其中一個初始哈希算法標準是MD5哈希,這是被廣泛用來進行文件整合驗證,而且存儲哈希密碼在網頁應用資料庫。哈希算法和工作量證明當考慮到整合哈希算法到區塊鏈協議中的時候,比特幣使用了比較舊的SHA256算法,但是以太坊使用了修改後的SHA3算法,作為工作量證明的算法。選擇工作量證明區塊鏈的哈希功能是很重要的部分,但是計算的效率稱為哈希。比特幣SHA256算法通過特定的硬體ASIC,進行有效計算。
  • AITD小課堂第十二課:哈希算法是什麼?非對稱加密是什麼?
    哈希算法是什麼? 區塊鏈的四大核心技術分別是密碼學、分布式帳本、共識機制以及智能合約。而密碼學作為其中最重要的一部分,可以說是區塊鏈的基石,而其他技術是以密碼學為地基,才能搭建出區塊鏈這座高樓大廈。
  • 理解數字籤名、加密通信的關鍵:哈希算法
    首先說哈希算法有很多種,例如 md5 ,SHA256 等等,但是它們總體上可以分為兩大類,一類是普通哈希,另外一類是加密哈希,cryptographic hash function 。  業界可以找到的哈希算法是有很多種的。我們可以大致按照輸出的哈希的長度來聊,雖然哈希算法的安全性也不單單是跟哈希長度有關,但是一般哈希值越長也就是越安全。
  • 關於哈希算法,必須了解這三點
    任意輸入值(Message)的二進位編碼經過哈希函數計算後,可以得出n比特的一個0、1字符串的哈希值,在不同算法中n的取值可能不同,例如128、160、192、256、384或512等。哈希算法在區塊鏈技術中得到了廣泛的應用,各個區塊之間通過哈希指針連接形成區塊鏈,每個區塊的完整性檢驗將以哈希運算的方式進行。
  • 千萬級高並發之Redis集群的一致性Hash算法?看完就明白了
    redis存在的問題,所有的緩存數據是分散存放在各個Redis節點上的,通過客戶端實現路由算法,來將某個key路由到某個具體的節點。下面簡單的了解下 hash算法一致性Hash概述為了能直觀的理解一致性hash原理,這裡結合一個簡單的例子來講解,假設有4臺伺服器,地址為ip1,ip2,ip3,ip4。
  • 什麼是哈希運算
    哈希算法(Hash Algorithm)即散列算法的直接音譯。
  • Comunion 區塊鏈深度學習系列|哈希算法的應用
    此時可以把這7個數據看成一個整體,前面6個數據是X,把X放在哈希函數裡面,會出來一個值,比如說Y值。由於比特幣網絡裡使用的哈希算法是SHA-256,當Y值出來之後,就會得到一個256個由0和1組成的字符串。這個字符串出來之後,它會和X裡面的難度值比較大小。
  • 分布式一致性算法:Raft 算法
    Raft 算法是可以用來替代 Paxos 算法的分布式一致性算法,而且 raft 算法比 Paxos 算法更易懂且更容易實現。本文對 raft 論文進行翻譯,希望能有助於讀者更方便地理解 raft 的思想。
  • 比特幣的加密本質: 哈希函數是什麼?
    什麼是哈希?  加密哈希函數是在數字數據上運行的數學運算。在比特幣中,所有操作都使用SHA256作為底層加密哈希函數。  安全哈希算法是由美國國家安全局(NSA)設計的一套加密哈希函數。  1)毫不含糊:哈希 (輸出)就像輸入數據的指紋。
  • Hash(哈希)算法科普
    單向散列函數算法也稱Hash(哈希)算法,是一種將任意長度的消息壓縮到某一固定長度(消息摘要)的函數(該過程不可逆)。