面試時遇到一致性哈希算法這樣回答會讓面試官眼前一亮

面試中一致性哈希算法被問到的概率非常大,本文將從如下三個方面探探一致性哈希算法,讓大家輕鬆應對面試,並且說出宇宙不同的答案。

  • 一致性哈希算法經典實用場景
  • 一致性哈希算法通常不適合用於服務類負載均衡
  • 面試應對之策

1、一致性哈希算法經典使用場景

在數據庫存儲領域如果單表數據量很大,通常會採用分庫分表,同樣在緩存領域同樣需要分庫,下面以一個非常常見的Redis分庫架構爲例進行闡述。
在這裏插入圖片描述
將上述3個Redis節點稱之爲分片,每一個節點存儲部分數據,期間需要使用負載均衡算法,將數據儘量分攤到各個節點,充分發揮分佈式的優勢,提升系統緩存訪問的性能。

在分佈緩存領域,對數據存在新增與查詢,即數據通過路由算法存儲在某一個節點後,查詢時需要儘量路由到同一個節點,否則會出現查詢未命中緩存的情況,這也是與分佈式服務調用領域的負載算法一個不同點。

分佈式緩存存儲類領域的負載均衡算法通常會使用某一個字段當分片鍵,在進行負載之前先求出分片字段對應的HashCode,然後與當前的節點數取模。即 hashcode(分片鍵) % 節點總數(分片總數)

1.1 在分佈式緩存領域上述算法的弊端

先哈希再驅魔實現起來簡單高效,但在分佈式緩存領域存在一個致命的痛點,對擴容、縮容不友好,會降低緩存的命中率。

因擴容引起的數據命中率問題示意圖如下:
在這裏插入圖片描述
例如當前集羣中由3個節點存儲,例如現在向集羣中寫入6個數據,其分片鍵的hashcode爲1-6,數據的分佈情況如上述所示,但由於隨着業務的急劇增長,3臺redis已經無法滿足業務的需求,項目組決定對其進行擴容,從原先的3臺擴容到4臺,這個時候項目組嘗試去緩存中查找 k1,k2,k3,k4,k5,k6時會出現什麼問題?

根據 hashcode 再取模的方式,由於數量從3臺到4臺,經路由算法路由後,k4 會嘗試從3.169的機器去查找,但對應的數據卻存儲在3.166上,以上面6個key的命中來看,只有50%的命中率,擴容後帶來緩存穿透,大量數據進入到後臺數據庫。

在數據存儲領域的第一種解決方案:成倍擴容。將原來的3個節點數量擴充倍,新增加的第一臺數據來源於第一臺,以此類推,第6臺的數據來源於第3臺,這樣k6經過新的負載均衡算法會落到第6臺,數據原本存在於第3臺,而第6臺的數據來源於第3臺,這樣避免了緩存穿透

成倍擴容能有效解決擴容後帶來的緩存穿透問題,但這樣做會造成資源的浪費,有沒有其他更好的方法呢?

一致性哈希算法閃亮登場。

1.2 一致性哈希算法

一致性哈希算法

一致性哈希算法的設計理念如下圖所示:
在這裏插入圖片描述
首先將哈希值映射到 0 ~ 2的32次方的一個圓中,然後將實際的物理節點的IP地址或取其hash值,放入到hash環中。

然後對需要插入的數據先求哈希,再順時針沿着哈希環,找到第一個實際節點,數據將存儲到該實際節點上。

擴容後的示例圖:
在這裏插入圖片描述
從中可以看到受影響的範圍能控制在兩個節點的hashcode之間的部分數據,比起先哈希再取模,其未命中率將會得到極大的影響。

但一致性哈希算法要得到較好的效果,取決於各個實體節點在哈希環的分佈情況,是否能分散,例如如下分佈則會大打折扣:
在這裏插入圖片描述
這種情況會造成數據分佈不均衡,爲了解決數據很可能分佈不均勻的情況,對一致性哈希算法,提出了改進,引入了虛擬節點的,可以設置一個哈希環中存在多少個虛擬節點,然後將虛擬節點映射到實體節點,從而解決數據分佈吧均衡的問題。
在這裏插入圖片描述
這樣通過爲不同的的實際節點映射不同的虛擬節點,實現數據的均勻分佈,並且擴容或縮容時並不會出現大面積的緩存穿透。



溫馨提示:上述的映射只是一個理想狀態,其核心思路是爲每一個實體節點創建多個虛擬節點,並且核心虛擬節點的Hash值越分散越好。

大家可以思考一下,如何用JAVA來實現一致性哈希算法?

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

  • 順時針選擇節點
    可以使用TreeMap,一來具備排序功能,天然提供了相應的方法獲取順時針的一個元素。
    TreeMap 的 ceilingEntry()方法用於返回與大於或等於給定鍵元素(ele)的最小鍵元素鏈接的鍵值對。

  • 虛擬節點如何生成分散的哈希值
    生成分散的哈希值,通常可以基於md5加密算法來實現。
    在這裏插入圖片描述

2、一致性哈希算法被“濫用”

一致性哈希算法在面對分佈式緩存有着得天獨厚的優勢,因爲它的產生就是爲了解決分佈式緩存擴容、縮容帶來的緩存穿透問題。但現在一致性在分佈式服務調用的負載算法竟然也引入了一致性哈希算法。

在Dubbo中爲了實現客戶端在服務調用時對服務提供者進行負載均衡,官方也提供了一致性哈希算法;在RocketMQ集羣消費模式時消費隊列的負載均衡機制竟然也實現了一致性哈希算法,但我覺得一致性哈希算法在這些領域完全無法發揮其他優勢,比輪循、加權輪循、隨機、加權隨機算法等負載均衡算法相比,實現複雜,性能低下,運維管理複雜

因爲在服務調用等負載均衡算法,多次服務調用之間關聯性不太強,在服務端擴容、縮容後,對於客戶端來說其實並不關心路由到哪臺服務器,其關心的是能否返回一臺服務器即可。

3、面試應對之策

在面試過程中,遇到一致性哈希算的時候,儘量能從其使用場景:分佈式緩存負載均衡,特別是突出擴容、縮容能有效避免緩存穿透的問題。同時需要闡述一致性哈希算法的缺陷以及其應對策略(虛擬節點)。

聊的差不多可以順便提一下閱讀過一致性哈希算法的源碼:強調TreeMap與虛擬節點哈希值的生成方法。

最後可以嘗試引導面試官聊聊現在一致性哈希算法有點被濫用的嫌疑,在輕鬆愉快的討論中與面試交流技術,面試官好評度蹭蹭往上漲。


歡迎加筆者微信號(dingwpmz),拉您如技術交流加羣探討,關注『中間件興趣圈』回覆**【PDF】**可獲取海量學習資料。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章