Redis中的一致性哈希問題


在說redis中的哈希(准確來說是一致性哈希)問題之前,先來看一個問題:為什么在分布式集群中一致性哈希會得到大量應用?

在一個分布式系統中,要將數據存儲到具體某個節點,或者將來自客戶端的請求分配到某個服務器節點做負載均衡,如果采用普通的hash取模算法進行映射,即如key.hashCode()%N,key代表數據的key,N是服務器節點數,使用上能達到預期效果。

但是如果此時要下線一個服務器或者上線一個新的服務器,那么原來的映射將全部失效。如果是做分布式存儲,則需要做數據遷移;如果是做分布式緩存,則原來的緩存失效,需要讓新增或下線的節點生效就需要做rehash,數據較大會比較消耗時間(其實這點對HashMap了解的,很熟悉這一點,HashMap在動態擴容進行rehash,數據量過大時很消耗時間影響性能)。這時,一致性哈希就派上用場了。

下面通過幾個問題逐步介紹redis2.X和redis3.X中的一些特性,來了解一致性哈希在redis中的應用,以及遇到的問題,不同版本是如何解決的。

1. 假如有兩台redis服務器,jedis客戶端要存入數據到這兩台服務器,它如何知道要存入哪台服務器?

這個就是開篇所說一般的做法:哈希取模。
key.hashcode() % nums(key是redis中的key,nums是redis服務器數)最終結果范圍:0到nums-1

2. 此時新增一台redis服務器,數據能寫入到新增的機器上嗎?不能。還是對原有redis服務器數進行取模。

那么如何解決這一問題呢?nums不定義為redis服務器具體數,而是一個比較大的值:2^32,從而映射到一個比較大的空間內,拿key.hashcode*()% 2^32-1來確定存入的服務器。最終會形成一個一致性哈希環,沿着這個環往下找,直至找到。

當然這里key.hashcode*()% 2^32-1只是舉個例子,實際生產中我們會采用哈希算法,如MD5、MurMurHash、crc32將數據映射到一個哈希環上。

3. 假如在新增一台redis服務器C前,數據存在節點A。加入C后,客戶端在操作的時候,會出現什么問題?

查找數據時,如果通過一致性哈希算法得出數據在C上,但真實數據在A上,客戶端在C上查找會找不到數據就會報空指針異常。
這個其實是在redis2.X中的問題,因為redis2.X不支持冬天擴容。這時我們可以考慮找一個合適的時間點如業務峰值低的時候,將環中的所有數據加載出來,灌入到另外一個新增節點后的環中進行處理。

4. redis3.X如何解決redis2.X的上述問題?

通過上面的問題可以得知redis2.X不支持動態加節點,就算成功加入新節點,數據會發生錯亂現象,而redis3.X解決了這個問題:

redis集群內置了16384個哈希槽,當需要在集群中插入數據時,先對key使用crc16算法得出一個結果,然后把結果對16384求余數。這樣每個key都會對應一個編號在0~16383之間的哈希槽,redis會根據節點數量大致均等的將哈希槽映射到不同節點。

redis集群的每個節點負責一部分哈希槽,這種結構很容易添加或者刪除節點,並且無論是添加刪除或者修改某一個節點,都不會造成集群不可用的狀態。哈希槽的好處在於可以方便的添加或移除節點:

1)當需要增加節點時,只需要把其他節點的某些哈希槽挪到新節點就可以了

2)當需要移除節點時,只需要把移除節點上的哈希槽挪到其他節點就行了

5. redis3.X的hash碰撞問題

通過hash映射,當某台機器上數據過多支撐不住導致宕機,此時它負責的數據會分配到其他機器,而redis集群服務器配置一般相同,其他機器也扛不住,就會造成雪崩,即便有主備也解決不了,最終可能導致整個集群都會掛掉。下圖演示了節點C宕機,C上的數據映射到D上的示例:

這其實就是分布式系統中極其常見的問題,數據傾斜。可以考慮通過如下方式解決:

1)如給大量相似數據即key相同,給key加上隨機串,將key打散盡可能隨機分配,避免數據傾斜
2)參考redis2.X版本中"虛擬節點"的做法,為每個真實節點引入N個虛擬節點。具體看下文

6. redis2.X是如何解決hash碰撞的問題?redis2.X有一個非常重要的概念:虛擬節點,每個節點都虛擬出160個虛擬節點。數據的存儲是沿着環的順時針方向找一個虛擬節點,每個虛擬節點都會關聯到一個真實節點。

圖中的A1、A2、B1、B2、C1、C2、D1、D2都是虛擬節點,機器A負載A1、A2的數據,機器B負載B1、B2的數據,機器C負載C1、C2的數據。由於這些虛擬節點數量很多,均勻分布,因此不會造成"雪崩"現象。


關注微信公眾號:大數據學習與分享,獲取更對技術干貨


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM