public class RandomLoadBalance extends AbstractLoadBalance { @Override protected String doSelect(List<String> serviceAddresses, RpcRequest rpcRequest) { Random random = new Random(); return serviceAddresses.get(random.nextInt(serviceAddresses.size())); } }
ConsistentHashLoadBalance
一致性哈希算法,大名鼎鼎
里面有一个内部类ConsistentHashSelector
private final ConcurrentHashMap<String, ConsistentHashSelector> selectors = new ConcurrentHashMap<>();
每一个服务有对应的一致性选择器
ConsistentHashSelector
静态变量
private final TreeMap<Long, String> virtualInvokers;//一个红黑树,用于存储哈希值和对应的虚拟节点 private final int identityHashCode;//一致性哈希选择器的标识哈希码。这个标识哈希码的作用是在后续检测哈希环是否需要更新时使用。
ConsistentHashSelector(List<String> invokers, int replicaNumber/*每个实际节点对应虚拟节点的数量*/, int identityHashCode) { this.virtualInvokers = new TreeMap<>();//用于存储虚拟节点和他对应的位置,也就是哈希值 this.identityHashCode = identityHashCode;//保存一下这个东西,其实没啥用
for (String invoker : invokers) { for (int i = 0; i < replicaNumber / 4; i++) {//一轮注册四个虚拟节点 byte[] digest = md5(invoker + i);//+i是为了区分不同的虚拟节点 for (int h = 0; h < 4; h++) {//每个md5哈希值创造4个虚拟节点 long m = hash(digest, h);//随着h的变化,每个虚拟节点其实是对应的digest的不同字节片段的哈希值 virtualInvokers.put(m, invoker);//放到红黑树里面,就相当于注册虚拟节点了 } } } }
doSelect方法
看完上面的就都很好理解了
@Override protected String doSelect(List<String> serviceAddresses, RpcRequest rpcRequest) { int identityHashCode = System.identityHashCode(serviceAddresses); // build rpc service name by rpcRequest String rpcServiceName = rpcRequest.getRpcServiceName(); ConsistentHashSelector selector = selectors.get(rpcServiceName); // check for updates,不一致那么就更新,比如有过节点添加删除的情况 if (selector == null || selector.identityHashCode != identityHashCode) { selectors.put(rpcServiceName, new ConsistentHashSelector(serviceAddresses, 160, identityHashCode)); selector = selectors.get(rpcServiceName); } return selector.select(rpcServiceName + Arrays.stream(rpcRequest.getParameters()));//调用selector返回 }