A B C D四个节点, 顺时针旋转,1 归属到 B,2 归属到 C;
假设AB间新增节点 E,则只会影响 AE 之间的分布;
单一节点可能数据倾斜,故可考虑虚拟节点。
import cn.hutool.core.lang.hash.MurmurHash;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* 一致性哈希负载均衡器
*
*/
public class ConsistentHashLoadBalancer implements LoadBalancer {
/**
* 一致性 Hash 环,存放虚拟节点
*/
private final TreeMap<Integer, ServiceMetaInfo> virtualNodes = new TreeMap<>();
/**
* 虚拟节点数
*/
private static final int VIRTUAL_NODE_NUM = 100;
@Override
public ServiceMetaInfo select(Map<String, Object> requestParams, List<ServiceMetaInfo> serviceMetaInfoList) {
if (serviceMetaInfoList.isEmpty()) {
return null;
}
// 构建虚拟节点环
for (ServiceMetaInfo serviceMetaInfo : serviceMetaInfoList) {
for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {
int hash = getHash(serviceMetaInfo.getServiceAddress() + "#" + i);
virtualNodes.put(hash, serviceMetaInfo);
}
}
// 获取调用请求的 hash 值
int hash = getHash(requestParams);
// 选择最接近且大于等于调用请求 hash 值的虚拟节点
Map.Entry<Integer, ServiceMetaInfo> entry = virtualNodes.ceilingEntry(hash);
if (entry == null) {
// 如果没有大于等于调用请求 hash 值的虚拟节点,则返回环首部的节点
entry = virtualNodes.firstEntry();
}
return entry.getValue();
}
/**
* Hash 算法,可自行实现
*
* @param key
* @return
*/
private int getHash(Object key) {
return MurmurHash.hash32(key.toString());
}
}