<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 110, comments - 101, trackbacks - 0, articles - 7
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    一致性哈希算法與Java實現

    Posted on 2012-10-10 11:32 云云 閱讀(48855) 評論(5)  編輯  收藏
      一致性哈希算法是分布式系統中常用的算法。比如,一個分布式的存儲系統,要將數據存儲到具體的節點上,如果采用普通的hash方法,將數據映射到具體的節點上,如key%N,key是數據的key,N是機器節點數,如果有一個機器加入或退出這個集群,則所有的數據映射都無效了,如果是持久化存儲則要做數據遷移,如果是分布式緩存,則其他緩存就失效了。

        因此,引入了一致性哈希算法:


     

    把數據用hash函數(如MD5),映射到一個很大的空間里,如圖所示。數據的存儲時,先得到一個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的數據。由于這些虛擬節點數量很多,均勻分布,因此不會造成“雪崩”現象。

     

    Java實現:

    1. public class Shard<S> { // S類封裝了機器節點的信息 ,如name、password、ip、port等   
    2.   
    3.     private TreeMap<Long, S> nodes; // 虛擬節點   
    4.     private List<S> shards; // 真實機器節點   
    5.     private final int NODE_NUM = 100// 每個機器節點關聯的虛擬節點個數   
    6.   
    7.     public Shard(List<S> shards) {  
    8.         super();  
    9.         this.shards = shards;  
    10.         init();  
    11.     }  
    12.   
    13.     private void init() { // 初始化一致性hash環   
    14.         nodes = new TreeMap<Long, S>();  
    15.         for (int i = 0; i != shards.size(); ++i) { // 每個真實機器節點都需要關聯虛擬節點   
    16.             final S shardInfo = shards.get(i);  
    17.   
    18.             for (int n = 0; n < NODE_NUM; n++)  
    19.                 // 一個真實機器節點關聯NODE_NUM個虛擬節點   
    20.                 nodes.put(hash("SHARD-" + i + "-NODE-" + n), shardInfo);  
    21.   
    22.         }  
    23.     }  
    24.   
    25.     public S getShardInfo(String key) {  
    26.         SortedMap<Long, S> tail = nodes.tailMap(hash(key)); // 沿環的順時針找到一個虛擬節點   
    27.         if (tail.size() == 0) {  
    28.             return nodes.get(nodes.firstKey());  
    29.         }  
    30.         return tail.get(tail.firstKey()); // 返回該虛擬節點對應的真實機器節點的信息   
    31.     }  
    32.   
    33.     /** 
    34.      *  MurMurHash算法,是非加密HASH算法,性能很高, 
    35.      *  比傳統的CRC32,MD5,SHA-1(這兩個算法都是加密HASH算法,復雜度本身就很高,帶來的性能上的損害也不可避免) 
    36.      *  等HASH算法要快很多,而且據說這個算法的碰撞率很低. 
    37.      *  http://murmurhash.googlepages.com/ 
    38.      */  
    39.     private Long hash(String key) {  
    40.           
    41.         ByteBuffer buf = ByteBuffer.wrap(key.getBytes());  
    42.         int seed = 0x1234ABCD;  
    43.           
    44.         ByteOrder byteOrder = buf.order();  
    45.         buf.order(ByteOrder.LITTLE_ENDIAN);  
    46.   
    47.         long m = 0xc6a4a7935bd1e995L;  
    48.         int r = 47;  
    49.   
    50.         long h = seed ^ (buf.remaining() * m);  
    51.   
    52.         long k;  
    53.         while (buf.remaining() >= 8) {  
    54.             k = buf.getLong();  
    55.   
    56.             k *= m;  
    57.             k ^= k >>> r;  
    58.             k *= m;  
    59.   
    60.             h ^= k;  
    61.             h *= m;  
    62.         }  
    63.   
    64.         if (buf.remaining() > 0) {  
    65.             ByteBuffer finish = ByteBuffer.allocate(8).order(  
    66.                     ByteOrder.LITTLE_ENDIAN);  
    67.             // for big-endian version, do this first:   
    68.             // finish.position(8-buf.remaining());   
    69.             finish.put(buf).rewind();  
    70.             h ^= finish.getLong();  
    71.             h *= m;  
    72.         }  
    73.   
    74.         h ^= h >>> r;  
    75.         h *= m;  
    76.         h ^= h >>> r;  
    77.   
    78.         buf.order(byteOrder);  
    79.         return h;  
    80.     }  
    81.   
    82. }  

    評論

    # re: 一致性哈希算法與Java實現   回復  更多評論   

    2014-05-22 12:25 by xdemo
    絕不可能~

    # re: 一致性哈希算法與Java實現   回復  更多評論   

    2014-08-12 17:37 by nodexy
    1樓高見?

    # re: 一致性哈希算法與Java實現   回復  更多評論   

    2015-01-15 20:37 by 沙漠綠樹
    我的qq是29561416

    我看了網上清一色都是拿memcached來說一致性hash,增加虛擬節點解決數據均衡的問題。我有個疑問:
    1.使用虛擬節點后,但是當我增加物理節點后,環中的虛擬節點是否要增加,如果把他應用在mysql上,數據遷移是否會很困難?

    2.在使用虛擬節點時,比如5個物理節點,每個物理節點虛擬出1024個虛節點,按道理hash環有5120個節點,但是使用kemata哈希虛擬環時,有些節點key的哈希結果相同,導致hash環中少于5120個節點?

    # re: 一致性哈希算法與Java實現   回復  更多評論   

    2015-10-21 00:22 by 一個不起眼的攻城獅
    我來解決樓上的問題,解決之前賢說兩句:
    樓上太強勢,絕對不可能,這5個字震懾到我了,而且看你的提問,只能算是懂一點hash一致性算法,樓主的說法是正確的,也是非常有參考價值的。
    問題答案如下:
    1. 你所說的是hash一致性的數據遷移問題,這個是hash一致性的弱點,可以改進,但是需要自己開發相應的程序,不是不可能完成的而是可以完成的,只是復雜點;退一萬步,任何技術都不是萬能的,都有弊端,只是看你的業務需求最適于那種技術。
    2. 你這個可以將hash的空間編程2的32次方,2的64次方都可以,不是只能用一種,要活學活用。另外,hash出來的key值相同少有發生,這是hash的特性決定的,也就是hash沖突,這個倒是個問題,解決方法是bloomfilter算法,有興趣的可以自己去查。

    # re: 一致性哈希算法與Java實現   回復  更多評論   

    2016-07-25 12:04 by 三單聯咖啡色
    有一個問題,如果使用虛擬節點,某臺機器每次宕機再恢復后都需要遷移數據。這樣是否反而更麻煩了。

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 毛片a级毛片免费观看免下载| 亚洲AV无码国产精品色午友在线| 日韩在线永久免费播放| 国产精品亚洲色图| 亚洲欧洲日产国码二区首页| 亚洲日韩精品无码一区二区三区| 亚洲国产日韩精品| 久久青青草原亚洲AV无码麻豆| 免费大黄网站在线观看| 最近2019中文字幕免费看最新 | 18勿入网站免费永久| 两个人的视频www免费| 亚洲日本va午夜中文字幕一区| 亚洲高清成人一区二区三区| 日韩免费无砖专区2020狼| 性xxxxx免费视频播放| 美女羞羞喷液视频免费| 亚洲AV天天做在线观看| 久久久青草青青国产亚洲免观| 免费国产综合视频在线看| 午夜免费福利在线| 最近中文字幕无吗高清免费视频| 51精品视频免费国产专区| 久久99精品免费视频| 男女猛烈xx00免费视频试看| 亚洲精品中文字幕无码A片老| 亚洲午夜无码久久久久小说| 亚洲精品第一国产综合野| 亚洲乱码中文论理电影| 亚洲国产人成在线观看| 亚洲成aⅴ人片在线观| 亚洲婷婷在线视频| 亚洲av午夜精品无码专区| 国产亚洲精品xxx| 国产亚洲精久久久久久无码| 亚洲爆乳无码专区| 亚洲AV中文无码乱人伦| 亚洲国产精品无码久久九九| gogo全球高清大胆亚洲| 亚洲色图综合在线| 国产亚洲精品国产|