下面的算法是对Dubbo源码中对于Ketama一致性Hash算法的改进后在项目中做负载均衡使用:
注意:
1.Dubbo的一致性Hash算法实现逻辑:
对每个一个注册的服务名,创建一个选择器(ConsistentHashSelector),这个选择器中维护了一个hash环,这个Hash环里存储着所有这个RPC服务提供者的地址,所以逻辑总结就是一个RPC服务,对应一个Hash环,一个Hash环里保存了这个Rpc服务提供的地址。
2.Key的生成逻辑:
当通过Key来选择对应的地址时,是以请求的方法加上参数生成Hash的,因为在Ketama哈希算法中,一串字符生成的Hash值是固定的。所以Dubbo的Key是以将方法的参数作为Key生成Hash的,我这里的逻辑是方法名+参数名作为Hash Key.这样保证每次请求时生成的Hash Key都不同,能够平衡的负载到各个服务器上。
/**
* @author zyz
*/
public class ConsistentHashLoadBalance1 extends AbstractLoadBalance {
// Key: rpcServiceName
private final ConcurrentMap<String, ConsistentHashSelector> selectors = new ConcurrentHashMap<>();
@Override
protected String doSelect(List<String> serviceAddresses, RpcRequestMessage msg) {
// 获取调用服务名
String rpcServiceName = msg.getInterfaceName();
// 生成调用列表hashCode
int identityHashCode = System.identityHashCode(rpcServiceName);
// 以调用rpcServiceName名为key,获取一致性hash选择器
ConsistentHashSelector selector = selectors.get(rpcServiceName);
// 若不存在则创建新的选择器
if (selector == null || selector.getIdentityHashCode() != identityHashCode) {
// 创建ConsistentHashSelector时会生成所有虚拟结点
selectors.put(rpcServiceName, new ConsistentHashSelector(serviceAddresses,identityHashCode));
// 获取选择器
selector = selectors.get(rpcServiceName);
}
// 选择结点
return selector.select(msg);
}
private static final class ConsistentHashSelector {
private final TreeMap<Long, String> virtualInvokers; // 虚拟结点
private final int replicaNumber = 160; // 副本数
private final int identityHashCode;// hashCode
// private final int[] argumentIndex; // 参数索引数组
public ConsistentHashSelector(List<String> invokers, int identityHashCode) {