
文章插图
所以这里我们可以改造这个哈希环的范围,假设我们改为 100000 。十进制的 100000 对于的 16 进制为 186A0。所以我们改造后的哈希算法为:

文章插图
再次调用后可以看到,计算后的哈希值都在10万以内 。但是分布极不均匀,说明修改数据后这个哈希算法不是一个优秀的哈希算法:

文章插图
以上,就是对一致性哈希算法在Dubbo中的实现的解读 。需要特殊说明一下的是,一致性哈希负载均衡策略和权重没有任何关系 。
我又发现了一个BUG前面我介绍了Dubbo 2.6.5版本之前,最小活跃数算法的两个 bug 。
很不幸,这次我又发现了Dubbo 2.7.4.1版本,一致性哈希负载均衡策略的一个bug,我提交了issue 地址如下:
https://github.com/apache/dubbo/issues/5429

文章插图
我在这里详细说一下这个Bug现象、原因和我的解决方案 。
现象如下,我们调用三次服务端:

文章插图
输出日志如下(有部分删减):

文章插图
可以看到,在三次调用的过程中并没有发生服务的上下线操作,但是每一次调用都重新进行了哈希环的映射 。而我们预期的结果是应该只有在第一次调用的时候进行哈希环的映射,如果没有服务上下线的操作,后续请求根据已经映射好的哈希环进行处理 。
上面输出的原因是由于每次调用的invokers的identityHashCode发生了变化:

文章插图
我们看一下三次调用invokers的情况:

文章插图
经过debug我们可以看出因为每次调用的invokers地址值不是同一个,所以System.identityHashCode(invokers)方法返回的值都不一样 。
接下来的问题就是为什么每次调用的invokers地址值都不一样呢?
经过Debug之后,可以找到这个地方:
org.apache.dubbo.rpc.cluster.RouterChain#route

文章插图
问题就出在这个TagRouter中:
org.apache.dubbo.rpc.cluster.router.tag.TagRouter#filterInvoker

文章插图
所以,在TagRouter中的stream操作,改变了invokers,导致每次调用时其
System.identityHashCode(invokers)返回的值不一样 。所以每次调用都会进行哈希环的映射操作,在服务节点多,虚拟节点多的情况下会有一定的性能问题 。
到这一步,问题又发生了变化 。这个TagRouter怎么来的呢?
如果了解Dubbo 2.7.x版本新特性的朋友可能知道,标签路由是Dubbo2.7引入的新功能 。

文章插图
通过加载下面的配置加载了RouterFactrory:
META-INFdubbointernal
org.apache.dubbo.rpc.cluster.RouterFactory(Dubbo 2.7.0版本之前)
META-INFdubbointernal
com.alibaba.dubbo.rpc.cluster.RouterFactory(Dubbo 2.7.0之前)
下面是Dubbo 2.6.7(2.6.x的最后一个版本)和Dubbo 2.7.0版本该文件的对比:

文章插图
可以看到确实是在 Dubbo 2.7.0 之后引入了 TagRouter 。
至此,Dubbo 2.7.0 版本之后,一致性哈希负载均衡算法的 Bug 的来龙去脉也介绍清楚了 。
解决方案是什么呢?特别简单,把获取 identityHashCode 的方法从 System.identityHashCode(invokers) 修改为 invokers.hashCode() 即可 。
此方案是我提的 issue 里面的评论,这里 System.identityHashCode 和 hashCode 之间的联系和区别就不进行展开讲述了,不清楚的大家可以自行了解一下 。
(我的另外一篇文章:够强!一行代码就修复了我提的Dubbo的Bug 。)

文章插图
改完之后,我们再看看运行效果:

文章插图
推荐阅读
- 带你走进潮汕工夫茶,工夫茶点心
- 带你了解安徽四大名茶,安徽茶打四大品牌
- 带你去看美团架构
- 万字长文讲解编码知识,看这文就够了!| 原力计划
- 一文带你彻底理解Linux的各种终端类型及概念
- 一篇长文学懂入门推荐算法库:surprise
- 电力负荷怎么计算?几分钟带你了解清楚,好东西,赶紧收藏
- 最新百度信息流产品手册,带你全面了解百度产品
- 三分钟带你了解香槟产区另一面,谈香槟,你也是行家
- 没有人比我更懂电流,今天带你重新认识电流
