欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java一致性Hash算法的實現(xiàn)詳解

 更新時間:2024年01月26日 09:45:22   作者:ZhaoJuFei  
這篇文章主要介紹了Java一致性Hash算法的實現(xiàn)詳解,hash的意思是散列,目的將一組輸入的數(shù)據(jù)均勻的分開、打散,往往用來配合路由算法做負載均衡,多用在分布式系統(tǒng)中,需要的朋友可以參考下

 哈希hash

hash的意思是散列,目的將一組輸入的數(shù)據(jù)均勻的分開、打散,往往用來配合路由算法做負載均衡,多用在分布式系統(tǒng)中。

比如memcached它只提供了K V的存儲、讀取,如果使用了多臺memcache做一個“邏輯集群”,就需要客戶端做“路由算法”,來保證數(shù)據(jù)均勻的進去,然后能“原路”拿出來。

常規(guī)哈希取模

常規(guī)哈希,往往結(jié)合取模運算,以便將請求轉(zhuǎn)發(fā)到后端的服務(wù)器上,如下圖:

第一步使用hash算法,將請求“打散”得到一個整數(shù)(比如傳遞過來一個請求,使用jdk類庫的hash對某個參數(shù)做計算),第二步將得到的參數(shù)對后端的服務(wù)器臺數(shù)取模,以上圖為例,加上有三臺服務(wù)器,那么id分別為1~6的請求會被轉(zhuǎn)發(fā)到1,2,0,1,2,0,上,不管請求id數(shù)是多少,總是這么周而復(fù)始的轉(zhuǎn)發(fā)。

假設(shè)上面是個緩存系統(tǒng),以上請求為set請求,在服務(wù)器數(shù)量不變的情況下,對同樣的id做get請求,由于采用同樣的hash算法,那么肯定能原路找到對應(yīng)的key值。這個算法簡單,而且數(shù)據(jù)分散的均勻。

如果系統(tǒng)訪問量突增,為了擴容加了一臺機器,編號為3,此時有了4臺機器,采用同樣的算法再去get請求會如何?比如id=6,這個時候 6%4=2,我們知道set時值其實放進了索引為0的機器,這個時候就get不到了。這就是上面算法的弊端,在增減機器時會使舊的數(shù)據(jù)大量“失效”,也就是命中率下降。

不帶虛擬節(jié)點的一致性哈希算法

為了解決以上問題,聰明的人發(fā)明了一致性哈希算法。思路是這樣,hash算法出來的整數(shù)有個范圍,我們在這個范圍內(nèi)布置三臺服務(wù)器(范圍具體是多少看前面的hash算法)。假設(shè)hash的范圍是1~300,每臺負責(zé)一段范圍內(nèi)的請求,比如一臺負責(zé)(1~100],一臺負責(zé)(100~200],一臺負責(zé)(200~1]。這三臺server收尾相接覆蓋/閉環(huán)了所有請求,稱為哈希環(huán),如下圖:

如何實現(xiàn)一臺服務(wù)器接收一個范圍的請求?這個時候不用取模了,而是將server也按照hash算法計算一個id值,比如按照他們的ip+port+name拼成的串計算,假設(shè)正好分別是 1,100,200,將他們放進一個treeMap里,Map<Inetger,Node> ,其中Node代表server節(jié)點,是自定義的數(shù)據(jù)結(jié)構(gòu),比如是一個類,包含ip,port,name等屬性。我們的例子中,map里包含三個元素。

一個請求過來hash得到的值必屬于這三個server的范圍,比如一個請求id=N,那么從map里get(N)去找server,找到直接轉(zhuǎn)發(fā),找不到進行如下運算:treemap里有個關(guān)鍵的api,tailMap(),這個接口能夠返回id比N大的map的子集,然后取子集的第一個節(jié)點,就是id=100的節(jié)點,通常稱為順時針查找。

//得到應(yīng)當(dāng)路由到的結(jié)點(示例代碼用String代表的節(jié)點)
private static String getServer(String key) {
	//得到該key的hash值
	int hash = getHash(key);
	//得到大于該Hash值的所有Map
	SortedMap<Integer, String> subMap = sortedMap.tailMap(hash);
	if(subMap.isEmpty()){
		//如果沒有比該key的hash值大的,則從第一個node開始
		Integer i = sortedMap.firstKey();
		//返回對應(yīng)的服務(wù)器
		return sortedMap.get(i);
	}else{
		//第一個Key就是順時針過去離node最近的那個結(jié)點
		Integer i = subMap.firstKey();
		//返回對應(yīng)的服務(wù)器
		return subMap.get(i);
	}
}

當(dāng)然如果子集為空,這意味著N>200,就取整個map的第一個節(jié)點,完成閉環(huán)。

分析:從實現(xiàn)可以看出,如果一個節(jié)點掛了,他的流量會順時針(逆時針實現(xiàn)也是一樣的)“導(dǎo)流”到下一個節(jié)點,其他節(jié)點不受影響。假如有100臺服務(wù)器,一臺掛了,其他99臺都能正常命中!這個算法比簡單的取模好了很多。

不過這里仍有個問題,假設(shè)各臺服務(wù)器性能差不多,此時流量突增,一臺server由于流量過載而掛掉,那么它的下一臺因為承載了2倍的流量,很有可能也會掛掉,依此類推,最后所有的節(jié)點都會掛掉,造成“雪崩”!

因此正常情況下,我們往往采用帶虛擬節(jié)點的一致性哈希算法(不特別說明的一致性哈希算法一般都是指的帶虛擬節(jié)點的算法)。

帶虛擬節(jié)點的一致性哈希算法

帶虛擬節(jié)點的一致性哈希算法是為了解決不帶虛擬節(jié)點算法的雪崩問題,虛擬節(jié)點也稱為分片。在上一步的基礎(chǔ)上理解虛擬節(jié)點是非常容易的。“虛擬”節(jié)點是server的副本、分身,每個虛擬節(jié)點存儲的server信息還是后面的物理地址,只不過每個server由一臺變成了多臺,這個時候往treeMap放節(jié)點時往往這么做:

for(i=1  -->  N) // N為每個server對應(yīng)的分片數(shù)量
{
   Map.put(hash(ip+port+name+i),node) // 所有虛擬節(jié)點放進去
}
這個for循環(huán)外面還會有個循環(huán),處理所有server node

由于每個server的ip,name不同,所以以上拼串hash后的值碰撞的概率是很小的,這樣所有的虛擬節(jié)點也會離散的分部到環(huán)上,形成的hash環(huán)如下圖,同樣顏色的虛擬節(jié)點同屬于一個server。

這個時候如果紅顏色的server掛了,它的虛擬節(jié)點負責(zé)的范圍會分別導(dǎo)航到下一個虛擬節(jié)點上,這些虛擬節(jié)點分別屬于不同的server,就避免了流量全部導(dǎo)流到一臺機器上。由于流量被均攤了,有效的減少了雪崩發(fā)生的概率。(理論上仍存在虛擬節(jié)點后面的虛擬節(jié)點屬于同一個server的情況,但是當(dāng)虛擬節(jié)點非常多時,這個概率是非常小的,而且這個分片數(shù)量是自定義的,往往設(shè)置幾百個)。

只要是hash算法,就有哈希碰撞的可能性,在增加server時,計算后的虛擬節(jié)點跟其他server的虛擬節(jié)點重復(fù)的話,也會導(dǎo)致部分緩存失效(可以通過算法改良)。

綜上,一致性哈希算法并不是強一致性,也不是高可用方案,如果server掛了數(shù)據(jù)丟了就是丟了,除非有恢復(fù)手段,它只是一種減少由擴縮容引起的命中率下降的手段。

到此這篇關(guān)于Java一致性Hash算法的實現(xiàn)詳解的文章就介紹到這了,更多相關(guān)Java一致性Hash算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java生成在線驗證碼

    java生成在線驗證碼

    這篇文章主要介紹了java生成在線驗證碼,需要的朋友可以參考下
    2023-10-10
  • Java日志軟件Log4j的基本使用教程

    Java日志軟件Log4j的基本使用教程

    這篇文章主要介紹了Java日志軟件Log4j的基本使用教程,包括回滾和發(fā)送日志郵件等基本功能使用的講解,需要的朋友可以參考下
    2015-12-12
  • Windows下Java環(huán)境配置的超詳細教程

    Windows下Java環(huán)境配置的超詳細教程

    這篇文章主要給大家介紹了關(guān)于Windows下Java環(huán)境配置的超詳細教程,文中通過圖文將配置的過程介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-01-01
  • spring boot 監(jiān)聽容器啟動代碼實例

    spring boot 監(jiān)聽容器啟動代碼實例

    這篇文章主要介紹了spring boot 監(jiān)聽容器啟動代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • Java--Socket通信(客戶端服務(wù)端雙向)

    Java--Socket通信(客戶端服務(wù)端雙向)

    這篇文章主要介紹了Java--Socket通信(客戶端服務(wù)端雙向),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • Java實現(xiàn)單例模式之餓漢式、懶漢式、枚舉式

    Java實現(xiàn)單例模式之餓漢式、懶漢式、枚舉式

    本篇文章主要介紹了Java實現(xiàn)單例的3種普遍的模式,餓漢式、懶漢式、枚舉式。具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2016-10-10
  • java WebSocket實現(xiàn)聊天消息推送功能

    java WebSocket實現(xiàn)聊天消息推送功能

    這篇文章主要為大家詳細介紹了java WebSocket實現(xiàn)聊天消息推送功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • IDEA EasyCode 一鍵幫你生成所需代碼

    IDEA EasyCode 一鍵幫你生成所需代碼

    這篇文章主要介紹了IDEA EasyCode 一鍵幫你生成所需代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Java 獲取上一個月的月份的正確寫法

    Java 獲取上一個月的月份的正確寫法

    這篇文章主要介紹了java獲取上一個月月份,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • java 漢諾塔詳解及實現(xiàn)代碼

    java 漢諾塔詳解及實現(xiàn)代碼

    這篇文章主要介紹了java 漢諾塔詳解及實現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下
    2017-04-04

最新評論