java 一致性hash算法 均衡分发_负载均衡-基础-一致性哈希算法及java实现

1 /**

2 * 一致性hash 的java 实现3 *@authorluoqiang4 * @data 2016/11/085 */

6 public classConsistencyHash {7

8 public ConsistencyHash(Listshards){9 shards =shards;10 init();11 }12

13 private static classNode{14 privateString name;15 privateString ip;16

17 publicNode(String name, String ip) {18 this.name =name;19 this.ip =ip;20 }21

22 publicString getName() {23 returnname;24 }25

26 public voidsetName(String name) {27 this.name =name;28 }29

30 publicString getIp() {31 returnip;32 }33

34 public voidsetIp(String ip) {35 this.ip =ip;36 }37

38 @Override39 publicString toString() {40 return "Node{" +

41 "ip='" + ip + '\'' +

42 ", name='" + name + '\'' +

43 '}';44 }45 }46

47 private static classClient{48 publicClient(String name, Long hashCode) {49 this.name =name;50 this.hashCode =hashCode;51 }52

53 publicClient(String name) {54 this.name =name;55 }56

57 privateString name;58 privateLong hashCode;59

60 publicString getName() {61 returnname;62 }63

64 public voidsetName(String name) {65 this.name =name;66 }67

68 publicLong getHashCode() {69 returnhashCode;70 }71

72 public voidsetHashCode(Long hashCode) {73 this.hashCode =hashCode;74 }75 }76

77 private static TreeMap nodes;//虚拟节点hash值 到 真实主机 的映射

78

79 private static TreeMap treeKey;//客户端hash值 到 真实节点 的映射

80

81 private static List shards = new ArrayList();//真实主机

82

83 private static List cliends = new ArrayList();//客户端

84

85 private static TreeMap clientTree;//客户端自己hash 和客户端的映射

86

87 private static final int NODE_NUM = 100;//每个机器节点关联的虚拟节点个数

88

89

90 private voidinit(){91 nodes = new TreeMap();92 treeKey = new TreeMap();93 clientTree = new TreeMap();94 for (int i = 0; i < shards.size(); i++) {95 final Node shardInfo =shards.get(i);96 for (int n = 0; n < NODE_NUM; n++) {97 Long key = hash("SHARD-"+shardInfo.name+"-NODE-"+n);98 nodes.put(key,shardInfo);99 }100 }101 }102

103 /**

104 * 添加一个真实主机105 */

106 private voidaddNode(Node n){107 System.out.println("添加主机"+n+"的变化:");108 for (int i = 0; i < NODE_NUM; i++) {109 Long lg = hash("SHARD-"+n.name+"-NODE-"+i);110 SortedMap head =nodes.headMap(lg);111 SortedMapbetween;112 if(head.size() == 0){113 between = treeKey.tailMap(nodes.lastKey());//建立在 最后一个虚拟主机的hash值 不和 客户端的hash值相等。

114 }else{115 Long begin =head.lastKey();116 between =treeKey.subMap(begin,lg);117 }118 nodes.put(lg,n);119 for(Iterator it=between.keySet().iterator();it.hasNext();){120 Long lo =it.next();121 treeKey.put(lo, nodes.get(lg));122 }123 }124 }125

126 /**

127 * 删除一个真实主机128 *@paramn129 */

130 private voiddeleteNode(Node n){131 System.out.println("删除主机"+n+"的变化:");132 for (int i = 0; i < NODE_NUM; i++) {133 Long virturalHashCode = hash("SHARD-" + n.name + "-NODE-" +i);134 SortedMap tail = nodes.tailMap(virturalHashCode);//等于和大于 此值 == 顺时针 环形此值后面

135 SortedMap head = nodes.headMap(virturalHashCode);//严格小于 此值(不等于) == 顺时针 环形此值前面

136 SortedMapbetween;137 if(head.size() == 0){138 between =treeKey.tailMap(nodes.lastKey());139 }else{140 Long begin =head.lastKey();141 Long end =tail.firstKey();142 /**

143 * 方法用于返回此映射的键值从fromKey(包括)到toKey(不包括)的部分视图。144 * (如果fromKey和toKey相等,则返回映射为空)返回的映射受此映射支持,145 * 因此改变返回映射反映在此映射中,反之亦然。146 */

147 between = treeKey.subMap(begin,end);//在n节点的第i个虚拟节点的所有key的集合

148 }149 nodes.remove(virturalHashCode);//从nodes中删除n节点的第i个虚拟节点

150 for(Iterator it =between.keySet().iterator();it.hasNext();){151 Long lo =it.next();152 treeKey.put(lo, nodes.get(tail.firstKey()));153 }154 }155 }156

157 /**

158 * 客户端hash值 映射 到 真实主机159 */

160 private void keyToNode(Listclients){161 for(Client client : clients) {162 Long hashCode =hash(client.getName());163 SortedMap tail = nodes.tailMap(hashCode); //沿环的顺时针找到一个虚拟节点

164 Node node = tail.size() == 0 ?nodes.get(nodes.firstKey()) : nodes.get(tail.firstKey());165 treeKey.put(hashCode,node);166 client.setHashCode(hashCode);167 clientTree.put(hashCode,client);168 }169 }170

171 /**

172 * 输出客户端 映射到 真实主机173 */

174 private voidprintKeyTree(){175 for(Iterator it =treeKey.keySet().iterator();it.hasNext();){176 Long lo =it.next();177 System.out.println(clientTree.get(lo).name+"(hash:"+lo+")连接到主机->"+treeKey.get(lo));178 }179 }180

181 /**

182 * MurMurHash算法,是非加密HASH算法,性能很高,183 * 比传统的CRC32,MD5,SHA-1184 * (这两个算法都是加密HASH算法,复杂度本身就很高,带来的性能上的损害也不可避免)185 * 等HASH算法要快很多,而且据说这个算法的碰撞率很低.186 *http://murmurhash.googlepages.com/

187 */

188 privateLong hash(String key){189

190 ByteBuffer buf =ByteBuffer.wrap(key.getBytes());191 int seed = 0x1234ABCD;192

193 ByteOrder byteOrder =buf.order();194 buf.order(ByteOrder.LITTLE_ENDIAN);195

196 long m = 0xc6a4a7935bd1e995L;197 int r = 47;198

199 long h = seed ^ (buf.remaining() *m);200

201 longk;202 while (buf.remaining() >= 8) {203 k =buf.getLong();204

205 k *=m;206 k ^= k >>>r;207 k *=m;208

209 h ^=k;210 h *=m;211 }212

213 if (buf.remaining() > 0) {214 ByteBuffer finish = ByteBuffer.allocate(8).order(215 ByteOrder.LITTLE_ENDIAN);216 //for big-endian version, do this first:217 //finish.position(8-buf.remaining());

218 finish.put(buf).rewind();219 h ^=finish.getLong();220 h *=m;221 }222

223 h ^= h >>>r;224 h *=m;225 h ^= h >>>r;226

227 buf.order(byteOrder);228 returnh;229 }230

231

232 public static voidmain(String[] args) {233 /**

234 * 客户端的hash值 和 真实主机的100个虚拟节点的hash值235 *236 * 一起均匀地分布在顺时针由小到大这个环上。(0 - 2^32 )237 *238 * 具体 客户端 最终 连接到 哪个主机,239 *240 * 原则是:将客户端hash值,顺时针往后 最近的 虚拟节点hash值。241 *242 */

243 Node s1 = new Node("s1", "192.168.1.1");244 Node s2 = new Node("s2", "192.168.1.2");245 Node s3 = new Node("s3", "192.168.1.3");246 Node s4 = new Node("s4", "192.168.1.4");247 Node s5 = new Node("s5", "192.168.1.5");248 shards.add(s1);249 shards.add(s2);250 shards.add(s3);251 shards.add(s4);252 ConsistencyHash sh = newConsistencyHash(shards);253 System.out.println("添加客户端,一开始有4个主机,分别为s1,s2,s3,s4,每个主机有100个虚拟主机:");254 for (int i = 1; i <= 9; i++) {255 String name = "10"+i+"客户端";256 cliends.add(newClient(name));257 }258 sh.keyToNode(cliends);259 sh.printKeyTree();260 sh.deleteNode(s2);261 sh.printKeyTree();262 sh.addNode(s5);263 sh.printKeyTree();264 }265 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值