这是why技术的第 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 类也跑过去了。

但是毫不夸张的说,我看了一眼这个提交记录,就发现了这里势必是有问题的。

他仅仅是把 LFU 缓存策略集合到了 Dubbo 代码中,但是却没有给使用者提供使用的入口。

因为这里是基于 SPI 实现的,他没有在对应的配置文件中加入配置。

这个问题非常容易验证,我们可以看一下。

其源码的位置是:org.apache.dubbo.common.utils.LFUCache

源码里面告诉我这样配置一下就可以使用 LFU 的缓存策略:

但是,当我这样配置,发起调用之后,是这样的:

可以看到当前请求的缓存策略确实是 lfu。

但是会抛出一个错误:

No such extension org.apache.dubbo.cache.CacheFactory by name lfu

没有 lfu 这个策略。

这不是玩我吗?

再看一下具体的原因:

org.apache.dubbo.common.extension.ExtensionLoader#getExtensionClasses 处只获取到了 4 个缓存策略,并没有我们想要的 LFU。

所以,在这里抛出了异常:

为什么没有找到我们想要的 LFU 呢?

那就得看你熟不熟悉 SPI 了。

在 SPI 文件中,确实没有 LFU 的配置:

所以,这是个 Bug,而这个 Bug 的解决方案,就是在 SPI 文件里面加上一行 LFU 的配置即可。

经过上面的分析,其实你也发现了,这个并不是一个有什么技术含量的提交。

更多的是运气成分。

只是由于对于 Dubbo 框架有些许的了解,所以对于这个地方,我发现问题、定位问题、解决问题的速度非常的快。

这是运气带不给我的东西。

这需要日复一日的潜入到框架中去,去感受它的脉络,梳理它的结构,学习它的思想。

这是需要时间去沉淀和学习的东西。

注意,我说的是“潜入”,而非是流于表面的。

什么是流于表面的呢?

比如,如果你之前没有用过 Dubbo 框架,但你又想去了解,学习它。

于是你看到了我的这篇或者其他的和 Dubbo 相关的公众号文章,企图从这些文章中入手。

记住鲁迅先生的话:

亦或者是你在搜索框里面,输入 “Dubbo”,然后漫无目的的看了起来。

哪怕你买了一本 Dubbo 相关的书或者看了 Dubbo 相关的系列视频,进行系统的学习。

我觉得,只要没有自己亲手去做,都属于流于表面。

而自己动手的第一步,就是搭建 Demo,从 Demo 入手。

到后面高阶一点的就是你了解到了这个框架的前世今生,能在几个大版本之间进行横向对比,知道为什么升级、怎么升级、升级之后是怎么样的。

再之后,能细致到某一个大的模块的演变是怎样的,历史上出现过哪些 Bug,是怎么去修复的。在那个版本之后进行了修复,是稳定的。

再举个例子吧。

另外一个 bug

回到最开始的地方,我为什么会在写 LFU 的时候联想到 Dubbo 呢?

因为在 2.7.7 这个版本发布的时候,我就关注到了它。

而当时关注到它的原因并不是 LFU ,而是新增了一种负载均衡策略:

于是我把之前的文章进行了汇总,写下了这篇文章:

吐血输出:2万字长文带你细细盘点五种负载均衡策略。

而其中一致性哈希负载均衡策略,我在实践的时候也发现了一个 bug。

其实这个 bug 也是一个必现的 bug,为什么没有被爆出来的原因,我想是因为当前的版本使用的人不多,而使用一致性哈希负载均衡策略的就更少了,甚至没有。

这个 bug 具体是这样的:

https://github.com/apache/dubbo/issues/5429

我已经知道了在一致性哈希算法中的这行代码就是导致 bug 的原因:

System.identityHashCode(invokers)

甚至我也知道了,这行代码导致 bug 的原因是 invokers 这个集合的地址变了。

这个集合里面,放的就是服务提供者列表。

集合里面的服务者列表其实并没有变化,只是每次都用了一个新的 list 来装这些服务提供者。

而为什么每次都用一个新的 list 来装,我也找到了:

问题就出在 TagRouter 中:

org.apache.dubbo.rpc.cluster.router.tag.TagRouter#filterInvoker

基本上到这里,也就明确原因了。

但是我前面说了,更高一级的是了解这个框架的前世今生。

问题出在 TagRouter,那么这个 TagRouter 怎么来的呢?

如果了解 Dubbo 2.7.x 版本新特性的朋友可能知道,标签路由是 Dubbo2.7 引入的新功能。

巧就巧在我还真的清楚这个地方的来龙去脉。

因为我的第一篇技术文章就是写的 Dubbo 2.7 新特性,当时进行了一个了解。

没想到一年多以后,竟然还呼应上了。

而这个 bug,其实也是一行代码就能修复;

而我当时为什么没有去修复呢?

因为最开始找到这个 bug 的时候,我想到的解决方案是写个工具类。

思路也是只关心 List 里面的元素,而不关心 List 这个容器,但是实现方式比较复杂,改动点较多,还需要写一个工具类。

当时就没动手,想着先提个 issue 放着,有时间了再弄。

结果,没想到 issue 放上去的当天就有人回复并了一个我没有想到的解决方案:

看到这个回复的时候,我才一下回过神来,原来一行代码就能代替我写的工具类了啊。

而对于其中涉及到的知识点,我是知道的。

我反思了一下自己为什么没有想到这个方案。

其实就是对于已知道的知识点,掌握不够深刻导致的,没有达到融会贯通的地步。

知其然,也知其所以然,可惜在需要使用的场景稍稍一变的情况下,就想不起来了。

知道知识点,但是该用的时候却记不起来,这种情况其实挺常见的,那怎么解决呢?

于是我写下了这篇文章:

够强!一行代码就修复了我提的Dubbo的Bug。

这篇文章就是我的解决方案,记录下来嘛。

就像高中的时候人手一本的错题本,做错的题,不会的题都抄下来嘛。没事的时候翻一翻,总有下次碰到的时候。再次碰到时,就是“一雪前耻”的机会。

写过但没有发现的 bug

我之前还写过一样的一篇文章:

Dubbo 2.7.5在线程模型上的优化

当时这个版本推出之后,我就赶紧去研究了一下对应部分的源码,然后写下这篇自称为全网第一篇解析 Dubbo 2.7.5 里程碑版本中的改进点之一:客户端线程模型优化的文章。

但是前两天我看提交记录的时候,发现了这样的一个提交:

并找到了对应的 issue:

https://github.com/apache/dubbo/issues/7054

根据这个 issue,我去看了一下对应的源码,确实是存在他描述的问题。

于是我就在想,我当时写文章的时候也是深入到源码里面了呀,为什么没有发现这样的问题呢?

我想原因还是在于自己当时思考的深度不够,仅仅是搭建了一个非常简陋的 Demo,而且把心思聚焦到了前后版本差异对比上。

只是摸到了一个大概的样子,被源码牵着走了,并没有跳出源码的包围,带着质疑的眼光去审视它。

所以,对于这种比较深层次的、一环扣一环的问题,自己还是流于表面了一些。

怎么看源码

前面举了三个例子,一个是发现并解决了 bug,一个是仅发现未解决的 bug,一个是有 bug 但没有发现。

前两个 bug 都有一个共性,在简单的 Demo 下就是必现的,只要跑到了对应的地方,就会出现和预期不符的情况,比较容易发现。

最后一个 bug 隐藏的比较深入一点,也许你触发了,但是程序自愈了。

当有一天我能发现并解决这样的 bug 时,我就不会说这是运气了。

但是发现这些 bug 的前提是得动手搭建 Demo 呀。

你不看源码,只是看网上的文章,是永远发现不了问题的,也是潜入不进去的。

分享一下我看源码的方法吧。

我们知道开源框架的设计和理念大多是非常优秀的,但是源码里面的细枝末节特别的多,一不小心就容易在源码里面迷失,直接就是一波劝退。

所以,对于初读源码的同学,首先要做的就是把核心流程梳理出来,边梳理边画图,要多画图,别怕麻烦。

对于几处关键的源码,一定要写上自己的备注。因为你知道的,当时也许你对这个地方为什么这样写门清,但是隔段时间再回来看,就摸不着头脑了。这个时候,备注就显的非常重要了。

对于看不明白的地方,打断点,疯狂的调试,反复的调试。

等待主流程摸清楚之后,再去进入到源码的细节部分。

举个简单的例子,比如你看 Dubbo 源码,先摸清楚它一次请求大概的调用链路之后,再去细致了解其中负载均衡的部分。

然后,就是多复习,多巩固了。

你发现没有,我说的这些其实你也知道,或者其他人也是这样说的。

为什么你看的时候就老是看不进去呢?不得要领呢?

是的,我开始也是这样的。但是,无它,唯反复练习尔。

共勉之。

最后说一句

才疏学浅,难免会有纰漏,如果你发现了错误的地方,可以在后台提出来,我对其加以修改。

感谢您的阅读,我坚持原创,十分欢迎并感谢您的关注。

我给Apache顶级项目贡献了点源码。的更多相关文章

  1. Dubbo下一站:Apache顶级项目

    导读: 近日,在Apache Dubbo开发者沙龙杭州站的活动中,阿里巴巴中间件技术专家曹胜利(展图)向开发者们分享了Dubbo2.7版本的规划. 本文将为你探秘 Dubbo 2.7背后的思考和实现方 ...

  2. 盘点 35 个 Apache 顶级项目,我拜服了…

    Apache 软件基金会 Apache 软件基金会,全称:Apache Software Foundation,简称:ASF,成立于 1999 年 7 月,是目前世界上最大的最受欢迎的开源软件基金会, ...

  3. 我给 Apache 顶级项目提了个 Bug

    这篇文章记录了给 Apache 顶级项目 - 分库分表中间件 ShardingSphere 提交 Bug 的历程. 说实话,这是一次比较曲折的 Bug 跟踪之旅.10月28日,我们在 GitHub 上 ...

  4. Apache 顶级项目 Apache Pulsar 成长回顾

    关于 Apache Pulsar Apache Pulsar 是 Apache 软件基金会顶级项目,是下一代云原生分布式消息流平台,集消息.存储.轻量化函数式计算为一体,采用计算与存储分离架构设计,支 ...

  5. 特性预览:Apache 顶级项目 Apache Pulsar 2.6.1 版本

    在正式分享 2.6.1 版本更新细节之前,冉小龙首先为我们分享了两个相关 PIP 的内容. 一个是 PIP-47 中关于「基于时间来进行版本更新」的计划.该 PIP 提出后,从 2.5.0 版本到目前 ...

  6. Apache顶级项目 Calcite使用介绍

    什么是Calcite Apache Calcite是一个动态数据管理框架,它具备很多典型数据库管理系统的功能,比如SQL解析.SQL校验.SQL查询优化.SQL生成以及数据连接查询等,但是又省略了一些 ...

  7. 官宣!ASF官方正式宣布Apache Hudi成为顶级项目

    马萨诸塞州韦克菲尔德(Wakefield,MA)- 2020年6月 - Apache软件基金会(ASF).350多个开源项目和全职开发人员.管理人员和孵化器宣布:Apache Hudi正式成为Apac ...

  8. 官宣!DolphinScheduler 毕业成为 Apache 软件基金会顶级项目

    全球最大的开源软件基金会 Apache 软件基金会(以下简称 Apache)于北京时间 2021年4月9日在官方渠道宣布Apache DolphinScheduler 毕业成为Apache顶级项目.这 ...

  9. 如何从零开始参与 Apache 顶级开源项目?| 墙裂推荐

    ​ 写在开头 从 2021 开始,有一个很有意思的说法经常在各大技术媒体或开源论坛中出现,「开源正在吞噬一切」.不论是否言过其实,从一个行业从业者的切身感知来看,开源确实从少数极客的小众文化成为主流的 ...

随机推荐

  1. Proud Merchants HDU - 3466 01背包&&贪心

    最近,我去了一个古老的国家.在很长一段时间里,它是世界上最富有.最强大的王国.结果,这个国家的人民仍然非常自豪,即使他们的国家不再那么富有.商人是最典型的,他们每个人只卖一件商品,价格是Pi,但是如果 ...

  2. Java_web-response的outputStream和Write输出数据的问题

    解决方法: 把方法换成这个也可以: 因为浏览器也是一个html解析工具,所以认识html文本 下面这个直接write(1),那么浏览器上就会显示L 这个样子在浏览器上看到的就是1: 字节流输出: 这个 ...

  3. Gym 2009-2010 ACM ICPC Southwestern European Regional Programming Contest (SWERC 2009) A. Trick or Treat (三分)

    题意:在二维坐标轴上给你一堆点,在x轴上找一个点,使得该点到其他点的最大距离最小. 题解:随便找几个点画个图,不难发现,答案具有凹凸性,有极小值,所以我们直接三分来找即可. 代码: int n; lo ...

  4. 使用 Nginx 在 Linux 上托管 ASP.NET Core

    server { listen 80; server_name example.com *.example.com; location / { proxy_pass http://localhost: ...

  5. OpenStack Train版-6.安装nova计算服务(计算节点)

    安装nova计算服务(computel01计算节点 192.168.0.20)安装软件包 yum install centos-release-openstack-train -y yum insta ...

  6. 桶排序 && leetcode 41

    桶排序 对于0-1000 ,用1001个桶  简单版 或者用10个桶0-9,先按各位装桶,然后依(桶)次放回,然后再按十位放桶,放回,然后百位. 也就是基数排序 https://www.cnblogs ...

  7. JVM实战篇

    1.1 JVM参数 1.1.1 标准参数 -version -help -server -cp 1.1.2 -X参数 非标准参数,也就是在JDK各个版本中可能会变动 -Xint 解释执行 -Xcomp ...

  8. BellmanFord为什么只需松弛V-1次

    首先s不用松弛,V-=1 然后对于其他的顶点..每次都至少能完全松弛一个顶点.. 为什么呢..因为初始d[s]=0,所以和s相邻接的边都将被松弛完全..无论松弛的顺序 那么对于这个图,无论松弛的顺序都 ...

  9. Chrome & targetText

    Chrome & targetText target text http://www.ruanyifeng.com/blog/2019/03/weekly-issue-47.html http ...

  10. anatomy app

    anatomy app https://appolicious.com/the-best-iphone-apps-for-anatomy-students/ ios anatomy app Compl ...