在线伪原创源码(这是why技术的第91篇原创文章这篇文章其实并没有什么技术性)
优采云 发布时间: 2022-02-08 04:13在线伪原创源码(这是why技术的第91篇原创文章这篇文章其实并没有什么技术性)
这是为什么技术的第 91 部分原创文章
这个文章并不是真正的技术分享。在我看来,更多的是记录和思考。
我想和大家分享一些我反馈给我的关于源代码和我之前写的部分文章。
一行源代码
我很久没有打开我的 Outlook 邮箱了。
前两天打开的时候发现我提交给Dubbo的pr已经被合并到master了:
这是我的pr提交第一次被合并。
这个pr是为了修复LFU缓存策略即使在Dubbo中配置也不起作用的BUG。
所以我可以算是为开源项目贡献过源代码的人。
你在问我贡献了多少代码?
一条线,是的,只有一条线!
而且,说起来,这个提交确实没有什么技术含量。因为这是一个必备的bug,只是很少有人使用这个功能。
要知道,当一个 bug 可以稳定地重现时,它就不再是一个真正的 bug。
但我想谈谈这次提交背后的一些事情。
发现并解决
从宿命论的角度来看,当我写出下面文章的第一个字的时候,这个bug就注定要被发现和修复了:
其实LRU也是一样的东西。
而这个文章是我在2020年12月下旬打的第一个字,是我2020年最后一个技术原创文章。
写LRU的时候就知道LFU肯定也需要专门写一篇文章。
所以2021年的第一个技术原创文章,我选择了LFU。
产生了这个 文章:
嘿,这是一个令人头疼的 LFU。
写这篇文章的时候,想到了之前看Dubbo的版本,好像提到了LFU。
于是我转向2.7.7版本的发布内容:
果然支持了LFU缓存策略,于是我把提交的代码记录拉了出来:
虽然他的实现逻辑没有问题,但是Test类也跑了过来。
但是毫不夸张的说,我看了下这个commit记录,发现这里肯定有问题。
他只是将 LFU 缓存策略集成到 Dubbo 代码中,并没有为用户提供使用的入口。
因为是基于SPI实现的,所以他没有在对应的配置文件中添加配置。
这个问题很容易验证,我们可以看看。
其源码位置为:mon.utils.LFUCache
源代码告诉我,我可以通过如下配置来使用 LFU 缓存策略:
但是,当我像这样配置它并启动呼叫时,它看起来像这样:
可以看到当前请求的缓存策略确实是lfu。
但是会抛出一个错误:
没有这样的扩展名 org.apache.dubbo.cache.CacheFactory 名称为 lfu
没有 lfu 策略。
这不是在玩我吗?
我们来看看具体原因:
在 mon.extension.ExtensionLoader#getExtensionClasses 处,只获得了 4 个缓存策略,没有我们想要的 LFU。
所以,这里抛出异常:
为什么我们没有找到我们想要的 LFU?
这取决于你是否熟悉 SPI。
在SPI文件中,确实没有LFU的配置:
所以,这是一个bug,解决这个bug的方法是在SPI文件中添加一行LFU配置。
经过上面的分析,其实你也发现这不是一篇有什么技术含量的投稿。
更多的是运气。
只是因为对 Dubbo 框架有一点了解,对于这个地方,我发现了问题,定位问题,很快解决了问题。
这是运气不会带给我的东西。
这需要日复一日地深入框架,感受它的脉络,理清它的结构,并了解它的思想。
这是需要时间来解决和学习的。
请注意,我说的是“潜入”,而不是肤浅的。
什么是肤浅的?
比如你之前没有使用过 Dubbo 框架,但是你想了解它,就去学习它。
所以你看到了我的文章或者其他 Dubbo 相关的公众号文章,试图从这些文章入手。
记住鲁迅先生的话:
或者你可以在搜索框中输入“Dubbo”,漫无目的地看。
即使你买了一本 Dubbo 相关的书,或者观看了一系列 Dubbo 相关的视频,也要系统地学习。
我想,只要你不自己做,那都是肤浅的。
自己做的第一步是构建一个 Demo,从一个 Demo 开始。
下一个高级点是你了解了这个框架的前世今生,可以横向比较几个主要版本,知道为什么要升级,怎么升级,升级后会发生什么。
之后,您可以详细了解一个大模块的演变过程,历史上出现过哪些 bug,以及如何修复它们。在该版本之后修复并且稳定。
让我再举一个例子。
另一个错误
回到开头,为什么我写 LFU 的时候会想到 Dubbo?
因为在2.7.7版本发布的时候,我就关注了。
当时关注它的原因并不是 LFU,而是一种新的负载均衡策略:
于是我总结了之前的文章,写了这个文章:
吐血输出:2万字长文带你详细盘点五种负载均衡策略。
其中,一致性哈希负载均衡策略,我在实践中也发现了一个bug。
其实这个bug也是必备的bug。之所以没有被曝光,我想是因为现在的版本用的人不多,而一致的hash负载均衡策略用的人更少甚至没有。
该错误如下:
我已经知道一致性哈希算法中的这行代码是导致该错误的原因:
System.identityHashCode(调用者)
连我都知道这行代码导致这个bug的原因是invokers集合的地址变了。
此集合收录服务提供者列表。
集合中的服务提供者列表没有改变,但是每次都使用一个新的列表来安装这些服务提供者。
以及为什么每次我使用新列表安装时,我也发现:
问题出在 TagRouter 中:
org.apache.dubbo.rpc.cluster.router.tag.TagRouter#filterInvoker
基本上,这就是原因。
但正如我之前所说,更高的层次是了解这个框架的前世今生。
问题出在TagRouter上,那么这个TagRouter是怎么来的呢?
如果你知道 Dubbo2.7.x 版本的新特性,你可能知道标签路由是 Dubbo2.7 引入的新特性。
巧合的是,我真的很了解这个地方的来龙去脉。
因为我的第一个技术文章是Dubbo 2.7的新特性,当时我就有了一个了解。
没想到,时隔一年多,竟然还回响了。
而且这个bug实际上可以用一行代码来修复;
那我为什么不修呢?
因为第一次发现这个bug的时候,想到的解决办法就是写一个工具类。
思路是只关心List里面的元素,不关心List容器,但是实现方式比较复杂,改动很多,还需要写一个工具类。
我当时没做,想着先提个问题,等有时间再做。
结果,我没想到有人在问题发布的那天回复了我没想到的解决方案:
看到这个回复,我才回过神来。原来,一行代码就可以代替我写的工具类。
而对于涉及的知识点,我是知道的。
我反思了为什么我没有想到这个计划。
其实是对已知的知识点掌握不足造成的,还没有达到掌握的程度。
我知道,我也知道为什么,可惜当需要使用的场景发生细微的变化时,我想不起来了。
我知道知识点,但我不记得什么时候应该使用它们。这种情况其实很常见。如何解决?
所以我写了这个文章:
够强!一行代码修复了我提到的 Dubbo bug。
这个 文章 是我的解决方案,记录一下。
就像你在高中的时候,每个人都有一本错误的问题书,他们抄下了错误的问题和他们做不到的问题。没事的时候把它翻过来,下次遇到它总会有的。当我们再次遇到它时,正是一个“雪中羞耻”的机会。
已写入但未找到的错误
我在 文章 之前写过相同的:
Dubbo 2.7.5 线程模型优化
这个版本上线后,我赶紧去研究对应部分的源码,然后写了这篇自称全网的第一篇文章,分析Dubbo2.7.5里程碑的改进版本一:文章 针对客户端线程模型进行了优化。
但是前两天查看commit记录的时候,发现了这样一个commit:
并找到了相应的问题:
根据这个问题,我看了一下对应的源码,确实有他描述的问题。
所以我在想,我写文章的时候,也深入到了源码里面,怎么没有发现这样的问题呢?
我想原因是我当时想的不够深入,只是搭建了一个非常简单的Demo,把心思放在了前后版本差异的对比上。
刚刚有了一个大概的想法,就被源代码给带走了。我没有跳出源码,用怀疑的眼光看着。
所以,对于这个比较深层次的问题,我还是很肤浅的。
如何阅读源代码
上面给出了三个例子,一个是发现并解决错误,一个是只找到未解决的错误,一个是有错误但没有找到。
前两个错误有一个共同点,它们必须出现在一个简单的演示中。只要去对应的地方,就会出现与预期不一致的情况,比较容易发现。
最后一个错误隐藏得更深一些,也许你触发了它,但程序会自行修复。
当有一天我能找到并修复这样一个错误时,我不会称之为运气。
但是找到这些bug的前提是搭建一个Demo。
不看源码,只看网上的文章,绝对找不到问题,也偷不到。