生活随笔
收集整理的這篇文章主要介紹了
一致性哈希算法与Java实现
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
來(lái)源:http://blog.csdn.net/wuhuan_wp/article/details/7010071
?一致性哈希算法是分布式系統(tǒng)中常用的算法。比如,一個(gè)分布式的存儲(chǔ)系統(tǒng),要將數(shù)據(jù)存儲(chǔ)到具體的節(jié)點(diǎn)上,如果采用普通的hash方法,將數(shù)據(jù)映射到具體的節(jié)點(diǎn)上,如key%N,key是數(shù)據(jù)的key,N是機(jī)器節(jié)點(diǎn)數(shù),如果有一個(gè)機(jī)器加入或退出這個(gè)集群,則所有的數(shù)據(jù)映射都無(wú)效了,如果是持久化存儲(chǔ)則要做數(shù)據(jù)遷移,如果是分布式緩存,則其他緩存就失效了。
? ? 因此,引入了一致性哈希算法:
把數(shù)據(jù)用hash函數(shù)(如MD5),映射到一個(gè)很大的空間里,如圖所示。數(shù)據(jù)的存儲(chǔ)時(shí),先得到一個(gè)hash值,對(duì)應(yīng)到這個(gè)環(huán)中的每個(gè)位置,如k1對(duì)應(yīng)到了圖中所示的位置,然后沿順時(shí)針找到一個(gè)機(jī)器節(jié)點(diǎn)B,將k1存儲(chǔ)到B這個(gè)節(jié)點(diǎn)中。
如果B節(jié)點(diǎn)宕機(jī)了,則B上的數(shù)據(jù)就會(huì)落到C節(jié)點(diǎn)上,如下圖所示:
這樣,只會(huì)影響C節(jié)點(diǎn),對(duì)其他的節(jié)點(diǎn)A,D的數(shù)據(jù)不會(huì)造成影響。然而,這又會(huì)造成一個(gè)“雪崩”的情況,即C節(jié)點(diǎn)由于承擔(dān)了B節(jié)點(diǎn)的數(shù)據(jù),所以C節(jié)點(diǎn)的負(fù)載會(huì)變高,C節(jié)點(diǎn)很容易也宕機(jī),這樣依次下去,這樣造成整個(gè)集群都掛了。
?????? 為此,引入了“虛擬節(jié)點(diǎn)”的概念:即把想象在這個(gè)環(huán)上有很多“虛擬節(jié)點(diǎn)”,數(shù)據(jù)的存儲(chǔ)是沿著環(huán)的順時(shí)針?lè)较蛘乙粋€(gè)虛擬節(jié)點(diǎn),每個(gè)虛擬節(jié)點(diǎn)都會(huì)關(guān)聯(lián)到一個(gè)真實(shí)節(jié)點(diǎn),如下圖所使用:
圖中的A1、A2、B1、B2、C1、C2、D1、D2都是虛擬節(jié)點(diǎn),機(jī)器A負(fù)載存儲(chǔ)A1、A2的數(shù)據(jù),機(jī)器B負(fù)載存儲(chǔ)B1、B2的數(shù)據(jù),機(jī)器C負(fù)載存儲(chǔ)C1、C2的數(shù)據(jù)。由于這些虛擬節(jié)點(diǎn)數(shù)量很多,均勻分布,因此不會(huì)造成“雪崩”現(xiàn)象。
Java實(shí)現(xiàn):
[java]?view plaincopy
public?class?Shard<S>?{??? ?? ????private?TreeMap<Long,?S>?nodes;??? ????private?List<S>?shards;??? ????private?final?int?NODE_NUM?=?100;??? ?? ????public?Shard(List<S>?shards)?{?? ????????super();?? ????????this.shards?=?shards;?? ????????init();?? ????}?? ?? ????private?void?init()?{??? ????????nodes?=?new?TreeMap<Long,?S>();?? ????????for?(int?i?=?0;?i?!=?shards.size();?++i)?{??? ????????????final?S?shardInfo?=?shards.get(i);?? ?? ????????????for?(int?n?=?0;?n?<?NODE_NUM;?n++)?? ?????????????????? ????????????????nodes.put(hash("SHARD-"?+?i?+?"-NODE-"?+?n),?shardInfo);?? ?? ????????}?? ????}?? ?? ????public?S?getShardInfo(String?key)?{?? ????????SortedMap<Long,?S>?tail?=?nodes.tailMap(hash(key));??? ????????if?(tail.size()?==?0)?{?? ????????????return?nodes.get(nodes.firstKey());?? ????????}?? ????????return?tail.get(tail.firstKey());??? ????}?? ?? ????? ? ? ? ? ?? ????private?Long?hash(String?key)?{?? ?????????? ????????ByteBuffer?buf?=?ByteBuffer.wrap(key.getBytes());?? ????????int?seed?=?0x1234ABCD;?? ?????????? ????????ByteOrder?byteOrder?=?buf.order();?? ????????buf.order(ByteOrder.LITTLE_ENDIAN);?? ?? ????????long?m?=?0xc6a4a7935bd1e995L;?? ????????int?r?=?47;?? ?? ????????long?h?=?seed?^?(buf.remaining()?*?m);?? ?? ????????long?k;?? ????????while?(buf.remaining()?>=?8)?{?? ????????????k?=?buf.getLong();?? ?? ????????????k?*=?m;?? ????????????k?^=?k?>>>?r;?? ????????????k?*=?m;?? ?? ????????????h?^=?k;?? ????????????h?*=?m;?? ????????}?? ?? ????????if?(buf.remaining()?>?0)?{?? ????????????ByteBuffer?finish?=?ByteBuffer.allocate(8).order(?? ????????????????????ByteOrder.LITTLE_ENDIAN);?? ?????????????? ?????????????? ????????????finish.put(buf).rewind();?? ????????????h?^=?finish.getLong();?? ????????????h?*=?m;?? ????????}?? ?? ????????h?^=?h?>>>?r;?? ????????h?*=?m;?? ????????h?^=?h?>>>?r;?? ?? ????????buf.order(byteOrder);?? ????????return?h;?? ????}?? ?? }??
總結(jié)
以上是生活随笔為你收集整理的一致性哈希算法与Java实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。