1. 參考文章
2. 示例代碼
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* 一致性 Hash 實(shí)現(xiàn)
*/
class ConsistentHash {
private final SortedMap<Integer, String> hashNodesMap = new TreeMap<>();
private final Map<String, String> virtualNodesMap = new HashMap<>();
/**
* @param nodeKeys 節(jié)點(diǎn) key 列表
* @param virtualNodeCount 虛擬節(jié)點(diǎn)數(shù)量, 提升 Hash 均衡性
*/
public ConsistentHash(List<String> nodeKeys, int virtualNodeCount) {
for (String nodeKey : nodeKeys) {
addNode(nodeKey);
}
final int nodeCount = nodeKeys.size();
for (int i = 0; i < virtualNodeCount; ++i) {
String nodeKey = nodeKeys.get(i % nodeCount);
String virtualNodeKey = String.format("VirtualNode_%s_%s", nodeKey, i);
addNode(virtualNodeKey);
virtualNodesMap.put(virtualNodeKey, nodeKey);
}
}
/**
* 獲取對(duì)應(yīng)的 key
*/
public String getNodeKey(String accessKey) {
int hash = bkdHash(accessKey);
SortedMap<Integer, String> tailMap = hashNodesMap.tailMap(hash);
if (tailMap.isEmpty()) {
tailMap = hashNodesMap;
}
String nodeKey = tailMap.get(tailMap.firstKey());
String realNodeKey = virtualNodesMap.get(nodeKey);
return realNodeKey != null ? realNodeKey : nodeKey;
}
/**
* 添加節(jié)點(diǎn)
*/
private void addNode(String nodeKey) {
hashNodesMap.put(bkdHash(nodeKey), nodeKey);
}
/**
* BKD hash 算法實(shí)現(xiàn)
*/
private static int bkdHash(String value) {
final int seed = 31;
int hash = 0;
value = md5(value);
for (int i = 0; i != value.length(); ++i) {
hash = seed * hash + value.charAt(i);
}
return hash;
}
/**
* MD5 算法
*/
private static String md5(String value) {
byte[] bytes = value.getBytes();
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
bytes = md5.digest(bytes);
StringBuilder builder = new StringBuilder();
for (byte b : bytes) {
String temp = Integer.toHexString(b & 255);
if (temp.length() == 1) {
builder.append('0');
}
builder.append(temp);
}
return builder.toString();
} catch (NoSuchAlgorithmException var8) {
var8.printStackTrace();
}
return "";
}
}
/**
* 一致性 Hash Demo
*/
public class ConsistentHashDemo {
public static void main(String[] args) {
List<String> nodes = new ArrayList<>();
nodes.add("10.234.23.135");
nodes.add("10.234.23.136");
nodes.add("10.234.23.137");
nodes.add("10.234.23.138");
ConsistentHash hash = new ConsistentHash(nodes, 8);
printServerIp(hash, "0b91c015160325042515067851893");
printServerIp(hash, "0b91c015160325042594167881893");
printServerIp(hash, "0b91c015160325049004068161893");
printServerIp(hash, "0b91c015160325064717068581893");
}
private static void printServerIp(ConsistentHash hash, String accessKey) {
System.out.println(String.format("%s - %s", accessKey, hash.getNodeKey(accessKey)));
}
}
運(yùn)行結(jié)果:
0b91c015160325042515067851893 - 10.234.23.135
0b91c015160325042594167881893 - 10.234.23.136
0b91c015160325049004068161893 - 10.234.23.136
0b91c015160325064717068581893 - 10.234.23.137