大白話聊聊面試中常問的一致性 Hash 算法!

當咱們在作數據庫分庫分表或者是分佈式緩存時,不可避免的都會遇到一個問題:
程序員

如何將數據均勻的分散到各個節點中,而且儘可能的在加減節點時能使受影響的數據最少。算法

Hash 取模sql

隨機放置就不說了,會帶來不少問題。一般最容易想到的方案就是 hash 取模了。數據庫

咱們能夠將傳入的 Key 按照 index = hash(key) % N 這樣來計算出須要存放的節點。其中 hash 函數是一個將字符串轉換爲正整數的哈希映射方法,N 就是節點的數量。緩存

這樣能夠知足數據的均勻分配,可是這個算法的容錯性和擴展性都較差。架構

好比增長或刪除了一個節點時,全部的 Key 都須要從新計算,顯然這樣成本較高,爲此須要一個算法知足分佈均勻同時也要有良好的容錯性和拓展性。併發

一致 Hash 算法分佈式

一致 Hash 算法是將全部的哈希值構成了一個環,其範圍在 0 ~ 2^32-1。函數

以下圖高併發


以後將各個節點散列到這個環上,能夠用節點的 IP、hostname 這樣的惟一性字段做爲 Key 進行 hash(key),散列以後以下:


以後須要將數據定位到對應的節點上,使用一樣的 hash 函數 將 Key 也映射到這個環上。


這樣按照順時針方向就能夠把 k1 定位到 N1節點,k2 定位到 N3節點,k3 定位到 N2節點。

容錯性

這時假設 N1 宕機了:


依然根據順時針方向,k2 和 k3 保持不變,只有 k1 被從新映射到了 N3。

這樣就很好的保證了容錯性,當一個節點宕機時只會影響到少少部分的數據。

拓展性

當新增一個節點時:


在 N2 和 N3 之間新增了一個節點 N4 ,這時會發現受印象的數據只有 k3,其他數據也是保持不變,因此這樣也很好的保證了拓展性。

虛擬節點

到目前爲止該算法依然也有點問題:當節點較少時會出現數據分佈不均勻的狀況:


這樣會致使大部分數據都在 N1 節點,只有少許的數據在 N2 節點。

爲了解決這個問題,一致哈希算法引入了虛擬節點。將每個節點都進行屢次 hash,生成多個節點放置在環上稱爲虛擬節點:


計算時能夠在 IP 後加上編號來生成哈希值。這樣只須要在原有的基礎上多一步由虛擬節點映射到實際節點的步驟便可讓少許節點也能知足均勻性。

歡迎工做一到五年的Java工程師朋友們加入Java程序員開發: 721575865

羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!

相關文章
相關標籤/搜索