關(guān)于一致性Hash算法原理可參考文章:一致性hash算法原理與實現(xiàn)
public class TreeMapConsistentHash {
/**
* 虛擬節(jié)點數(shù)量
*/
private static final int VIRTUAL_NODE_SIZE = 4;
/**
* 定義treeMap
*/
private TreeMap<Long, String> tree = new TreeMap<>();
/**
* 在服務(wù)器列表中根據(jù)key定位節(jié)點
* @param values 服務(wù)器列表
* @param key token
* @return
*/
public String choose(List<String> values, String key) {
for (String value: values) {
//value作為key,hash值作為value
add(hash(value), value);
}
return selectNode(key);
}
/**
* hash落環(huán)走越,并加入虛擬節(jié)點
* @param key
* @param value
*/
private void add(long key, String value) {
tree.clear();
//虛擬節(jié)點
for (int i = 0; i < VIRTUAL_NODE_SIZE; i++) {
Long hash = this.hash("vir" + key + i);
tree.put(hash, value);
}
tree.put(key, value);
}
/**
* 在環(huán)中根據(jù)傳入的值找到第一個server
* 使用tailMap特性模擬hash環(huán)旨指,如果tailMap返回空,則表示已經(jīng)到了hash環(huán)的末尾谆构,那么需要使用第一個key
* @param value
* @return
*/
private String selectNode(String value) {
long hash = hash(value);
SortedMap<Long, String> after = tree.tailMap(hash);
if (after != null && !after.isEmpty()) {
String server = after.get(after.firstKey());
System.out.println("路由成功:value: " + value + ", route server: " + server );
return server;
}
return tree.firstEntry().getValue();
}
/**
* hash計算
* @param value
* @return
*/
private Long hash(String value) {
byte[] digest = DigestUtils.md5(value);
// hash code, Truncate to 32-bits
long hashCode = ((long) (digest[3] & 0xFF) << 24) | ((long) (digest[2] & 0xFF) << 16) | ((long) (digest[1] & 0xFF) << 8) | (digest[0] & 0xFF);
long truncateHashCode = hashCode & 0xffffffffL;
return truncateHashCode;
}
}
如何使用
比如我們使用zookeeper作為注冊中心呵晨,那么將應(yīng)用注冊到zookeeper的特定節(jié)點下摸屠,取出節(jié)點下所有應(yīng)用的服務(wù)地址猪杭,根據(jù)consumer方的
key hash值來選擇具體調(diào)用那個provider
public class ConsistentHashRouter implements Router {
private TreeMapConsistentHash hash = new TreeMapConsistentHash();
/**
* values: List<String> servers = Lists.newArrayList("127.0.0.1","192.168.11.1" ...)
* key: consumer的特定數(shù)值妥衣,比如根據(jù)userId
**/
@Override
public String chooseServer(List<String> values, String key) {
return hash.choose(values,key);
}
}