缘起
关于一致性hash算法的原理,本文不做概述。本文说的是如何在java中实现一致性Hash算法。
代码
package com.bxoon.test;
import java.util.*;
/**
* 一致性Hash
* @author zhongguangxi
*/
public class ConsistenceHash {
// 物理节点集合
private List<String> realNodes = new ArrayList<>();
// 虚拟节点数,用户指定
private int viretalNums = 100;
// 物理节点与虚拟节点的对应关系存储
private Map<String,List<Integer>> real2VirtualMap = new HashMap<>();
// 排序存储结构红黑树,key是虚拟节点的hash值,value是物理节点
private SortedMap<Long,String> sortedMap = new TreeMap<>();
public ConsistenceHash(int viretalNums) {
super();
this.viretalNums = viretalNums;
}
public ConsistenceHash() {
super();
}
/**
* 添加物理节点
* @param node
*/
public void addService(String node){
String vnode = null;
int i = 0;
for (int count=0;count<viretalNums;){
i++;
vnode = node+"-"+i;
long hashValue = FNV1_32_HASH.hash(vnode);
if (!this.sortedMap.containsKey(hashValue)){
count++;
this.sortedMap.put(hashValue,node);
}
}
this.realNodes.add(node);
}
/**
* 删除物理节点
* @param node
*/
public void removeService(String node){
}
/**
* 获取数据的存取节点
* @param key
* @return
*/
public String getService(String key){
long hash = FNV1_32_HASH.hash(key);
SortedMap<Long,String> map = this.sortedMap.tailMap(hash);
if (map.isEmpty()){
return this.sortedMap.get(sortedMap.firstKey());
}else{
return map.get(map.firstKey());
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
ConsistenceHash consistenceHash = new ConsistenceHash();
consistenceHash.addService("193.168.1.10");
consistenceHash.addService("193.168.1.11");
consistenceHash.addService("193.168.1.12");
for (int i =0;i<100;i++){
System.out.println("a"+i+" 对应的服务器:"+consistenceHash.getService("a"+i));
}
}
}
输出结果
a0 对应的服务器:193.168.1.12
a1 对应的服务器:193.168.1.12
a2 对应的服务器:193.168.1.12
a3 对应的服务器:193.168.1.11
a4 对应的服务器:193.168.1.10
a5 对应的服务器:193.168.1.11
a6 对应的服务器:193.168.1.10
a7 对应的服务器:193.168.1.12
a8 对应的服务器:193.168.1.10
a9 对应的服务器:193.168.1.11
a10 对应的服务器:193.168.1.12
a11 对应的服务器:193.168.1.12
a12 对应的服务器:193.168.1.12
a13 对应的服务器:193.168.1.12
a14 对应的服务器:193.168.1.11
a15 对应的服务器:193.168.1.10
a16 对应的服务器:193.168.1.10
a17 对应的服务器:193.168.1.10
a18 对应的服务器:193.168.1.10
a19 对应的服务器:193.168.1.10
a20 对应的服务器:193.168.1.12
a21 对应的服务器:193.168.1.12
a22 对应的服务器:193.168.1.10
a23 对应的服务器:193.168.1.10
a24 对应的服务器:193.168.1.12
a25 对应的服务器:193.168.1.10
a26 对应的服务器:193.168.1.12
a27 对应的服务器:193.168.1.11
a28 对应的服务器:193.168.1.10
a29 对应的服务器:193.168.1.12
a30 对应的服务器:193.168.1.12
a31 对应的服务器:193.168.1.12
a32 对应的服务器:193.168.1.12
a33 对应的服务器:193.168.1.12
a34 对应的服务器:193.168.1.12
a35 对应的服务器:193.168.1.10
a36 对应的服务器:193.168.1.10
a37 对应的服务器:193.168.1.11
a38 对应的服务器:193.168.1.10
a39 对应的服务器:193.168.1.11
a40 对应的服务器:193.168.1.11
a41 对应的服务器:193.168.1.11
a42 对应的服务器:193.168.1.12
a43 对应的服务器:193.168.1.10
a44 对应的服务器:193.168.1.12
a45 对应的服务器:193.168.1.11
a46 对应的服务器:193.168.1.10
a47 对应的服务器:193.168.1.11
a48 对应的服务器:193.168.1.10
a49 对应的服务器:193.168.1.10
a50 对应的服务器:193.168.1.10
a51 对应的服务器:193.168.1.10
a52 对应的服务器:193.168.1.12
a53 对应的服务器:193.168.1.10
a54 对应的服务器:193.168.1.10
a55 对应的服务器:193.168.1.11
a56 对应的服务器:193.168.1.10
a57 对应的服务器:193.168.1.11
a58 对应的服务器:193.168.1.12
a59 对应的服务器:193.168.1.12
a60 对应的服务器:193.168.1.12
a61 对应的服务器:193.168.1.11
a62 对应的服务器:193.168.1.12
a63 对应的服务器:193.168.1.10
a64 对应的服务器:193.168.1.12
a65 对应的服务器:193.168.1.12
a66 对应的服务器:193.168.1.11
a67 对应的服务器:193.168.1.10
a68 对应的服务器:193.168.1.12
a69 对应的服务器:193.168.1.12
a70 对应的服务器:193.168.1.11
a71 对应的服务器:193.168.1.12
a72 对应的服务器:193.168.1.12
a73 对应的服务器:193.168.1.10
a74 对应的服务器:193.168.1.12
a75 对应的服务器:193.168.1.10
a76 对应的服务器:193.168.1.12
a77 对应的服务器:193.168.1.10
a78 对应的服务器:193.168.1.10
a79 对应的服务器:193.168.1.11
a80 对应的服务器:193.168.1.12
a81 对应的服务器:193.168.1.10
a82 对应的服务器:193.168.1.12
a83 对应的服务器:193.168.1.12
a84 对应的服务器:193.168.1.12
a85 对应的服务器:193.168.1.12
a86 对应的服务器:193.168.1.10
a87 对应的服务器:193.168.1.10
a88 对应的服务器:193.168.1.11
a89 对应的服务器:193.168.1.10
a90 对应的服务器:193.168.1.11
a91 对应的服务器:193.168.1.12
a92 对应的服务器:193.168.1.11
a93 对应的服务器:193.168.1.12
a94 对应的服务器:193.168.1.10
a95 对应的服务器:193.168.1.11
a96 对应的服务器:193.168.1.11
a97 对应的服务器:193.168.1.10
a98 对应的服务器:193.168.1.10
a99 对应的服务器:193.168.1.11
结论
可以看到测试结果,每一个key都落在了对应的节点上。
基本原理
1.添加物理节点的时候要添加对应的虚拟节点
2.在一个Map<String,Node>中保存虚拟节点和物理节点的对应关系,其中key为虚拟节点的Hash,而value为物理节点
3.在获取节点的时候,根据某个key的hash值得到离他最近的一个节点,如果没有的话则取集合中第一个节点,这样就形成了一个环。