【策略】一致性Hash演算法(Hash環)的java程式碼實現
Love Lenka發表於2017-05-16
【一】一致性hash演算法,基本實現分佈平衡。
1 package org.ehking.quartz.curator; 2 3 import java.util.SortedMap; 4 import java.util.TreeMap; 5 6 public class ConsistentHashingWithoutVirtualNode { 7 /** 8 * 待新增入Hash環的伺服器列表 9 */ 10 private static String[] servers = {"192.168.0.0:111", "192.168.0.1:111", "192.168.0.2:111", 11 "192.168.0.3:111", "192.168.0.4:111"}; 12 13 /** 14 * key表示伺服器的hash值,value表示伺服器的名稱 15 */ 16 private static SortedMap<Integer, String> sortedMap = 17 new TreeMap<Integer, String>(); 18 19 /** 20 * 程式初始化,將所有的伺服器放入sortedMap中 21 */ 22 static 23 { 24 for (int i = 0; i < servers.length; i++) 25 { 26 int hash = getHash(servers[i]); 27 System.out.println("[" + servers[i] + "]加入集合中, 其Hash值為" + hash); 28 sortedMap.put(hash, servers[i]); 29 } 30 System.out.println(); 31 } 32 33 /** 34 * 使用FNV1_32_HASH演算法計算伺服器的Hash值,這裡不使用重寫hashCode的方法,最終效果沒區別 35 */ 36 private static int getHash(String str) 37 { 38 final int p = 16777619; 39 int hash = (int)2166136261L; 40 for (int i = 0; i < str.length(); i++) 41 hash = (hash ^ str.charAt(i)) * p; 42 hash += hash << 13; 43 hash ^= hash >> 7; 44 hash += hash << 3; 45 hash ^= hash >> 17; 46 hash += hash << 5; 47 48 // 如果算出來的值為負數則取其絕對值 49 if (hash < 0) 50 hash = Math.abs(hash); 51 return hash; 52 } 53 54 /** 55 * 得到應當路由到的結點 56 */ 57 private static String getServer(String node) 58 { 59 // 得到帶路由的結點的Hash值 60 int hash = getHash(node); 61 // 得到大於該Hash值的所有Map 62 SortedMap<Integer, String> subMap = 63 sortedMap.tailMap(hash); 64 // 第一個Key就是順時針過去離node最近的那個結點 65 Integer i = subMap.firstKey(); 66 // 返回對應的伺服器名稱 67 return subMap.get(i); 68 } 69 70 public static void main(String[] args) 71 { 72 String[] nodes = {"127.0.0.1:1111", "221.226.0.1:2222", "10.211.0.1:3333"}; 73 for (int i = 0; i < nodes.length; i++) 74 System.out.println("[" + nodes[i] + "]的hash值為" + 75 getHash(nodes[i]) + ", 被路由到結點[" + getServer(nodes[i]) + "]"); 76 } 77 }
【二】藉助虛擬節點,實現分佈平衡的hash演算法
1 package org.ehking.quartz.curator; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.LinkedList; 6 import java.util.List; 7 import java.util.Set; 8 import java.util.SortedMap; 9 import java.util.TreeMap; 10 import java.util.UUID; 11 12 public class ConsistentHashingWithVirtualNode { 13 /** 14 * 待新增入Hash環的伺服器列表 15 */ 16 private static String[] servers = { "192.168.0.0:111","192.168.0.1:111", "192.168.0.2:111"}; 17 18 /** 19 * 真實結點列表,考慮到伺服器上線、下線的場景,即新增、刪除的場景會比較頻繁,這裡使用LinkedList會更好 20 */ 21 private static List<String> realNodes = new LinkedList<String>(); 22 /** 23 * 虛擬節點,key表示虛擬節點的hash值,value表示虛擬節點的名稱 24 */ 25 private static SortedMap<Integer, String> virtualNodes = 26 new TreeMap<Integer, String>(); 27 28 /** 29 * 虛擬節點的數目,這裡寫死,為了演示需要,一個真實結點對應5個虛擬節點 30 */ 31 private static final int VIRTUAL_NODES = 1000; 32 33 static 34 { 35 // 先把原始的伺服器新增到真實結點列表中 36 for (int i = 0; i < servers.length; i++) 37 realNodes.add(servers[i]); 38 39 // 再新增虛擬節點,遍歷LinkedList使用foreach迴圈效率會比較高 40 for (String str : realNodes) 41 { 42 for (int i = 0; i < VIRTUAL_NODES; i++) 43 { 44 String virtualNodeName = str + "&&VN" + String.valueOf(i); 45 int hash = getHash(virtualNodeName); 46 System.out.println("虛擬節點[" + virtualNodeName + "]被新增, hash值為" + hash); 47 virtualNodes.put(hash, virtualNodeName); 48 } 49 } 50 System.out.println(); 51 } 52 53 /** 54 * 使用FNV1_32_HASH演算法計算伺服器的Hash值,這裡不使用重寫hashCode的方法,最終效果沒區別 55 */ 56 private static int getHash(String str) 57 { 58 final int p = 16777619; 59 int hash = (int)2166136261L; 60 for (int i = 0; i < str.length(); i++) 61 hash = (hash ^ str.charAt(i)) * p; 62 hash += hash << 13; 63 hash ^= hash >> 7; 64 hash += hash << 3; 65 hash ^= hash >> 17; 66 hash += hash << 5; 67 68 // 如果算出來的值為負數則取其絕對值 69 if (hash < 0) 70 hash = Math.abs(hash); 71 return hash; 72 } 73 74 /** 75 * 得到應當路由到的結點 76 */ 77 private static String getServer(String node) 78 { 79 // 得到帶路由的結點的Hash值 80 int hash = getHash(node); 81 // 得到大於該Hash值的所有Map 82 SortedMap<Integer, String> subMap = 83 virtualNodes.tailMap(hash); 84 Integer i=null; 85 String virtualNode = null; 86 if(subMap==null||subMap.size()==0){ 87 i=virtualNodes.firstKey(); 88 virtualNode=virtualNodes.get(i); 89 }else{ 90 i = subMap.firstKey(); 91 virtualNode= subMap.get(i); 92 } 93 // 第一個Key就是順時針過去離node最近的那個結點 94 95 // 返回對應的虛擬節點名稱,這裡字串稍微擷取一下 96 return virtualNode.substring(0, virtualNode.indexOf("&&")); 97 } 98 99 public static void main(String[] args) 100 { 101 102 HashMap<String,Integer> map=new HashMap<String, Integer>(); 103 List<String> id=new ArrayList<String>(); 104 for(int i=0;i<1000;i++){ 105 id.add(UUID.randomUUID().toString().replace("-", "")); 106 //id.add("adasfdsafdsgfdsagdsafdsafdsaf"+i); 107 } 108 for (int i = 0; i < id.size(); i++){ 109 String aString=getServer(id.get(i)); 110 Integer aInteger=map.get(aString); 111 if(aInteger==null){ 112 map.put(aString,1); 113 }else{ 114 map.put(aString, aInteger+1); 115 } 116 } 117 Set<String> set= map.keySet(); 118 for(String a:set){ 119 System.out.println("節點【"+a+"】分配到元素個數為==>"+map.get(a)); 120 } 121 } 122 }
相關文章
- 對一致性Hash演算法,Java程式碼實現的深入研究2016-02-13演算法Java
- 【策略】一致性Hash演算法2017-05-17演算法
- 【轉載】對一致性Hash演算法,Java程式碼實現的深入研究2017-05-16演算法Java
- 強一致性hash實現java版本及強一致性hash原理2018-08-14Java
- Java實現一致性Hash演算法深入研究2016-02-14Java演算法
- 手動實現一致性 Hash 演算法2019-03-21演算法
- 自己實現一個一致性 Hash 演算法2019-03-04演算法
- 一致性hash演算法原理及go實現2018-04-25演算法Go
- 一致性Hash的原理與實現2022-04-10
- 一致性hash演算法2020-11-09演算法
- redis 雙寫實現策略 && hash取模2019-03-02Redis
- 一致性hash演算法的理解2018-08-29演算法
- 一致性 Hash 演算法的實際應用2019-03-01演算法
- 一致性hash的c++簡單實現2017-01-10C++
- 基於BKDRhash實現Hash演算法2014-09-12演算法
- PHP 之一致性 hash 演算法2019-06-24PHP演算法
- 一文搞懂一致性 hash 的原理和實現2021-07-20
- 一文搞懂一致性hash的原理和實現2021-07-20
- 什麼是一致性Hash演算法?2019-05-26演算法
- phpmemcached一致性hash2017-11-14PHP
- 一致性hash演算法的一些理解2022-02-17演算法
- 一個hash表的實現2013-07-28
- Hash演算法2018-11-20演算法
- Java教程分享:五分鐘瞭解一致性hash演算法2021-05-06Java演算法
- 短連結演算法實現–加鹽hash2019-01-19演算法
- Golang 實現 Redis(7): Redis 叢集與一致性 Hash2020-11-25GolangRedis
- 一致性Hash學習2014-05-15
- 10分鐘瞭解一致性hash演算法2019-08-06演算法
- 五分鐘瞭解一致性hash演算法2021-05-08演算法
- 一致性 hash 演算法( consistent hashing )2014-06-30演算法
- Hash演算法的講解2015-04-03演算法
- 【轉】什麼是一致性hash演算法?(詳解)2019-02-20演算法
- 分散式快取一致性hash演算法理解2017-12-23分散式快取演算法
- hash 表在 go 語言中的實現2021-04-16Go
- 7、域滲透——Pass The Hash的實現2018-06-11
- JAVA 實現的 SHA-256 和 SHA-512 兩種 Hash 演算法的呼叫2019-03-05Java演算法
- 閒聊 Hash 演算法2017-02-27演算法
- Hash join演算法原理2009-02-20演算法