速读摘要文章源自JAVA秀-https://www.javaxiu.com/19413.html
这个pr是修复LFU缓存策略在Dubbo中即使配置了,也不起作用的bug。经过上面的分析,其实你也发现了,这个并不是一个有什么技术含量的提交。当时这个版本推出之后,我就赶紧去研究了一下对应部分的源码,然后写下这篇自称为全网第一篇解析Dubbo 2.7.5里程碑版本中的客户端线程模型优化的文章。于是我就在想,我当时写文章的时候也是深入到源码里面了呀,为什么没有发现这样的问题呢?文章源自JAVA秀-https://www.javaxiu.com/19413.html
原文约 3251 字 | 图片 25 张 | 建议阅读 7 分钟 | 评价反馈文章源自JAVA秀-https://www.javaxiu.com/19413.html
修了Apache Dubbo的一个bug
大数据肌肉猿 文章源自JAVA秀-https://www.javaxiu.com/19413.html
以下文章来源于why技术,作者why技术文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html 文章源自JAVA秀-https://www.javaxiu.com/19413.html why技术文章源自JAVA秀-https://www.javaxiu.com/19413.html 一个主要写代码,经常写文章,偶尔拍视频的风骚程序猿。文章源自JAVA秀-https://www.javaxiu.com/19413.html
这篇文章其实并没有什么技术性的分享,从我的角度而言,更多是记录和思考。文章源自JAVA秀-https://www.javaxiu.com/19413.html
把我对于源码和之前写的部分文章反哺给我的一些东西,带来的一点点思考分享给大家。文章源自JAVA秀-https://www.javaxiu.com/19413.html
一行源码
我很长时间没打开我的 Outlook 邮箱了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
前两天打开的时候发现我之前给 Dubbo 提交的 pr 居然已经被合并到 master 了:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
这是第一次,我提交的 pr 被合并了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
这个 pr 是修复 LFU 缓存策略在 Dubbo 中即使配置了,也不起作用的 bug。文章源自JAVA秀-https://www.javaxiu.com/19413.html
于是我也算是为开源项目贡献过源码的人了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
什么你问我贡献了多少代码?文章源自JAVA秀-https://www.javaxiu.com/19413.html
一行,是的,就一行!文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
而且,说起来,这次提交真的是没有什么技术含量的事情。因为这是一个必现的 bug,只是很少有人用到这个功能而已。文章源自JAVA秀-https://www.javaxiu.com/19413.html
你知道的,当一个 bug 能稳定复现的时候,其实它已经就不算是一个 bug 了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
但是我想聊聊这次提交背后的一些东西。文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
发现与解决文章源自JAVA秀-https://www.javaxiu.com/19413.html
从宿命论的角度来说,当我写下面这篇文章的第一个字的时候,这个 bug 就注定是等着我去发现并修复了:文章源自JAVA秀-https://www.javaxiu.com/19413.html
其实吧,LRU也就那么回事。文章源自JAVA秀-https://www.javaxiu.com/19413.html
而这篇文章我敲下第一个字的时间是 2020 年 12 月的下旬,这是我 2020 年的最后一篇技术原创文章。文章源自JAVA秀-https://www.javaxiu.com/19413.html
当我写 LRU 的时候,我就知道 LFU 肯定也是需要专门写一篇的。文章源自JAVA秀-https://www.javaxiu.com/19413.html
于是 2021 年的第一篇技术原创文章,我就选题了 LFU。文章源自JAVA秀-https://www.javaxiu.com/19413.html
产生了这篇文章:文章源自JAVA秀-https://www.javaxiu.com/19413.html
哎,这让人抠脑壳的 LFU。文章源自JAVA秀-https://www.javaxiu.com/19413.html
写这篇文章的时候,我想起之前看 Dubbo 的版本,好像是提到了一下 LFU。文章源自JAVA秀-https://www.javaxiu.com/19413.html
于是我翻到了 2.7.7 版本的发布内容:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
果然是支持了 LFU 缓存策略,于是翻出了提交的代码记录:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
虽然他的实现逻辑没有问题,Test 类也跑过去了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
但是毫不夸张的说,我看了一眼这个提交记录,通过眼神编译,就发现了这里势必是有问题的。文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
他仅仅是把 LFU 缓存策略集合到了 Dubbo 代码中,但是却未提供使用的入口。文章源自JAVA秀-https://www.javaxiu.com/19413.html
因为这里是基于 SPI 实现的,他没有在对应的配置文件中加入配置。文章源自JAVA秀-https://www.javaxiu.com/19413.html
这个问题非常容易验证,我们可以看一下。文章源自JAVA秀-https://www.javaxiu.com/19413.html
其源码的位置是:org.apache.dubbo.common.utils.LFUCache
文章源自JAVA秀-https://www.javaxiu.com/19413.html
源码里面告诉我这样配置一下就可以使用 LFU 的缓存策略:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
但是,当我这样配置,发起调用之后,是这样的:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
可以看到当前请求的缓存策略确实是 LFU。文章源自JAVA秀-https://www.javaxiu.com/19413.html
但是会抛出一个错误:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
No such extension org.apache.dubbo.cache.CacheFactory by name lfu
文章源自JAVA秀-https://www.javaxiu.com/19413.html
没有 LFU 这个策略。文章源自JAVA秀-https://www.javaxiu.com/19413.html
这不是玩我吗?文章源自JAVA秀-https://www.javaxiu.com/19413.html
再看一下具体的原因:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
在 org.apache.dubbo.common.extension.ExtensionLoader#getExtensionClasses
处只获取到了 4 个缓存策略,并没有我们想要的 LFU。文章源自JAVA秀-https://www.javaxiu.com/19413.html
所以,在这里抛出了异常:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
为什么没有找到我们想要的 LFU 呢?文章源自JAVA秀-https://www.javaxiu.com/19413.html
那就得看你熟不熟悉 SPI 了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
在 SPI 文件中,确实没有 LFU 的配置:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
所以,这是个 Bug,而这个 Bug 的解决方案,就是在 SPI 文件里面加上一行 LFU 的配置即可。文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
经过上面的分析,其实你也发现了,这个并不是一个有什么技术含量的提交。文章源自JAVA秀-https://www.javaxiu.com/19413.html
更多的是运气成分。文章源自JAVA秀-https://www.javaxiu.com/19413.html
只是由于对于 Dubbo 框架有些许的了解,所以对于这个地方,我发现问题、定位问题、解决问题的速度非常的快。文章源自JAVA秀-https://www.javaxiu.com/19413.html
这是运气给不了我的东西。文章源自JAVA秀-https://www.javaxiu.com/19413.html
这需要日复一日的潜入到框架中去,去感受它的脉络,梳理它的结构,学习它的思想。文章源自JAVA秀-https://www.javaxiu.com/19413.html
这是需要时间去沉淀和学习的东西。文章源自JAVA秀-https://www.javaxiu.com/19413.html
注意,我说的是“潜入”,而非是流于表面的。文章源自JAVA秀-https://www.javaxiu.com/19413.html
什么是流于表面的呢?文章源自JAVA秀-https://www.javaxiu.com/19413.html
比如,如果你之前没有用过 Dubbo 框架,但你又想去了解,学习它。文章源自JAVA秀-https://www.javaxiu.com/19413.html
于是你看到了我的这篇或者其他的和 Dubbo 相关的文章,企图从这些文章中入手。文章源自JAVA秀-https://www.javaxiu.com/19413.html
记住鲁迅先生的话:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
这里只适合查漏补缺,不适合系统的学习。文章源自JAVA秀-https://www.javaxiu.com/19413.html
亦或者是你在搜索框里面,输入 “Dubbo”,然后漫无目的的看了起来。文章源自JAVA秀-https://www.javaxiu.com/19413.html
哪怕你买了一本 Dubbo 相关的书或者看了 Dubbo 相关的系列视频,进行系统的学习。文章源自JAVA秀-https://www.javaxiu.com/19413.html
我觉得,只要没有自己亲手去做,都属于流于表面。文章源自JAVA秀-https://www.javaxiu.com/19413.html
而自己动手的第一步,就是搭建 Demo,从 Demo 入手。文章源自JAVA秀-https://www.javaxiu.com/19413.html
到后面高阶一点的就是你了解到了这个框架的前世今生,能在几个大版本之间进行横向对比,知道为什么升级、怎么升级、升级之后是怎么样的。文章源自JAVA秀-https://www.javaxiu.com/19413.html
再之后,能细致到某一个大的模块的演变是怎样的,历史上出现过哪些 Bug,是怎么去修复的,在哪个版本之后修复了,是稳定的。文章源自JAVA秀-https://www.javaxiu.com/19413.html
再举个例子吧。文章源自JAVA秀-https://www.javaxiu.com/19413.html
另外一个bug
回到最开始的地方,我为什么会在写 LFU 的时候联想到 Dubbo 呢?文章源自JAVA秀-https://www.javaxiu.com/19413.html
因为在 2.7.7 这个版本发布的时候,我就关注到了它。文章源自JAVA秀-https://www.javaxiu.com/19413.html
而当时关注到它的原因并不是 LFU ,而是新增了一种负载均衡策略:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
于是我把之前的文章进行了汇总,写下了这篇文章:文章源自JAVA秀-https://www.javaxiu.com/19413.html
吐血输出:2万字长文带你细细盘点五种负载均衡策略。文章源自JAVA秀-https://www.javaxiu.com/19413.html
而其中一致性哈希负载均衡策略,我在实践的时候也发现了一个 bug。文章源自JAVA秀-https://www.javaxiu.com/19413.html
其实这个 bug 也是一个必现的 bug,为什么没有被爆出来的原因,我想是因为当前的版本使用的人不多,而使用一致性哈希负载均衡策略的就更少了,甚至没有。文章源自JAVA秀-https://www.javaxiu.com/19413.html
这个 bug 具体是这样的:文章源自JAVA秀-https://www.javaxiu.com/19413.html
https://github.com/apache/dubbo/issues/5429文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
我已经知道了在一致性哈希算法中的这行代码就是导致 bug 的原因:文章源自JAVA秀-https://www.javaxiu.com/19413.html
System.identityHashCode(invokers)
文章源自JAVA秀-https://www.javaxiu.com/19413.html
甚至我也知道了,这行代码导致 bug 的原因是 invokers 这个集合的地址变了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
这个集合里面,放的就是服务提供者列表。文章源自JAVA秀-https://www.javaxiu.com/19413.html
集合里面的服务者列表其实并没有变化,只是每次都用了一个新的 list 来装这些服务提供者。文章源自JAVA秀-https://www.javaxiu.com/19413.html
而为什么每次都用一个新的 list 来装,我也找到了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
问题就出在 TagRouter 中:文章源自JAVA秀-https://www.javaxiu.com/19413.html
org.apache.dubbo.rpc.cluster.router.tag.TagRouter#filterInvoker
文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
基本上到这里,也就明确原因了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
但是我前面说了,更高一级的是了解这个框架的前世今生。文章源自JAVA秀-https://www.javaxiu.com/19413.html
问题出在 TagRouter,那么这个 TagRouter 怎么来的呢?文章源自JAVA秀-https://www.javaxiu.com/19413.html
如果了解 Dubbo 2.7.x 版本新特性的朋友可能知道,标签路由是 Dubbo2.7 引入的新功能。文章源自JAVA秀-https://www.javaxiu.com/19413.html
巧就巧在我还真的清楚这个地方的来龙去脉。文章源自JAVA秀-https://www.javaxiu.com/19413.html
因为我的第一篇技术文章就是写的 Dubbo 2.7 新特性,当时进行了一个了解。文章源自JAVA秀-https://www.javaxiu.com/19413.html
没想到一年多以后,竟然还呼应上了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
而这个 bug,其实也是一行代码就能修复;文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
而我当时为什么没有去修复呢?文章源自JAVA秀-https://www.javaxiu.com/19413.html
因为最开始找到这个 bug 的时候,我想到的解决方案是写个工具类。文章源自JAVA秀-https://www.javaxiu.com/19413.html
思路也是只关心 List 里面的元素,而不关心 List 这个容器,但是实现方式比较复杂,改动点较多,还需要写一个工具类。文章源自JAVA秀-https://www.javaxiu.com/19413.html
当时就没动手,想着先提个 issue 放着,有时间了再弄。文章源自JAVA秀-https://www.javaxiu.com/19413.html
结果,没想到 issue 放上去的当天就有人回复并了一个我没有想到的解决方案:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
看到这个回复的时候,我才一下回过神来,原来一行代码就能代替我写的工具类了啊。文章源自JAVA秀-https://www.javaxiu.com/19413.html
而对于其中涉及到的知识点,我是知道的。文章源自JAVA秀-https://www.javaxiu.com/19413.html
我反思了一下自己为什么没有想到这个方案。文章源自JAVA秀-https://www.javaxiu.com/19413.html
其实就是对于已知道的知识点,掌握不够深刻导致的,没有达到融会贯通的地步。文章源自JAVA秀-https://www.javaxiu.com/19413.html
知其然,也知其所以然,可惜在需要使用的场景稍稍一变的情况下,就想不起来了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
知道知识点,但是该用的时候却记不起来,这种情况其实挺常见的,那怎么解决呢?文章源自JAVA秀-https://www.javaxiu.com/19413.html
于是我写下了这篇文章:文章源自JAVA秀-https://www.javaxiu.com/19413.html
够强!一行代码就修复了我提的Dubbo的Bug。文章源自JAVA秀-https://www.javaxiu.com/19413.html
这篇文章就是我的解决方案,记录下来嘛。文章源自JAVA秀-https://www.javaxiu.com/19413.html
就像高中的时候人手一本的错题本,做错的题,不会的题都抄下来嘛。没事的时候翻一翻,总有下次碰到的时候。再次碰到时,就是“一雪前耻”的机会。文章源自JAVA秀-https://www.javaxiu.com/19413.html
写过但没有发现的bug
我之前还写过一样的一篇文章:文章源自JAVA秀-https://www.javaxiu.com/19413.html
Dubbo 2.7.5在线程模型上的优化文章源自JAVA秀-https://www.javaxiu.com/19413.html
当时这个版本推出之后,我就赶紧去研究了一下对应部分的源码,然后写下这篇自称为全网第一篇解析 Dubbo 2.7.5 里程碑版本中的客户端线程模型优化的文章。文章源自JAVA秀-https://www.javaxiu.com/19413.html
但是前两天我看提交记录的时候,发现了这样的一个提交:文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
并找到了对应的 issue:文章源自JAVA秀-https://www.javaxiu.com/19413.html
https://github.com/apache/dubbo/issues/7054
文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
根据这个 issue,我去看了一下对应的源码,确实是存在他描述的问题。文章源自JAVA秀-https://www.javaxiu.com/19413.html
于是我就在想,我当时写文章的时候也是深入到源码里面了呀,为什么没有发现这样的问题呢?文章源自JAVA秀-https://www.javaxiu.com/19413.html
我想原因还是在于自己当时思考的深度不够,仅仅是搭建了一个非常简陋的 Demo,而且把心思聚焦到了前后版本差异对比上。文章源自JAVA秀-https://www.javaxiu.com/19413.html
只是摸到了一个大概的样子,于是被源码牵着走了,并没有跳出源码的包围,带着质疑的眼光去审视它。文章源自JAVA秀-https://www.javaxiu.com/19413.html
所以,对于这种比较深层次的、一环扣一环的问题,自己还是流于表面了一些。文章源自JAVA秀-https://www.javaxiu.com/19413.html
一旦被源码牵着走了,大概率的情况下就会无条件的相信源码。毫无质疑之心。文章源自JAVA秀-https://www.javaxiu.com/19413.html
怎么看源码
前面举了三个例子,一个是发现并解决了 bug,一个是仅发现未解决的 bug,一个是有 bug 但没有发现。文章源自JAVA秀-https://www.javaxiu.com/19413.html
前两个 bug 都有一个共性,在简单的 Demo 下就是必现的,只要跑到了对应的地方,就会出现和预期不符的情况,比较容易发现。文章源自JAVA秀-https://www.javaxiu.com/19413.html
最后一个 bug 隐藏的比较深入一点,也许你触发了,但是程序自愈了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
当有一天我能发现并解决这样的 bug 时,我就不会说这是运气了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
但是发现这些 bug 的前提是得动手搭建 Demo 呀。文章源自JAVA秀-https://www.javaxiu.com/19413.html
你不看源码,只是看网上的文章,是永远发现不了问题的,也是潜入不进去的。文章源自JAVA秀-https://www.javaxiu.com/19413.html
分享一下我看源码的方法吧。文章源自JAVA秀-https://www.javaxiu.com/19413.html
我们知道开源框架的设计和理念大多是非常优秀的,但是源码里面的细枝末节特别的多,一不小心就容易在源码里面迷失,直接就是一波劝退。文章源自JAVA秀-https://www.javaxiu.com/19413.html
所以,对于初读源码的同学,首先要做的就是把核心流程梳理出来,边梳理边画图,要多画图,别怕麻烦。文章源自JAVA秀-https://www.javaxiu.com/19413.html
对于几处关键的源码,一定要写上自己的备注。因为你知道的,当时也许你对这个地方为什么这样写门清,但是隔段时间再回来看,就摸不着头脑了。这个时候,备注就显得非常重要了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
对于看不明白的地方,打断点,疯狂的调试,反复的调试。文章源自JAVA秀-https://www.javaxiu.com/19413.html
等待主流程摸清楚之后,再去进入到源码的细节部分。文章源自JAVA秀-https://www.javaxiu.com/19413.html
举个简单的例子,比如你看 Dubbo 源码,先摸清楚它一次请求大概的调用链路之后,再去细致了解其中负载均衡的部分。文章源自JAVA秀-https://www.javaxiu.com/19413.html
然后,就是多复习,多巩固了。文章源自JAVA秀-https://www.javaxiu.com/19413.html
文章源自JAVA秀-https://www.javaxiu.com/19413.html
你发现没有,我说的这些其实你也知道,或者其他人也是这样说的。文章源自JAVA秀-https://www.javaxiu.com/19413.html
为什么你看的时候就老是看不进去呢?不得要领呢?文章源自JAVA秀-https://www.javaxiu.com/19413.html
是的,我开始也是这样的。但是,无它,唯反复练习尔。文章源自JAVA秀-https://www.javaxiu.com/19413.html
共勉之。文章源自JAVA秀-https://www.javaxiu.com/19413.html
<span style="margin:0;padding:0;max-width:100% !important;-webkit-box-sizing:border-box !important;word-wrap:break-word !important;color:rgb(255,0,0);overflow-wrap:break-word !important;box-sizing:border-box !important"--<end--文章源自JAVA秀-https://www.javaxiu.com/19413.html
扫描下方二维码添加好友,备注【交流】可私聊交流,也可进资源丰富学习群更文不易,点个“在看”支持一下?文章源自JAVA秀-https://www.javaxiu.com/19413.html
阅读原文文章源自JAVA秀-https://www.javaxiu.com/19413.html

评论