dubbo源码分析第二十二篇一dubbo负载均衡-ConsistentHashLoadBalance及一致性hash算法
2022/1/20 17:42:17
本文主要是介绍dubbo源码分析第二十二篇一dubbo负载均衡-ConsistentHashLoadBalance及一致性hash算法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
ConsistentHashLoadBalance
原理图
第一步: 基于网络地址hash构建虚拟一致性hash表
获取接口与方法名
每个方法构建一致性hash选择器
通过选择器选择一个Invoker基于调用方法参数值hash获取hash结果
选择器选择Invoker的依据: 方法的参数值hash以及参与hash的方法参数数量
默认只有第一个参数的参数值参与hash
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) { 获取接口与方法名 String methodName = RpcUtils.getMethodName(invocation); String key = invokers.get(0).getUrl().getServiceKey() + "." + methodName; 每一个方法一个一致性hash选择器 int invokersHashCode = invokers.hashCode(); ConsistentHashSelector<T> selector = (ConsistentHashSelector<T>) selectors.get(key); if (selector == null || selector.identityHashCode != invokersHashCode) { selectors.put(key, new ConsistentHashSelector<T>(invokers, methodName, invokersHashCode)); selector = (ConsistentHashSelector<T>) selectors.get(key); } 通过选择器选择一个Invoker return selector.select(invocation); }
获取一致性hash选择器
- 获取方法配置的结点数,默认160
- 获取需要进行hash的参数数组索引,默认对第一个参数进行hash
- 构建一致性hash表,大小为replicaNumber*Invoker数量
private static final class ConsistentHashSelector<T> { private final TreeMap<Long, Invoker<T>> virtualInvokers; // 一致性hash表 大小为replicaNumber*Invoker数量 private final int replicaNumber; // 副本数 默认160个 private final int identityHashCode; private final int[] argumentIndex;// [0,1,2]几个参数参数参与hash 负载,默认只有第一个参数参与也就是数组为[0] ConsistentHashSelector(List<Invoker<T>> invokers, String methodName, int identityHashCode) { this.virtualInvokers = new TreeMap<Long, Invoker<T>>(); // 生成调用结点HashCode this.identityHashCode = identityHashCode; URL url = invokers.get(0).getUrl(); 获取方法配置的结点数,默认160 this.replicaNumber = url.getMethodParameter(methodName, HASH_NODES, 160); 获取需要进行hash的参数数组索引,默认对第一个参数进行 String methodParameter = url.getMethodParameter(methodName, HASH_ARGUMENTS, "0"); String[] index = COMMA_SPLIT_PATTERN.split(methodParameter); // {'0'} 构建参数hash的参数数组元信息 argumentIndex = new int[index.length]; for (int i = 0; i < index.length; i++) { argumentIndex[i] = Integer.parseInt(index[i]); } 构建一致性hash表 for (Invoker<T> invoker : invokers) { // 每个Invoker构建40*4个虚拟节点 String address = invoker.getUrl().getAddress(); for (int i = 0; i < replicaNumber / 4; i++) { // 每4个虚拟节点共用同一个地址进行hash // byte数组 128位 byte[] digest = md5(address + i); // 简单理解: 有40个不同地址的节点 [有40个节点的hash 通过地址加index进行md5 hash] for (int h = 0; h < 4; h++) { // 每个地址hash结果为128位,分成0~31 32——63 64~95 96~127四部分 long m = hash(digest, h); // 算出四部分每部分的hash值 virtualInvokers.put(m, invoker); // 加入一致性hash表[注意不是环] } } } }
负载实现
- 根据前面配置的argumentIndex,判断取几个参数进行一致性hash
- 默认argumentIndex 大小为1,数组值为0;表示取第一个参数进行hash
public Invoker<T> select(Invocation invocation) { 根据前面配置的argumentIndex,判断取几个参数进行一致性hash String key = toKey(invocation.getArguments()); byte[] digest = md5(key); return selectForKey(hash(digest, 0)); } private String toKey(Object[] args) { 默认argumentIndex 大小为1,数组值为0 表示取第一个参数进行hash StringBuilder buf = new StringBuilder(); for (int i : argumentIndex) { if (i >= 0 && i < args.length) { buf.append(args[i]); } } return buf.toString(); }
- 根据hash值取virtualInvokers一致性hash表上的节点
- 兜底逻辑: 溢出则取第一个
private Invoker<T> selectForKey(long hash) { Map.Entry<Long, Invoker<T>> entry = virtualInvokers.ceilingEntry(hash); if (entry == null) { entry = virtualInvokers.firstEntry(); } return entry.getValue(); }
这篇关于dubbo源码分析第二十二篇一dubbo负载均衡-ConsistentHashLoadBalance及一致性hash算法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享