我給Apache頂級項目貢獻(xiàn)了點源碼.
這是why哥的第 91 篇原創(chuàng)文章

這篇文章其實并沒有什么技術(shù)性的分享,從我的角度而言,更多是記錄和思考。
把我對于源碼和之前寫的部分文章反哺給我的一些東西,帶來的一點點思考分享給大家。
一行源碼
我很長時間沒打開我的 Outlook 郵箱了。
前兩天打開的時候發(fā)現(xiàn)我之前給 Dubbo 提交的 pr 居然已經(jīng)被合并到 master 了:

這是第一次,我提交的 pr 被合并了。
這個 pr 是修復(fù) LFU 緩存策略在 Dubbo 中即使配置了,也不起作用的 bug。
于是我也算是為開源項目貢獻(xiàn)過源碼的人了。
什么你問我貢獻(xiàn)了多少代碼?
一行,是的,就一行!

而且,說起來,這次提交真的是沒有什么技術(shù)含量的事情。因為這是一個必現(xiàn)的 bug,只是很少有人用到這個功能而已。
你知道的,當(dāng)一個 bug 能穩(wěn)定復(fù)現(xiàn)的時候,其實它已經(jīng)就不算是一個 bug 了。
但是我想聊聊這次提交背后的一些東西。

發(fā)現(xiàn)與解決
從宿命論的角度來說,當(dāng)我寫下面這篇文章的第一個字的時候,這個 bug 就注定是等著我去發(fā)現(xiàn)并修復(fù)了:
而這篇文章我敲下第一個字的時間是 2020 年 12 月的下旬,這是我 2020 年的最后一篇技術(shù)原創(chuàng)文章。
當(dāng)我寫 LRU 的時候,我就知道 LFU 肯定也是需要專門寫一篇的。
于是 2021 年的第一篇技術(shù)原創(chuàng)文章,我就選題了 LFU。
產(chǎn)生了這篇文章:
寫這篇文章的時候,我想起之前看 Dubbo 的版本,好像是提到了一下 LFU。
于是我翻到了 2.7.7 版本的發(fā)布內(nèi)容:

果然是支持了 LFU 緩存策略,于是翻出了提交的代碼記錄:

雖然他的實現(xiàn)邏輯沒有問題,Test 類也跑過去了。
但是毫不夸張的說,我看了一眼這個提交記錄,通過眼神編譯,就發(fā)現(xiàn)了這里勢必是有問題的。

他僅僅是把 LFU 緩存策略集合到了 Dubbo 代碼中,但是卻未提供使用的入口。
因為這里是基于 SPI 實現(xiàn)的,他沒有在對應(yīng)的配置文件中加入配置。
這個問題非常容易驗證,我們可以看一下。
其源碼的位置是:org.apache.dubbo.common.utils.LFUCache
源碼里面告訴我這樣配置一下就可以使用 LFU 的緩存策略:

但是,當(dāng)我這樣配置,發(fā)起調(diào)用之后,是這樣的:

可以看到當(dāng)前請求的緩存策略確實是 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 的配置即可。

經(jīng)過上面的分析,其實你也發(fā)現(xiàn)了,這個并不是一個有什么技術(shù)含量的提交。
更多的是運氣成分。
只是由于對于 Dubbo 框架有些許的了解,所以對于這個地方,我發(fā)現(xiàn)問題、定位問題、解決問題的速度非常的快。
這是運氣給不了我的東西。
這需要日復(fù)一日的潛入到框架中去,去感受它的脈絡(luò),梳理它的結(jié)構(gòu),學(xué)習(xí)它的思想。
這是需要時間去沉淀和學(xué)習(xí)的東西。
注意,我說的是“潛入”,而非是流于表面的。
什么是流于表面的呢?
比如,如果你之前沒有用過 Dubbo 框架,但你又想去了解,學(xué)習(xí)它。
于是你看到了我的這篇或者其他的和 Dubbo 相關(guān)的文章,企圖從這些文章中入手。
記住魯迅先生的話:

這里只適合查漏補缺,不適合系統(tǒng)的學(xué)習(xí)。
亦或者是你在搜索框里面,輸入 “Dubbo”,然后漫無目的的看了起來。
哪怕你買了一本 Dubbo 相關(guān)的書或者看了 Dubbo 相關(guān)的系列視頻,進(jìn)行系統(tǒng)的學(xué)習(xí)。
我覺得,只要沒有自己親手去做,都屬于流于表面。
而自己動手的第一步,就是搭建 Demo,從 Demo 入手。
到后面高階一點的就是你了解到了這個框架的前世今生,能在幾個大版本之間進(jìn)行橫向?qū)Ρ龋罏槭裁瓷墶⒃趺瓷墶⑸壷笫窃趺礃拥摹?/p>
再之后,能細(xì)致到某一個大的模塊的演變是怎樣的,歷史上出現(xiàn)過哪些 Bug,是怎么去修復(fù)的,在哪個版本之后修復(fù)了,是穩(wěn)定的。
再舉個例子吧。
另外一個bug
回到最開始的地方,我為什么會在寫 LFU 的時候聯(lián)想到 Dubbo 呢?
因為在 2.7.7 這個版本發(fā)布的時候,我就關(guān)注到了它。
而當(dāng)時關(guān)注到它的原因并不是 LFU ,而是新增了一種負(fù)載均衡策略:

于是我把之前的文章進(jìn)行了匯總,寫下了這篇文章:
吐血輸出:2萬字長文帶你細(xì)細(xì)盤點五種負(fù)載均衡策略。
而其中一致性哈希負(fù)載均衡策略,我在實踐的時候也發(fā)現(xiàn)了一個 bug。
其實這個 bug 也是一個必現(xiàn)的 bug,為什么沒有被爆出來的原因,我想是因為當(dāng)前的版本使用的人不多,而使用一致性哈希負(fù)載均衡策略的就更少了,甚至沒有。
這個 bug 具體是這樣的:
https://github.com/apache/dubbo/issues/5429

我已經(jīng)知道了在一致性哈希算法中的這行代碼就是導(dǎo)致 bug 的原因:
System.identityHashCode(invokers)
甚至我也知道了,這行代碼導(dǎo)致 bug 的原因是 invokers 這個集合的地址變了。
這個集合里面,放的就是服務(wù)提供者列表。
集合里面的服務(wù)者列表其實并沒有變化,只是每次都用了一個新的 list 來裝這些服務(wù)提供者。
而為什么每次都用一個新的 list 來裝,我也找到了。
問題就出在 TagRouter 中:
org.apache.dubbo.rpc.cluster.router.tag.TagRouter#filterInvoker

基本上到這里,也就明確原因了。
但是我前面說了,更高一級的是了解這個框架的前世今生。
問題出在 TagRouter,那么這個 TagRouter 怎么來的呢?
如果了解 Dubbo 2.7.x 版本新特性的朋友可能知道,標(biāo)簽路由是 Dubbo2.7 引入的新功能。

巧就巧在我還真的清楚這個地方的來龍去脈。
因為我的第一篇技術(shù)文章就是寫的 Dubbo 2.7 新特性,當(dāng)時進(jìn)行了一個了解。
沒想到一年多以后,竟然還呼應(yīng)上了。
而這個 bug,其實也是一行代碼就能修復(fù);

而我當(dāng)時為什么沒有去修復(fù)呢?
因為最開始找到這個 bug 的時候,我想到的解決方案是寫個工具類。
思路也是只關(guān)心 List 里面的元素,而不關(guān)心 List 這個容器,但是實現(xiàn)方式比較復(fù)雜,改動點較多,還需要寫一個工具類。
當(dāng)時就沒動手,想著先提個 issue 放著,有時間了再弄。
結(jié)果,沒想到 issue 放上去的當(dāng)天就有人回復(fù)并了一個我沒有想到的解決方案:

看到這個回復(fù)的時候,我才一下回過神來,原來一行代碼就能代替我寫的工具類了啊。
而對于其中涉及到的知識點,我是知道的。
我反思了一下自己為什么沒有想到這個方案。
其實就是對于已知道的知識點,掌握不夠深刻導(dǎo)致的,沒有達(dá)到融會貫通的地步。
知其然,也知其所以然,可惜在需要使用的場景稍稍一變的情況下,就想不起來了。
知道知識點,但是該用的時候卻記不起來,這種情況其實挺常見的,那怎么解決呢?
于是我寫下了這篇文章:
夠強(qiáng)!一行代碼就修復(fù)了我提的Dubbo的Bug。
這篇文章就是我的解決方案,記錄下來嘛。
就像高中的時候人手一本的錯題本,做錯的題,不會的題都抄下來嘛。沒事的時候翻一翻,總有下次碰到的時候。再次碰到時,就是“一雪前恥”的機(jī)會。
寫過但沒有發(fā)現(xiàn)的bug
?我之前還寫過一樣的一篇文章:
當(dāng)時這個版本推出之后,我就趕緊去研究了一下對應(yīng)部分的源碼,然后寫下這篇自稱為全網(wǎng)第一篇解析 Dubbo 2.7.5 里程碑版本中的客戶端線程模型優(yōu)化的文章。
但是前兩天我看提交記錄的時候,發(fā)現(xiàn)了這樣的一個提交:

并找到了對應(yīng)的 issue:
https://github.com/apache/dubbo/issues/7054

根據(jù)這個 issue,我去看了一下對應(yīng)的源碼,確實是存在他描述的問題。
于是我就在想,我當(dāng)時寫文章的時候也是深入到源碼里面了呀,為什么沒有發(fā)現(xiàn)這樣的問題呢?
我想原因還是在于自己當(dāng)時思考的深度不夠,僅僅是搭建了一個非常簡陋的 Demo,而且把心思聚焦到了前后版本差異對比上。
只是摸到了一個大概的樣子,于是被源碼牽著走了,并沒有跳出源碼的包圍,帶著質(zhì)疑的眼光去審視它。
所以,對于這種比較深層次的、一環(huán)扣一環(huán)的問題,自己還是流于表面了一些。
一旦被源碼牽著走了,大概率的情況下就會無條件的相信源碼。毫無質(zhì)疑之心。
怎么看源碼
前面舉了三個例子,一個是發(fā)現(xiàn)并解決了 bug,一個是僅發(fā)現(xiàn)未解決的 bug,一個是有 bug 但沒有發(fā)現(xiàn)。
前兩個 bug 都有一個共性,在簡單的 Demo 下就是必現(xiàn)的,只要跑到了對應(yīng)的地方,就會出現(xiàn)和預(yù)期不符的情況,比較容易發(fā)現(xiàn)。
最后一個 bug 隱藏的比較深入一點,也許你觸發(fā)了,但是程序自愈了。
當(dāng)有一天我能發(fā)現(xiàn)并解決這樣的 bug 時,我就不會說這是運氣了。
但是發(fā)現(xiàn)這些 bug 的前提是得動手搭建 Demo 呀。
你不看源碼,只是看網(wǎng)上的文章,是永遠(yuǎn)發(fā)現(xiàn)不了問題的,也是潛入不進(jìn)去的。
分享一下我看源碼的方法吧。
我們知道開源框架的設(shè)計和理念大多是非常優(yōu)秀的,但是源碼里面的細(xì)枝末節(jié)特別的多,一不小心就容易在源碼里面迷失,直接就是一波勸退。
所以,對于初讀源碼的同學(xué),首先要做的就是把核心流程梳理出來,邊梳理邊畫圖,要多畫圖,別怕麻煩。
對于幾處關(guān)鍵的源碼,一定要寫上自己的備注。因為你知道的,當(dāng)時也許你對這個地方為什么這樣寫門清,但是隔段時間再回來看,就摸不著頭腦了。這個時候,備注就顯得非常重要了。
對于看不明白的地方,打斷點,瘋狂的調(diào)試,反復(fù)的調(diào)試。
等待主流程摸清楚之后,再去進(jìn)入到源碼的細(xì)節(jié)部分。
舉個簡單的例子,比如你看 Dubbo 源碼,先摸清楚它一次請求大概的調(diào)用鏈路之后,再去細(xì)致了解其中負(fù)載均衡的部分。
然后,就是多復(fù)習(xí),多鞏固了。

你發(fā)現(xiàn)沒有,我說的這些其實你也知道,或者其他人也是這樣說的。
為什么你看的時候就老是看不進(jìn)去呢?不得要領(lǐng)呢?
是的,我開始也是這樣的。但是,無它,唯反復(fù)練習(xí)爾。
共勉之。
荒腔走板

周末的時候拿著投影儀去新家那邊試了一下效果,當(dāng)窗簾一拉,幕布放下,電影一放,酒杯相碰的那一下。
啊,舒服了,是裝修之前想象中的家庭影院的效果。
本來之前說的在新家看的第一部電影得是紅紅火火的那種,但是沒想到誤打誤撞放了一個動作片。
你別說,我們一起窩在沙發(fā)上,看完之后,一致認(rèn)為還挺好看的。
由于我們還沒搬家,空間顯得也比較凌亂,投影儀也是放在餐桌上,而為了一個好的投影角度,移動了餐桌。
導(dǎo)致完全擋住了去往衛(wèi)生間的路,于是看電影的間隙,我想去衛(wèi)生間,是從桌子下面鉆過去的。
發(fā)現(xiàn)這問題的時候,我說:到時候這邊的墻上做一個擱物板,就可以放其他東西,也可以找到更好的角度放下這個投影儀了。
她說:對呀,這些問題其實在我們沒有住進(jìn)來之前是很難想到的,只有搬進(jìn)來之后,慢慢的折騰。
她說這句話之后,我就覺得兩個人在一起,沒有什么是一蹴而就,都是在慢慢磨合中悄無聲息的打造出來的。
也許我都沒有注意到,而打造出來的東西,它就叫做:
生活。
另外,我還想隨口問一句:
有人知道靠譜的除甲醛的騷操作嗎?別說通風(fēng),我一直在通。
最后,昨天氣氛到位了,發(fā)了個朋友圈,于是很多人在朋友圈問我投影儀是怎么弄的。
其實我之前說過的:別問,問就是一個電動幕布而已,不用的時候可以收上去。
而且我發(fā)現(xiàn)收上去之后,直接投影到窗簾上,還挺有氣氛的,簡直是氛圍組擔(dān)當(dāng)。
大概就是這樣的:
最后說一句(求關(guān)注)
好了,看到了這里安排個“一鍵三連”(轉(zhuǎn)發(fā)、在看、點贊)吧,周更很累的,需要一點正反饋。

才疏學(xué)淺,難免會有紕漏,如果你發(fā)現(xiàn)了錯誤的地方,可以在后臺提出來,我對其加以修改。
感謝您的閱讀,我堅持原創(chuàng),十分歡迎并感謝您的關(guān)注。

最后,大家覺得文章還行,可以給我的號標(biāo)個星。如果不標(biāo)星,按照微信的推送機(jī)制,后續(xù)有可能會看不到我的文章。
之前把我標(biāo)星了的讀者,你也可以看一下,遷移之后應(yīng)該神不知鬼不覺的被官方取消掉了,也需要重新進(jìn)行標(biāo)星。

你的星標(biāo),對我非常重要。
推薦???:我酸了,來看看那些955的公司。
推薦???:我錯了,打我可以,別打臉。
推薦???:面試官叫我設(shè)計一個排行榜。
推薦???:我一般在B站看這些破玩意...
推薦???:布隆,牛逼!布谷鳥,牛逼!
我是 why,一個主要寫代碼,經(jīng)常寫文章,偶爾拍視頻的程序猿。
轉(zhuǎn)發(fā)、點贊、在看、一鍵三連。

