热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

dubbo源码分析第二十二篇一dubbo负载均衡ConsistentHashLoadBalance及一致性hash算法

ConsistentHashLoadBalance原理图第一步:基于网络地址hash构建虚拟一致性hash表获取接口与方法名每个方法构建一致性hash选择器通过选择器选择一个In

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);}通过选择器选择一个Invokerreturn 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>>();// 生成调用结点HashCodethis.identityHashCode = identityHashCode;URL url = invokers.get(0).getUrl();获取方法配置的结点数,默认160this.replicaNumber = url.getMethodParameter(methodName, HASH_NODES, 160);获取需要进行hash的参数数组索引,默认对第一个参数进行String methodParameter = url.getMethodParameter(methodName, HASH_ARGUMENTS, "0");String[] index = COMMA_SPLIT_PATTERN.split(methodParameter); // {&#39;0&#39;}构建参数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,判断取几个参数进行一致性hashString key = toKey(invocation.getArguments());byte[] digest = md5(key);return selectForKey(hash(digest, 0));
}private String toKey(Object[] args) {默认argumentIndex 大小为1,数组值为0表示取第一个参数进行hashStringBuilder 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();}

推荐阅读
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • 本文详细探讨了KMP算法中next数组的构建及其应用,重点分析了未改良和改良后的next数组在字符串匹配中的作用。通过具体实例和代码实现,帮助读者更好地理解KMP算法的核心原理。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文介绍了如何使用 Spring Boot DevTools 实现应用程序在开发过程中自动重启。这一特性显著提高了开发效率,特别是在集成开发环境(IDE)中工作时,能够提供快速的反馈循环。默认情况下,DevTools 会监控类路径上的文件变化,并根据需要触发应用重启。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 本文探讨了Hive中内部表和外部表的区别及其在HDFS上的路径映射,详细解释了两者的创建、加载及删除操作,并提供了查看表详细信息的方法。通过对比这两种表类型,帮助读者理解如何更好地管理和保护数据。 ... [详细]
  • IneedtofocusTextCellsonebyoneviaabuttonclick.ItriedlistView.ScrollTo.我需要通过点击按钮逐个关注Tex ... [详细]
  • 本文深入探讨 MyBatis 中动态 SQL 的使用方法,包括 if/where、trim 自定义字符串截取规则、choose 分支选择、封装查询和修改条件的 where/set 标签、批量处理的 foreach 标签以及内置参数和 bind 的用法。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • 本文介绍如何使用 NSTimer 实现倒计时功能,详细讲解了初始化方法、参数配置以及具体实现步骤。通过示例代码展示如何创建和管理定时器,确保在指定时间间隔内执行特定任务。 ... [详细]
author-avatar
大小大空间_566
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有