最近有小夥伴跑過來問什麼是Hash一致性算法,說面試的時候被問到了,由於不瞭解,因此就沒有回答上,問我有沒有相應的學習資料推薦,當時上班,沒時間回覆,晚上回去了就忘了這件事,今天忽然看到這個,加班爲你們整理一下什麼是Hash一致性算法,但願對你們有幫助!html
常常閱讀我文章的小夥伴應該都很熟悉我寫文章的套路,上來就是先要問一句爲何?也就是爲何要有Hash一致性算法?就像之前介紹爲何要有Spring同樣,首先會以歷史的角度或者項目發展的角度來分析,今天的分享仍是同樣的套路,先從歷史的角度來一步步分析,探討一下到底什麼是Hash一致性算法!面試
咱們在使用Redis的時候,爲了保證Redis的高可用,提升Redis的讀寫性能,最簡單的方式咱們會作主從複製,組成Master-Master或者Master-Slave的形式,或者搭建Redis集羣,進行數據的讀寫分離,相似於數據庫的主從複製和讀寫分離。以下所示: 算法
假設,咱們有一個社交網站,須要使用Redis存儲圖片資源,存儲的格式爲鍵值對,key值爲圖片名稱,value爲該圖片所在文件服務器的路徑,咱們須要根據文件名查找該文件所在文件服務器上的路徑,數據量大概有2000W左右,按照咱們約定的規則進行分庫,規則就是隨機分配,咱們能夠部署8臺緩存服務器,每臺服務器大概含有500W條數據,而且進行主從複製,示意圖以下:數據庫
因爲規則是隨機的,全部咱們的一條數據都有可能存儲在任何一組Redis中,例如上圖咱們用戶查找一張名稱爲"a.png"的圖片,因爲規則是隨機的,咱們不肯定具體是在哪個Redis服務器上的,所以咱們須要進行一、二、三、4,4次查詢纔可以查詢到(也就是遍歷了全部的Redis服務器),這顯然不是咱們想要的結果,有了解過的小夥伴可能會想到,隨機的規則不行,可使用相似於數據庫中的分庫分表規則:按照Hash值、取模、按照類別、按照某一個字段值等等常見的規則就能夠出來了!好,按照咱們的主題,咱們就使用Hash的方式。後端
可想而知,若是咱們使用Hash的方式,每一張圖片在進行分庫的時候均可以定位到特定的服務器,示意圖以下:緩存
上圖中,假設咱們查找的是"a.png",因爲有4臺服務器(排除從庫),所以公式爲hash(a.png) % 4 = 2
,可知定位到了第2號服務器,這樣的話就不會遍歷全部的服務器,大大提高了性能!服務器
上述的方式雖然提高了性能,咱們再也不須要對整個Redis服務器進行遍歷!可是,使用上述Hash算法進行緩存時,會出現一些缺陷,主要體如今服務器數量變更的時候,全部緩存的位置都要發生改變!微信
試想一下,若是4臺緩存服務器已經不能知足咱們的緩存需求,那麼咱們應該怎麼作呢?很簡單,多增長几臺緩存服務器不就好了!假設:咱們增長了一臺緩存服務器,那麼緩存服務器的數量就由4臺變成了5臺。那麼本來hash(a.png) % 4 = 2
的公式就變成了hash(a.png) % 5 = ?
, 可想而知這個結果確定不是2的,這種狀況帶來的結果就是當服務器數量變更時,全部緩存的位置都要發生改變!換句話說,當服務器數量發生改變時,全部緩存在必定時間內是失效的,當應用沒法從緩存中獲取數據時,則會向後端數據庫請求數據(還記得上一篇的《緩存雪崩》嗎?)!網絡
一樣的,假設4臺緩存中忽然有一臺緩存服務器出現了故障,沒法進行緩存,那麼咱們則須要將故障機器移除,可是若是移除了一臺緩存服務器,那麼緩存服務器數量從4臺變爲3臺,也是會出現上述的問題!多線程
因此,咱們應該想辦法不讓這種狀況發生,可是因爲上述Hash算法自己的緣故,使用取模法進行緩存時,這種狀況是沒法避免的,爲了解決這些問題,Hash一致性算法(一致性Hash算法)誕生了!
一致性Hash算法也是使用取模的方法,只是,剛纔描述的取模法是對服務器的數量進行取模,而一致性Hash算法是對2^32取模,什麼意思呢?簡單來講,一致性Hash算法將整個哈希值空間組織成一個虛擬的圓環,如假設某哈希函數H的值空間爲0-2^32-1(即哈希值是一個32位無符號整形),整個哈希環以下:
下一步將各個服務器使用Hash進行一個哈希,具體能夠選擇服務器的IP或主機名做爲關鍵字進行哈希,這樣每臺機器就能肯定其在哈希環上的位置,這裏假設將上文中四臺服務器使用IP地址哈希後在環空間的位置以下:
例如咱們有Object A、Object B、Object C、Object D四個數據對象,通過哈希計算後,在環空間上的位置以下:
現假設Node C不幸宕機,能夠看到此時對象A、B、D不會受到影響,只有C對象被重定位到Node D。通常的,在一致性Hash算法中,若是一臺服務器不可用,則受影響的數據僅僅是此服務器到其環空間中前一臺服務器(即沿着逆時針方向行走遇到的第一臺服務器)之間數據,其它不會受到影響,以下所示:
下面考慮另一種狀況,若是在系統中增長一臺服務器Node X,以下圖所示:
綜上所述,一致性Hash算法對於節點的增減都只需重定位環空間中的一小部分數據,具備較好的容錯性和可擴展性。
一致性Hash算法在服務節點太少時,容易由於節點分部不均勻而形成數據傾斜(被緩存的對象大部分集中緩存在某一臺服務器上)問題,例如系統中只有兩臺服務器,其環分佈以下:
例如上面的狀況,能夠爲每臺服務器計算三個虛擬節點,因而能夠分別計算 「Node A#1」、「Node A#2」、「Node A#3」、「Node B#1」、「Node B#2」、「Node B#3」的哈希值,因而造成六個虛擬節點:
上文中,咱們一步步分析了什麼是一致性Hash算法,主要是考慮到分佈式系統每一個節點都有可能失效,而且新的節點極可能動態的增長進來的狀況,如何保證當系統的節點數目發生變化的時候,咱們的系統仍然可以對外提供良好的服務,這是值得考慮的!
參考文章:
一、www.cnblogs.com/lpfuture/p/… 二、www.zsythink.net/archives/11…