導航:首頁 > 源碼編譯 > 一致性哈希演算法java

一致性哈希演算法java

發布時間:2023-06-15 11:13:38

java去公司工作用到的是哪方面的知識

小公司做小項目一般都用SSH+jsp大公司做項目都是根據不同的項目 採取不同的框架技術,比如銀行大部分都用 EJB等

第一:先學習Java的核心庫(JavaSE)

JavaSE的內容包括:環境搭建、基礎語法、面向對象、數組、集合、常用類、IO流、反射機制、網路編程……..

第二:MySQL資料庫

搞定一門資料庫相關的課程,例如:MySQL、Oracle,搞定一個就可以了,目前互聯網公司,例如:京東、阿里等,他們都在使用MySQL,所以建議大家學習MySQL資料庫,小巧輕盈,免費,由於互聯網公司的項目訪問量比較大,所以一般會搭建資料庫的集群,可以一個資料庫不夠,所以需要搭建資料庫集群,為了應付高並發。(搭建的比較多的時候,免費就很重要了。)

第三:WEB前端

以後從事Java開發,從事JavaEE開發,主要開發的系統結構是B/S結構的,B指的是Browser,S指的是Server。要開發這種系統,B端要會,S端也要精通。WEB前端的學習就是學習B端技術。包括:HTML 、CSS、JavaScript(JS)、jQuery框架(底層對JS進行了封裝)…

第四:WEB後端(JavaWEB)

WEB後端其實可以是很多種不同的編程語言,例如:PHP、C、C++、Java,他們都可以進行WEB後端的開發,我們既然選擇了比較火爆的Java,那麼我們學習的後端一定是基於Java語言實現的,包括:Servlet、Filter、Jsp、EL、JSTL、MVC架構模式、資料庫連接池(阿里巴巴的Druid連接池)、代理模式(動態代理)。另外後端學習了之後,還要學習一個非同步編程技術AJAX。(完成網頁的局部刷新,AJAX其實不屬於後端,是前端瀏覽器上的程序。)

學習到這里為止,表示Java基本/基礎的技術已經學完了。但是這些最基層的技術在實際的開發中不會使用的,一般為了開發效率,都會使用大量的提前封裝好的框架。

第五:最好能夠停留下來,做一個項目。

這個項目最好能將之前所學全部串起來。(對以前的知識點進行鞏固。)

這個項目最好是基於:Servlet + Jsp+AJAX+jQuery+MySQL….

在這個項目的開發過程中:大家一定要記住,目前比較好的項目自動構建工具:Maven是一定要精通的。還有一個就是團隊協作開發:Git/SVN是一定要會用的。(目前使用Git比較多一些。)

第六:學習高級框架

Spring、SpringMVC、MyBatis(持久層框架,這個框架互聯網公司使用比較多,因為互聯網項目需要進行SQL優化,MyBatis的SQL優化很方便,所以大部分都是使用MyBatis)

Struts2(很少使用了,使用這個的肯定是很老的項目)、Hibernate(傳統企業,還有政府等可能會使用Hibernate。)

SpringBoot(新項目大部分使用的都是boot了。所以在項目中遇到還在使用SSM的一般都是遺留項目。)

當你走到這里之後,基本上你可以出山了。(去找工作,8K的薪資應該問題不大,但前提是你學的好。學習的深度夠了,廣度夠了。)

第七:最好能有一個大型項目是使用框架來完成的。

SpringBoot做一個項目。

Spring SpringMVC MyBatis做一個項目。

這個項目最好是找幾個人搭夥做一下。體驗一下團隊協作。(尤其是使用一些協作的工具。怎麼溝通,怎麼寫日報,怎麼開會,怎麼使用Git,等等….)

第八:如果你的薪資想達到15K的話,你可能需要還要學習一些分布式相關的一些技術。

能夠應付高並發的一些技術,例如:分布式框架Dubbo、SpringCloud、MQ、Nginx、Redis…..

java的知識體系構架

....祝 工作順心 哈哈

⑵ 如何正確實現Java中的hashCode方法

正確實現Java中的hashCode方法:
相等和哈希碼

相等是從一般的方面來講,哈希碼更加具有技術性。如果我們在理解方面存在困難,我們可以說,他們通過只是一個實現細節來提高了性能。
大多數的數據結構通過equals方法來判斷他們是否包含一個元素,例如:
List<String> list = Arrays.asList("a", "b", "c");
boolean contains = list.contains("b");

這個變數contains結果是true,因為,雖然」b」是不相同的實例(此外,忽略字元串駐留),但是他們是相等的。
通過比較實例的每個元素,然後將比較結果賦值給contains是比較浪費的,雖然整個類的數據結構進行了優化,能夠提升性能。
他們通過使用一種快捷的方式(減少潛在的實例相等)進行比較,從而代替通過比較實例所包含的每個元素。而快捷比較僅需要比較下面這些方面:
快捷方式比較即通過比較哈希值,它可以將一個實例用一個整數值來代替。哈希碼相同的實例不一定相等,但相等的實例一定具有有相同的哈希值。(或應該有,我們很快就會討論這個)這些數據結構經常通過這種這種技術來命名,可以通過Hash來識別他們的,其中,HashMap是其中最著名的代表。
它們通常是這樣這樣運作的
當添加一個元素,它的哈希碼是用來計算內部數組的索引(即所謂的桶)
如果是,不相等的元素有相同的哈希碼,他們最終在同一個桶上並且捆綁在一起,例如通過添加到列表。
當一個實例來進行contains操作時,它的哈希碼將用來計算桶值(索引值),只有當對應索引值上存在元素時,才會對實例進行比較。
因此equals,hashCode是定義在Object類中。
散列法的思想
如果hashCode作為快捷方式來確定相等,那麼只有一件事我們應該關心:相等的對象應該具有相同的哈希碼,這也是為什麼如果我們重寫了equals方法後,我們必須創建一個與之匹配的hashCode實現的原因!
否則相等的對象是可能不會有相同的哈希碼的,因為它們將調用的是Object's的默認實現。
HashCode 准則
引用自官方文檔
hashCode通用約定:
* 調用運行Java應用程序中的同一對象,hashCode方法必須始終返回相同的整數。這個整數不需要在不同的Java應用程序中保持一致。
* 根據equals(Object)的方法來比較,如果兩個對象是相等的,兩個對象調用hashCode方法必須產生相同的結果。
* 根據equals(Object)的方法是比較,如果兩個對象是不相等的,那麼兩個對象調用hashCode方法並不一定產生不同的整數的結果。但是,程序員應該意識到給不相等的對象產生不同的整數結果將有可能提高哈希表的性能。
第一點反映出了相等的一致性屬性,第二個就是我們上面提出的要求。第三個闡述了一個重要的細節,我們將在稍後討論。
HashCode實現
下面是非常簡單的Person.hashCode的實現
@Override
public int hashCode() {
return Objects.hash(firstName, lastName);
}

person』s是通過多個欄位結合來計算哈希碼的。都是通過Object的hash函數來計算。
選擇欄位
但哪些欄位是相關的嗎?需求將會幫助我們回答這個問題:如果相等的對象必須具有相同的哈希碼,那麼計算哈希碼就不應包括任何不用於相等檢查的欄位。(否則兩個對象只是這些欄位不同但是仍然有可能會相等,此時他們這兩個對象哈希碼卻會不相同。)
所以用於哈希組欄位應該相等時使用的欄位的子集。默認情況下都使用相同的欄位,但有一些細節需要考慮。
一致性
首先,有一致性的要求。它應該相當嚴格。雖然它允許如果一些欄位改變對應的哈希碼發生變化(對於可變的類是不可避免的),但是哈希數據結構並不是為這種場景准備的。
正如我們以上所見的哈希碼用於確定元素的桶。但如果hash-relevant欄位發生了改變,並不會重新計算哈希碼、也不會更新內部數組。
這意味著以後通過相等的對象,甚至同一實例進行查詢也會失敗,數據結構計算當前的哈希碼與之前存儲實例計算的哈希碼並不一致,並是錯誤的桶。
結論:最好不要使用可變欄位計算哈希碼!
性能
哈希碼最終計算的頻率與可能調用equals差不多,那麼這里將是影響性能的關鍵部分,因此考慮此部分性能也是非常有意義的。並且與equals相比,優化之後又更大的上升空間。
除非使用非常復雜的演算法或者涉及非常多的欄位,那麼計算哈希碼的運算成本是微不足道的、同樣也是不可避免的。但是也應該考慮是否需要包含所有的欄位來進行運算。集合需要特別警惕的對待。以Lists和sets為例,將會包含集合裡面的每一個元素來計算哈希碼。是否需要調用它們需要具體情況具體分析。
如果性能是至關重要的,使用Objects.hash因為需要為varargs創建一個數組也許並不是最好的選擇。但一般規則優化是適用的:不要過早地使用一個通用的散列碼演算法,也許需要放棄集合,只有優化分析顯示潛在的改進。
碰撞
總是關注性能,這個實現怎麼呢?
@Override
public int hashCode() {
return 0;
}

快是肯定的。相等的對象將具有相同的哈希碼。並且,沒有可變的欄位!
但是,我們之前說過的桶呢?!這種方式下所有的實例將會有相同的桶!這將會導致一個鏈表來包含所有的元素,這樣一來將會有非常差的性能。每次調用contains將會觸發對整個list線性掃描。
我們希望盡可能少的元素在同一個桶!一個演算法返回變化多端的哈希碼,即使對於非常相似的對象,是一個好的開始。
怎樣才能達到上面的效果部分取決於選取的欄位,我們在計算中包含更多的細節,越有可能獲取到不同的哈希碼。注意:這個與我們所說的性能是完全相反的。因此,有趣的是,使用過多或者過少的欄位都會導致糟糕的性能。
防止碰撞的另一部分是使用實際計算散列的演算法。
計算Hsah
最簡單的方法來計算一個欄位的哈希碼是通過直接調用hashCode,結合的話會自動完成。常見的演算法是首先在以任意數量的數值(通常是基本數據類型)反復進行相乘操作再與欄位哈希碼相加
int prime = 31;
int result = 1;
result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());
result = prime * result + ((lastName == null) ? 0 : lastName.hashCode());
return result;

這可能導致溢出,但是不是特別有問題的,因為他們並沒有產生Java異常。
注意,即使是非常良好的的哈希演算法也可能因為輸入特定的模式的數據有導致頻繁碰撞。作為一個簡單的例子假設我們會計算點的散列通過增加他們的x和y坐標。當我們處理f(x) = -x線上的點時,線上的點都滿足:x + y == 0,將會有大量的碰撞。
但是:我們可以使用一個通用的演算法,只到分析表明並不正確,才需要對哈希演算法進行修改。
總結
我們了解到計算哈希碼就是壓縮相等的一個整數值:相等的對象必須有相同的哈希碼,而出於對性能的考慮:最好是盡可能少的不相等的對象共享相同的哈希碼。
這就意味著如果重寫了equals方法,那麼就必須重寫hashCode方法
當實現hashCode
使用與equals中使用的相同的欄位(或者equals中使用欄位的子集)
最好不要包含可變的欄位。
對集合不要考慮調用hashCode
如果沒有特殊的輸入特定的模式,盡量採用通用的哈希演算法
記住hashCode性能,所以除非分析表明必要性,否則不要浪費太多的精力。

⑶ 一致性hash演算法是什麼

一致性哈希演算法是在1997年由麻省理工學院提出的一種分布式哈希(DHT)演算法。其設計目標是為了解決網際網路中的熱點(Hot spot)問題,初衷和CARP十分類似。

一致性Hash是一種特殊的Hash演算法,由於其均衡性、持久性的映射特點,被廣泛的應用於負載均衡領域,如nginx和memcached都採用了一致性Hash來作為集群負載均衡的方案。

一致性哈希演算法的目標是,當K個請求key發起請求時。後台增減節點,只會引起K/N的key發生重新映射。即一致性哈希演算法,在後台節點穩定時,同一key的每次請求映射到的節點是一樣的。而當後台節點增減時,該演算法盡量將K個key映射到與之前相同的節點上。

構成哈希演算法的條件:

從哈希值不能反向推導出原始數據(所以哈希演算法也叫單向哈希演算法)。

對輸入數據非常敏感,哪怕原始數據只修改了一個 Bit,最後得到的哈希值也大不相同。

散列沖突的概率要很小,對於不同的原始數據,哈希值相同的概率非常小。

哈希演算法的執行效率要盡量高效,針對較長的文本,也能快速地計算出哈希值。

⑷ 如何用java獲取redis的info

預備
jedis-2.5.2
commons-pool2-2.2.jar
使用單連接
此方式僅建議用於開發環境做調試用。
// 創建連接
String host = "192.168.56.102";
int port = 6379;
Jedis client = new Jedis(host, port);
// 執行set指令
String result = client.set("key-string", "Hello, Redis!");
System.out.println( String.format("set指令執行結果:%s", result) );
// 執行get指令
String value = client.get("key-string");
System.out.println( String.format("get指令執行結果:%s", value) );
運行上述代碼,控制台輸出:
set指令執行結果:OK
get指令執行結果:Hello, Redis!
使用連接池
此方式適用於僅使用單個Redis實例的場景。
// 生成連接池配置信息
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(10);
config.setMaxTotal(30);
config.setMaxWaitMillis(3*1000);

// 在應用初始化的時候生成連接池
JedisPool pool = new JedisPool(config, "192.168.56.102", 6379);

// 在業務操作時,從連接池獲取連接
Jedis client = pool.getResource();
try {
// 執行指令
String result = client.set("key-string", "Hello, Redis!");
System.out.println( String.format("set指令執行結果:%s", result) );
String value = client.get("key-string");
System.out.println( String.format("get指令執行結果:%s", value) );
} catch (Exception e) {
// TODO: handle exception
} finally {
// 業務操作完成,將連接返回給連接池
if (null != client) {
pool.returnResource(client);
}
} // end of try block

// 應用關閉時,釋放連接池資源
pool.destroy();

運行上述代碼,控制台輸出:

set指令執行結果:OK
get指令執行結果:Hello, Redis!
使用連接池+分布式
在規模較大的系統中,往往會有多個Redis實例做負載均衡。並且還實現主從備份,當主實例發生故障時,切換至從實例提供服務。
類似於Memcached的客戶端,Jedis也提供了客戶端分布式操作的方式,採用一致性哈希演算法。
// 生成多機連接信息列表
List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
shards.add( new JedisShardInfo("127.0.0.1", 6379) );
shards.add( new JedisShardInfo("192.168.56.102", 6379) );

// 生成連接池配置信息
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(10);
config.setMaxTotal(30);
config.setMaxWaitMillis(3*1000);

// 在應用初始化的時候生成連接池
ShardedJedisPool pool = new ShardedJedisPool(config, shards);

// 在業務操作時,從連接池獲取連接
ShardedJedis client = pool.getResource();
try {
// 執行指令
String result = client.set("key-string", "Hello, Redis!");
System.out.println( String.format("set指令執行結果:%s", result) );
String value = client.get("key-string");
System.out.println( String.format("get指令執行結果:%s", value) );
} catch (Exception e) {
// TODO: handle exception
} finally {
// 業務操作完成,將連接返回給連接池
if (null != client) {
pool.returnResource(client);
}
} // end of try block

// 應用關閉時,釋放連接池資源
pool.destroy();

運行上述代碼,控制台輸出:

set指令執行結果:OK
get指令執行結果:Hello, Redis!

⑸ (3)一致性哈希vs哈希取模演算法

大數字取模 分散不同桶,兩個桶, 2、3、4、5 ,模 2 分桶:

擴容 新桶 ,模 3 來結果:

每次擴展 和 收縮 所有條目分布 重新計算 ,某些場景不可接受。文件 分布 在哪台 哈希演算法 決定 ,這個系統想要 加 一台機器時就需要 停 下來等所有文件 重新分布一次 才能對外提供服務,一台機器掉線盡管 只掉一部分數據 ,所有數據訪問路由 都會出問題 。 無法平滑的擴縮容 。

無狀態化 ,用多瞎輪個桶,  模 7個 ,開始只有兩個 3 和 6。同樣取模,分到不存在的桶,往下找第一個真實存桶。 2 和 3 分3 桶, 4 和 5分 6 桶。

添加新  編號4桶, 還是模 7 :

3 號桶取模 小於等於 3 ,4 號桶只需從 6 號桶 拿走屬於它數字就可, 只調整一個桶重新分布 。即使有 1 億個桶,增加減少一個桶也只會影響一個桶的數據分布。

只需 和後面機器同步 數據 就可工作 ,同步到後一台機器再下線。 實現中 可以讓每台機器 同步一份自己前面機器的數據 ,即使 掉線也不影響 這部分數據服務。

問題:編號  6 的機桶下線 了, 沒有後一個桶了 ,哈希空間做成 環狀 , 數據給 3  :

一致性哈希還能 實現部分 的分布式系統 無鎖化 , 演算法的確定性 ,分到哪個桶也是確定的就 不存在爭搶 , 不需要分布式鎖 了。

查找效率:普通的哈希 查詢 一次 哈希計算就可以找到對應的桶了  O(1) ,一致性哈希需要將 排好序 的 桶組成 一個 鏈表 ,一路找下去k 個桶  O(k)

O(k) 對於哈希來說 不能忍 ,這個量級了用哈希沒意義,在排好序桶里查詢, 二分 把時間復雜度降到 O(logk) ,桶組合需不斷增減,鏈表實現二分肯定不行,用 跳轉錶快速跳轉 也能 實現 O(logk) 

跳轉表中, 每個桶記錄距離自己 1,2,4 距離的數字所存的桶,不管查詢落在哪個節點上,對整個哈希環上任意的查詢一次都 可以至少跳過一半的查詢空間? ,這樣遞歸下去很快就可以定位到數據是存在哪個桶上。

上面只是 一種 ,很多一致性哈希 變體 。如選桶:上面順著數字選 對面 出現 第一個桶 ,其實也可選距離 數字最近桶 ,這樣跳轉表規則也變。同樣跳轉表不同演算法實現:  CAN,Chord,Tapestry,Pastry 這四種 DHT  

1、如果 6號 (裡面有數據)桶突然 宕機 了,是不是裡面的數據也丟失了?來不及將桶里的數據往前一個桶移?

答:實際情況會做冗餘,畫的是一個桶, 實際可能是三個

2、 「一致性」 是擴縮容前後數據在桶里的 分布是一致 的

3、 分布式 系統中怎麼 實現服務間的事務 ,目前有哪些通用做法,比如bbo?

用zk或者etcd這種分布式 鎖 服務,讓介面是 冪等, 可以反復重試

4、增加此類操作會 拖慢集群的性能 。如果某節點上一刻 宕機 ,往後新尺唯數據會進入 下一個節點 ,宕機節點 恢復 ,下一個節點還要同步原屬宕機的數據,復雜度為O(nlogn),會不會代價略高?開源的ketama沒有同步數據這一做法,所以本質上只是近似一致性哈希,是不是一個trade-off的選擇?

答:這個場景不適合使用一致性哈希吧。以 負載均衡 為例,理論上是認為後台伺服器是 無狀態 的吧。所以宕機重啟 不應該有數據同步 的問題。

處理數據同步,raft強一致方案

對磨困信hash結果取余數 (hash() mod N):機器編號從 0到N-1 ,hash()值 按N取模 , 余數i,分發到編號i機器 。致命問題,宕機,落在該機器請求無法處理,有 (N-1)/N 伺服器的緩存數據重新計算;為何是 (N-1)/N 呢:3 台機器,hash值 1-6 分布:

host 1: 1 4

host 2: 2 5

host 3: 3 6

掛掉一台,只剩兩台, 模數取 2:

host 1: 1 3 5

host 2: 2 4 6

位置不變2個: 1,2,位置改變4個,占共6個數據的比率是 4/6 = 2/3。

N個真實 節點,每個映射成 M個虛擬節 點, M*N個虛擬節點散列在圓環上. 真虛相互交錯分布,真down後,平均分到所有節點

訪問方法:

寫入緩存請求,Key值為K,計算器hash值Hash(K), Hash(K) 對應於環中的某一個點,沒有映射到機器節點,順時針查找,直到找到有映射機器的節點,確定目標節點,超過2^32找不到,命中第一個。

缺陷:server數量很少時,環中分布不均勻,導致cache到server不均勻

例:用電話號碼group by,如移動用戶多,就會傾斜,reverse或加隨機數解決

hash取模對模數有要求,用奇數不用偶數,數據量大的時模數不好選,用上面辦法。

https://zhuanlan.hu.com/p/24440059

https://blog.csdn.net/hunandexingkong/article/details/70241933

⑹ 哈希表、哈希演算法、一致性哈希表

    散列表(Hash table,也叫哈希表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。它通過把關鍵碼映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做散列函數(哈希函數),存放記錄的數組叫做散列表。

  優點:

        哈希表可以提供快速的操作。

缺點:

        哈希表通常是基於數組的,數組創建後難於擴展。

        也沒有一種簡便的方法可以以任何一種順序〔例如從小到大)遍歷表中的數據項 。

    綜上, 如果不需要有序遍歷數據,井且可以提前預測數據量的大小。那麼哈希表在速度和易用性方面是無與倫比的。

        1. 使用哈希函數將被查找的鍵轉換為數組的索引。

        2. 處理哈希碰撞沖突。

    若關鍵字為 k ,則其值存放在 f(k) 的存儲位置上。由此,不需比較便可直接取得所查記錄。稱這個對應關系 f 為散列函數,按這個思想建立的表為散列表。

    若對於關鍵字集合中的任一個關鍵字,經散列函數映象到地址集合中任何一個地址的概率是相等的,則稱此類散列函數為 均勻散列函數 (Uniform Hash function),這就是使關鍵字經過散列函數得到一個"隨機的地址",從而減少碰撞。

散列函數能使對一個數據序列的訪問過程更加迅速有效,通過散列函數,數據元素將被更快地定位。

一個好的散列函數一般應該考慮下列因素 :

    1.計算簡單,以便提高轉換速度。

    2.關鍵詞對應的地址空間分布均勻,以盡量減少沖突。

1.   直接定址法

    取關鍵字或者關鍵字的某個線性函數值作為哈希地址,即H(Key)=Key或者H(Key)=a*Key+b(a,b為整數),這種散列函數也叫做自身函數.如果H(Key)的哈希地址上已經有值了,那麼就往下一個位置找,直到找到H(Key)的位置沒有值了就把元素放進去。

2.   數字分析法

    數字分析法就是找出數字的規律,盡可能利用這些數據來構造沖突幾率較低的散列地址。

3.   平方取中法

    取關鍵字平方後的中間幾位作為散列地址。這種方法的原理是通過取平方擴大差別,平方值的中間幾位和這個數的每一位都相關,則對不同的關鍵字得到的哈希函數值不易產生沖突,由此產生的哈希地址也較為均勻。該方法適用於關鍵字中的每一位都有某些數字重復出現頻度很高的現象。

4.   折疊法

    折疊法是將關鍵字分割成位數相同的幾部分,最後一部分位數可以不同,然後取這幾部分的疊加和(注意:疊加和時去除進位)作為散列地址。

    數位疊加可以有移位疊加和間界疊加兩種方法。移位疊加是將分割後的每一部分的最低位對齊,然後相加;間界疊加是從一端向另一端沿分割界來回折疊,然後對齊相加。

    該方法適用於關鍵字特別多的情況。

5.   隨機數法

    選擇一個隨機數,作為散列地址,通常用於關鍵字長度不同的場合。

6.   除留余數法

    取關鍵字被某個不大於散列表表長m的數p除後所得的余數為散列地址.即H(Key)=Key MOD p,p<=m.不僅可以對關鍵字直接取模,也可在折疊、平方取中等運算之後取模。對p的選擇很重要,一般取素數或m,若p選得不好,則很容易產生沖突。

    對不同的關鍵字可能得到同一散列地址,即 k1≠k2 ,而 f(k1)=f(k2) ,這種現象稱為碰撞(英語:Collision)。具有相同函數值的關鍵字對該散列函數來說稱做同義詞。

    通過構造性能良好的散列函數,可以減少沖突,但一般不可能完全避免沖突,因此解決沖突是哈希法的另一個關鍵問題。 創建哈希表和查找哈希表都會遇到沖突,兩種情況下解決沖突的方法應該一致。

下面以創建哈希表為例,說明解決沖突的方法。

1.開放定址法

    這種方法也稱再散列法,其基本思想是:當關鍵字key的哈希地址p=H(key)出現沖突時,以p為基礎,產生另一個哈希地址p1,如果p1仍然沖突,再以p為基礎,產生另一個哈希地址p2,…,直到找出一個不沖突的哈希地址pi ,將相應元素存入其中。這種方法有一個通用的再散列函數形式:Hi=(H(key)+di)%m   i=1,2,…,m-1,其中H(key)為哈希函數,m 為表長,di稱為增量序列,i為碰撞次數。增量序列的取值方式不同,相應的再散列方式也不同。增量序列主要有以下幾種:

    (1) 線性探測再散列

        di=1,2,3,…,m-1

        這種方法的特點是:沖突發生時,順序查看錶中下一單元,直到找出一個空單元或查遍全表。

    (2)二次探測再散列

        di=12,-12,22,-22,…,k2,-k2( k<=m/2 )

        這種方法的特點是:沖突發生時,在表的左右進行跳躍式探測,比較靈活。

    (3)偽隨機探測再散列

        di=偽隨機數序列。

    線性探測再散列的 優點 是:只要哈希表不滿,就一定能找到一個不沖突的哈希地址,而二次探測再散列和偽隨機探測再散列則不一定。線性探測再散列容易產生「二次聚集」,即在處理同義詞的沖突時又導致非同義詞的沖突。

    其實除了上面的幾種方法,開放定址法還有很多變種,不過都是對di有不同的表示方法。(如雙散列探測法:di=i*h2(k))

2.再哈希法

    這種方法是同時構造多個不同的哈希函數:Hi=RHi(key),i=1,2,3,…,n。

    當哈希地址H1=RH1(key)發生沖突時,再計算H2=RH2(key)……,直到沖突不再產生。這種方法不易產生聚集,但增加了計算時間。

 3.鏈地址法(拉鏈法)

    這種方法的基本思想是將所有哈希地址相同的元素構成一個稱為同義詞鏈的單鏈表,並將單鏈表的頭指針存在哈希表(數組)中,因而查找、插入和刪除主要在同義詞鏈中進行。若選定的散列表長度為m,則可將散列表定義為一個由m個頭指針組成的指針數組T[0..m-1]。凡是散列地址為i的結點,均插入到以T[i]為頭指針的單鏈表中。T中各分量的初值均應為空指針。鏈地址法適用於經常進行插入和刪除的情況。

     拉鏈法的優點

        與開放定址法相比,拉鏈法有如下幾個優點:

            (1)拉鏈法處理沖突簡單,且無堆積現象,即非同義詞決不會發生沖突,因此平均查找長度較短;

            (2)由於拉鏈法中各鏈表上的結點空間是動態申請的,故它更適合於造表前無法確定表長的情況;

            (3)開放定址法為減少沖突,要求裝填因子α較小,故當結點規模較大時會浪費很多空間。而拉鏈法中理論上可取α≥1,且結點較大時,拉鏈法中增加的指針域可忽略不計,因此節省空間;(散列表的裝填因子定義為:α= 填入表中的元素個數 / 散列表的長度)

註:HashMap默認裝填因子是0.75。

            (4)在用拉鏈法構造的散列表中,刪除結點的操作易於實現。只要簡單地刪去鏈表上相應的結點即可。而對開放定址法構造的散列表,刪除結點不能簡單地將被刪結點的空間置為空,否則將截斷在它之後填入散列表的同義詞結點的查找路徑。這是因為各種開放定址法中,空地址單元都被理解沒有查找到元素。 因此在用開放定址法處理沖突的散列表上執行刪除操作,只能在被刪結點上做刪除標記,而不能真正刪除結點。

     拉鏈法的缺點

        拉鏈法的缺點是:指針需要額外的空間,故當結點規模較小時,開放定址法較為節省空間,此時將節省的指針空間用來擴大散列表的規模,可使裝填因子變小,這又減少了開放定址法中的沖突,從而提高平均查找速度。

4、建立公共溢出區

    這種方法的基本思想是:將哈希表分為基本表和溢出表兩部分,凡是和基本表發生沖突的元素,一律填入溢出表(在這個方法裡面是把元素分開兩個表來存儲)。

    散列表的查找過程基本上和造表過程相同。一些關鍵碼可通過散列函數轉換的地址直接找到,另一些關鍵碼在散列函數得到的地址上產生了沖突,需要按處理沖突的方法進行查找。在介紹的三種處理沖突的方法中,產生沖突後的查找仍然是給定值與關鍵碼進行比較的過程。所以,對散列表查找效率的量度,依然用平均查找長度來衡量。

    查找過程中,關鍵碼的比較次數,取決於產生沖突的多少,產生的沖突少,查找效率就高,產生的沖突多,查找效率就低。因此,影響產生沖突多少的因素,也就是影響查找效率的因素。

影響產生沖突多少有以下三個因素:

    1. 散列函數是否均勻;

    2. 處理沖突的方法;

    3. 散列表的裝填因子。

     散列表的裝填因子

        定義為:α= 填入表中的元素個數 / 散列表的長度

        α是散列表裝滿程度的標志因子。由於表長是定值,α與"填入表中的元素個數"成正比,所以,α越大,填入表中的元素較多,產生沖突的可能性就越大;α越小,填入表中的元素較少,產生沖突的可能性就越小。

        實際上,散列表的平均查找長度是裝填因子α的函數,只是不同處理沖突的方法有不同的函數。

    這個HASH演算法不是大學里數據結構課里那個HASH表的演算法。這里的HASH演算法是密碼學的基礎,了解了hash基本定義,就不能不提到一些著名的hash演算法,MD5 和 SHA-1 可以說是目前應用最廣泛的Hash演算法,而它們都是以 MD4 為基礎設計的。

Hash演算法在信息安全方面的應用主要體現在以下的3個方面:

     ⑴  文件校驗

        我們比較熟悉的校驗演算法有奇偶校驗和CRC校驗,這2種校驗並沒有抗 數據篡改 的能力,它們一定程度上能檢測出數據傳輸中的信道誤碼,但卻不能防止對數據的惡意破壞。

        MD5 Hash演算法的"數字指紋"特性,使它成為目前應用最廣泛的一種文件完整性 校驗和 (Checksum)演算法,不少Unix系統有提供計算md5 checksum的命令

     ⑵  數字簽名

        Hash 演算法也是現代密碼體系中的一個重要組成部分。由於非對稱演算法的運算速度較慢,所以在 數字簽名 協議中,單向散列函數扮演了一個重要的角色。對 Hash 值,又稱"數字摘要"進行數字簽名,在統計上可以認為與對文件本身進行數字簽名是等效的。而且這樣的協議還有其他的優點。

     ⑶ 鑒權協議

        如下的鑒權協議又被稱作挑戰--認證模式:在傳輸信道是可被偵聽,但不可被篡改的情況下,這是一種簡單而安全的方法。

    一致性哈希表簡稱DHT,主要應用於分布式緩存中,可以用來解決分布式存儲結構下動態增加和刪除節點所帶來的問題。比如,一個分布式的存儲系統,要將數據存儲到具體的節點上,如果採用普通的hash方法,將數據映射到具體的節點上,如key%N(key是數據的key,N是機器節點數),如果有一個機器加入或退出這個集群,則所有的數據映射都無效了,如果是持久化存儲則要做數據遷移,如果是分布式緩存,則其他緩存就失效了。

判定哈希演算法好壞的四個定義 :

    1、平衡性(Balance):平衡性是指哈希的結果能夠盡可能分布到所有的緩沖中去,這樣可以使得所有的緩沖空間都得到利用。

    2、單調性(Monotonicity):單調性是指如果已經有一些內容通過哈希分派到了相應的緩沖中,又有新的緩沖加入到系統中。哈希的結果應能夠保證原有已分配的內容可以被映射到原有的或者新的緩沖中去,而不會被映射到舊的緩沖集合中的其他緩沖區。

    3、分散性(Spread):在分布式環境中,終端有可能看不到所有的緩沖,而是只能看到其中的一部分。當終端希望通過哈希過程將內容映射到緩沖上時,由於不同終端所見的緩沖范圍有可能不同,從而導致哈希的結果不一致,最終的結果是相同的內容被不同的終端映射到不同的緩沖區中。這種情況顯然是應該避免的,因為它導致相同內容被存儲到不同緩沖中去,降低了系統存儲的效率。 分散性的定義就是上述情況發生的嚴重程度。好的哈希演算法應能夠盡量避免不一致的情況發生,也就是盡量降低分散性。

    4、負載(Load):負載問題實際上是從另一個角度看待分散性問題。既然不同的終端可能將相同的內容映射到不同的緩沖區中,那麼對於一個特定的緩沖區而言,也可能被不同的用戶映射為不同的內容。與分散性一樣,這種情況也是應當避免的, 因此好的哈希演算法應能夠盡量降低緩沖的負荷。

    在分布式集群中,對機器的添加刪除,或者機器故障後自動脫離集群這些操作是分布式集群管理最基本的功能。如果採用常用的hash取模演算法,那麼在有機器添加或者刪除後,很多原有的數據就無法找到了,這樣嚴重的違反了單調性原則。接下來主要說明一下一致性哈希演算法是如何設計的。

以SpyMemcached的ketama演算法來說,思路是這樣的:

把數據用hash函數,映射到一個很大的空間里,如圖所示。數據的存儲時,先得到一個hash值,對應到這個環中的每個位置,如k1對應到了圖中所示的位置,然後沿順時針找到一個機器節點B,將k1存儲到B這個節點中。

如果B節點宕機了,則B上的數據就會落到C節點上,如下圖所示:

這樣,只會影響C節點,對其他的節點A,D的數據不會造成影響。然而,這又會造成一個「雪崩」的情況,即C節點由於承擔了B節點的數據,所以C節點的負載會變高,C節點很容易也宕機,這樣依次下去,這樣造成整個集群都掛了。

為此,引入了「虛擬節點」的概念:即把想像在這個環上有很多「虛擬節點」,數據的存儲是沿著環的順時針方向找一個虛擬節點,每個虛擬節點都會關聯到一個真實節點,如下圖所使用:

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

⑺ 一致性哈希演算法怎麼保證數據的一致性

環割法(一致性 hash)環割法的原理如下:

1. 初始化的時候生成分片數量 X × 環割數量 N 的固定方式編號的字元串,例如 SHARD-1-NODE-1,並計算所有 X×N 個字元串的所有 hash 值。

2. 將所有計算出來的 hash 值放到一個排序的 Map 中,並將其中的所有元素進行排序。

3. 輸入字元串的時候計算輸入字元串的 hash 值,查看 hash 值介於哪兩個元素之間,取小於 hash 值的那個元素對應的分片為數據的分片。

數據比較

下面將通過測試對環割法和跳躍法的性能及均衡性進行對比,說明 DBLE 為何使用跳躍法代替了環割法。

⑻ 一致性哈希 java實現 怎麼映射到圓環上

一致性哈希提出了在動態變化的Cache環境中,哈希演算法應該滿足的4個適應條件:單調性是指如果已經有一些內容通過哈希分派到了相應的緩沖中,又有新的緩沖區加入到系統中,那麼哈希的結果應能夠保證原有已分配的內容可以被映射到新的緩沖區中去,而不會被映射到舊的緩沖集合中的其他緩沖區。(這段翻譯信息有負面價值的,當緩沖區大小變化時一致性哈希(Consistenthashing)盡量保護已分配的內容不會被重新映射到新緩沖區。)簡單的哈希演算法往往不能滿足單調性的要求,如最簡單的線性哈希:x→ax+bmod(P)在上式中,P表示全部緩沖的大小。不難看出,當緩沖大小發生變化時(從P1到P2),原來所有的哈希結果均會發生變化,從而不滿足單調性的要求。哈希結果的變化意味著當緩沖空間發生變化時,所有的映射關系需要在系統內全部更新。而在P2P系統內,緩沖的變化等價於Peer加入或退出系統,這一情況在P2P系統中會頻繁發生,因此會帶來極大計算和傳輸負荷。單調性就是要求哈希演算法能夠應對這種情況。負載問題實際上是從另一個角度看待分散性問題。既然不同的終端可能將相同的內容映射到不同的緩沖區中,那麼對於一個特定的緩沖區而言,也可能被不同的用戶映射為不同的內容。與分散性一樣,這種情況也是應當避免的,因此好的哈希演算法應能夠盡量降低緩沖的負荷。從表面上看,一致性哈希針對的是分布式緩沖的問題,但是如果將緩沖看作P2P系統中的Peer,將映射的內容看作各種共享的資源(數據,文件,媒體流等),就會發現兩者實際上是在描述同一問題。路由演算法在一致性哈希演算法中,每個節點(對應P2P系統中的Peer)都有隨機分配的ID。在將內容映射到節點時,使用內容的關鍵字和節點的ID進行一致性哈希運算並獲得鍵值。一致性哈希要求鍵值和節點ID處於同一值域。最簡單的鍵值和ID可以是一維的,比如從0000到9999的整數集合。根據鍵值存儲內容時,內容將被存儲到具有與其鍵值最接近的ID的節點上。例如鍵值為1001的內容,系統中有ID為1000,1010,1100的節點,該內容將被映射到1000節點。為了構建查詢所需的路由,一致性哈希要求每個節點存儲其上行節點(ID值大於自身的節點中最小的)和下行節點(ID值小於自身的節點中最大的)的位置信息(IP地址)。當節點需要查找內容時,就可以根據內容的鍵值決定向上行或下行節點發起查詢請求。收到查詢請求的節點如果發現自己擁有被請求的目標,可以直接向發起查詢請求的節點返回確認;如果發現不屬於自身的范圍,可以轉發請求到自己的上行/下行節點。為了維護上述路由信息,在節點加入/退出系統時,相鄰的節點必須及時更新路由信息。這就要求節點不僅存儲直接相連的下行節點位置信息,還要知道一定深度(n跳)的間接下行節點信息,並且動態地維護節點列表。當節點退出系統時,它的上行節點將嘗試直接連接到最近的下行節點,連接成功後,從新的下行節點獲得下行節點列表並更新自身的節點列表。同樣的,當新的節點加入到系統中時,首先根據自身的ID找到下行節點並獲得下行節點列表,然後要求上行節點修改其下行節點列表,這樣就恢復了路由關系。

閱讀全文

與一致性哈希演算法java相關的資料

熱點內容
dvd光碟存儲漢子演算法 瀏覽:758
蘋果郵件無法連接伺服器地址 瀏覽:963
phpffmpeg轉碼 瀏覽:672
長沙好玩的解壓項目 瀏覽:145
專屬學情分析報告是什麼app 瀏覽:564
php工程部署 瀏覽:833
android全屏透明 瀏覽:737
阿里雲伺服器已開通怎麼辦 瀏覽:803
光遇為什麼登錄時伺服器已滿 瀏覽:302
PDF分析 瀏覽:486
h3c光纖全工半全工設置命令 瀏覽:143
公司法pdf下載 瀏覽:383
linuxmarkdown 瀏覽:350
華為手機怎麼多選文件夾 瀏覽:683
如何取消命令方塊指令 瀏覽:350
風翼app為什麼進不去了 瀏覽:779
im4java壓縮圖片 瀏覽:362
數據查詢網站源碼 瀏覽:151
伊克塞爾文檔怎麼進行加密 瀏覽:893
app轉賬是什麼 瀏覽:163