redis 一致性hash ,分散式儲存
轉自:http://my.oschina.net/zhenglingfei/blog/405622
今天請教jedis跟shareJedis有啥區別,某神答曰:shareJedis是切片的,將例項作為一致性Hash,分散式儲存,感覺好高大上就在網上找了下,趕腳下面說的很不錯哦,就偷過來了
hash是什麼
hash即hash演算法,又稱為雜湊演算法,百度百科的定義是
雜湊演算法將任意長度的二進位制值對映為較短的固定長度的二進位制值,這個小的二進位制值稱為雜湊值。雜湊值是一段資料唯一且極其緊湊的數值表示形式。
1.這句話有幾個很重要的地方,首先是任意長度二進位制,在java中,可以代表所有物件(序列化)
2.固定長度,使得hashmap等可以按照高低位進行位操作,同時能夠提供統一的方式(有種協議的感覺)
3.資料唯一的數值,使得hashcode可以作為查詢的依據(快速查詢的根本)
為什麼hash
說為什麼首先要說說如果沒有會怎麼樣。
csdn有這樣一篇文章講的很有意思,我們有一堆豬,怎麼根據體重找到對應的一頭。如果沒有hash的思想,我們會比較每頭豬,但是如果有1000頭你也這樣做麼。引入hash,每頭豬的重量hash到一個hashcode,hashcode會對映到對應的豬圈,我們只要比較每個豬圈的豬就行了,而最理想的情況就是每個豬圈的豬都一樣多(注:每個豬圈一個是好,但是空間消耗巨大)
而java中,hash也是採用這樣的方式,通過hashcode與桶數取模的方式(當然時間是通過位操作,效能更高)自然對映到具體的桶中。
關於分散式儲存
當hash遇上分散式,單臺機子的hashmap儲存已經不能滿足我們的key-value需求,怎麼辦,我們需要把儲存內容分佈到不同的實體機上,這時需要一種把key對映到不同機器的方法,我們想起了hash,可以把實體機當做是桶,採用和hashmap實現一樣的思路,通過和實體機的數量取模,自然對映到不同的機器。
ok,搞定,分散式確實可以實現。但現在問題來了,如果其中一臺機子掛了,或者又加了一臺機子怎麼辦,這時出現兩種情況:
1.不做任何改變,那麼掛了的資料將無法得到恢復,新增的機子也無法得到利用
2.rehash 這種情況,桶的數量將會改變,所有的值將重新對映,最終資料會得到儲存,這有兩個問題,rehash的時刻,所有key將重新對映,這時,對於大併發的情形,是災難的,所有請求將不經過任何快取,伺服器面臨崩潰的風險,再者,老的資料依然還在,並且不會被用到,浪費儲存空間。
那麼,怎麼辦
引入一致性hash
consistent hashing是這樣一種hash演算法,簡單的說,在移除/新增一個 節點(機器,ip)時,它能夠儘可能小的改變已存在key對映關係,儘可能的滿足單調性()的要求。
hash迴環
任何的hash值都是固定長度的,因此可以通過一個迴環來承載所有的hash值(為什麼用環後面會說)
對映
hash最總要的一步就是把物件對映到對應的桶,而與通常的hash做法相比,一致性hash會比較特殊,一致性hash不會將key直接對映到桶,而將key和桶分別對映到迴環的對應hash值節點
對映key
對映桶
接下來是最重要的一步,把key對映到對應的桶
尋桶
現在 cache 和物件都已經通過同一個 hash 演算法對映到 hash 數值空間中了,接下來要考慮的就是如何將物件對映到 cache 上面了。
在這個環形空間中,如果沿著順時針方向從物件的 key 值出發,直到遇見一個 cache ,那麼就將該物件儲存在這個 cache 上,因為物件和 cache 的 hash 值是固定的,因此這個 cache 必然是唯一和確定的。這樣不就找到了物件和 cache 的對映方法了嗎?!
依然繼續上面的例子(參見圖 3 ),那麼根據上面的方法,物件 object1 將被儲存到 cache A 上; object2和 object3 對應到 cache C ; object4 對應到 cache B ;
好處
我們講了這麼多一致性hash的演算法,那麼他究竟帶來了什麼,我們分新增和刪除的情況考慮
新增
我們新增一個新的節點D,按照順時針的方式,原先對映到C的object2會對映到D,而object3則還是對映到C,這樣新增只會影響到object2,事實上是B和D之間的物件,這種影響相比傳統的方式,影響是很小的
刪除
與新增類似,刪除也只會影響A和B之間的物件
虛擬節點(一下完全引自:http://my.oschina.net/jsan/blog/49702)
考量 Hash 演算法的另一個指標是平衡性 (Balance) ,定義如下:
平衡性
平衡性是指雜湊的結果能夠儘可能分佈到所有的緩衝中去,這樣可以使得所有的緩衝空間都得到利用。
hash 演算法並不是保證絕對的平衡,如果 cache 較少的話,物件並不能被均勻的對映到 cache 上,比如在上面的例子中,僅部署 cache A 和 cache C 的情況下,在 4 個物件中, cache A 僅儲存了 object1 ,而 cache C 則儲存了 object2 、 object3 和 object4 ;分佈是很不均衡的。
為了解決這種情況, consistent hashing 引入了“虛擬節點”的概念,它可以如下定義:
“虛擬節點”( virtual node )是實際節點在 hash 空間的複製品( replica ),一實際個節點對應了若干個“虛擬節點”,這個對應個數也成為“複製個數”,“虛擬節點”在 hash 空間中以 hash 值排列。
仍以僅部署 cache A 和 cache C 的情況為例,在圖 4 中我們已經看到, cache 分佈並不均勻。現在我們引入虛擬節點,並設定“複製個數”為 2 ,這就意味著一共會存在 4 個“虛擬節點”, cache A1, cache A2 代表了 cache A ; cache C1, cache C2 代表了 cache C ;假設一種比較理想的情況,參見圖 6 。
圖 6 引入“虛擬節點”後的對映關係
此時,物件到“虛擬節點”的對映關係為:
objec1->cache A2 ; objec2->cache A1 ; objec3->cache C1 ; objec4->cache C2 ;
因此物件 object1 和 object2 都被對映到了 cache A 上,而 object3 和 object4 對映到了 cache C 上;平衡性有了很大提高。
引入“虛擬節點”後,對映關係就從 { 物件 -> 節點 } 轉換到了 { 物件 -> 虛擬節點 } 。查詢物體所在 cache時的對映關係如圖 7 所示。
圖 7 查詢物件所在 cache
“虛擬節點”的 hash 計算可以採用對應節點的 IP 地址加數字字尾的方式。例如假設 cache A 的 IP 地址為202.168.14.241 。
引入“虛擬節點”前,計算 cache A 的 hash 值:
Hash(“202.168.14.241”);
引入“虛擬節點”後,計算“虛擬節”點 cache A1 和 cache A2 的 hash 值:
Hash(“202.168.14.241#1”); // cache A1
Hash(“202.168.14.241#2”); // cache A2
參考
http://my.oschina.net/u/1166485/blog/136663