技巧二、多猜,多搜索,可以在底層庫(標(biāo)準(zhǔn)庫、網(wǎng)絡(luò)框架等)打條件斷點(diǎn)過篩選出關(guān)鍵流程 。
這句話其實(shí)是高效 debug 的關(guān)鍵。初看源碼時「猜」是很重要且很有效的手段,結(jié)合 IDE 的搜索功能,能夠幫我們快速定位關(guān)鍵代碼。
為什么底層庫適合打斷點(diǎn)呢?因?yàn)槌隹创箜?xiàng)目的代碼很難搞清楚其中的細(xì)節(jié),加上各種異步、多線程的操作,很容易把代碼「跟丟」。如果把斷點(diǎn)打在底層庫的接口/方法上,就可以根據(jù)調(diào)用棧分析調(diào)用過程。
當(dāng)然,底層庫被調(diào)用的次數(shù)比較多,可能出現(xiàn)很多無關(guān)的調(diào)用,所以要結(jié)合條件斷點(diǎn)來過濾掉無關(guān)的調(diào)用。
還是用 Pulsar 舉例,我現(xiàn)在想探究 producer 發(fā)送消息的流程,那么 producer 和 broker 之間的網(wǎng)絡(luò)通信過程就是一個重要的切入點(diǎn)。
首先發(fā)現(xiàn) Pulsar 的網(wǎng)絡(luò)協(xié)議使用的是 protobuf,而且注意到PulsarApi.proto
這個文件中有一個BaseCommand
定義:
message BaseCommand {
enum Type {
CONNECT = 2;
SUBSCRIBE = 4;
PRODUCER = 5;
SEND = 6;
SEND_RECEIPT= 7;
MESSAGE = 9;
ACK = 10;
PING = 18;
PONG = 19;
...
}
required Type type = 1;
optional CommandConnect connect = 2;
optional CommandConnected connected = 3;
...
}
又發(fā)現(xiàn) Pulsar 底層靠 netty 框架實(shí)現(xiàn)網(wǎng)絡(luò)通信,那么我們可以大膽猜測, 源碼里肯定有一個大 switch 語句 ,來根據(jù) command 里面的 type 分類處理對應(yīng)的 command。
所以我們可以全局搜索一下case SEND_RECEIPT
,就找到了PulsarDecoder
這個文件:
這里會根據(jù)不同的 command type 調(diào)用不同的 handle 函數(shù),所以可以認(rèn)為這里是 Pulsar 關(guān)鍵功能的入口。
而且注意這是 common 包,也就是說 client 和 broker 都會依賴這個包, 所以斷點(diǎn)打在 switch 這里就可以看到 client 和 broker 的網(wǎng)絡(luò)交互 ,每次跳轉(zhuǎn)的 case 就是網(wǎng)絡(luò)命令的交互順序:
PS:因?yàn)?ping/pong 心跳消息在調(diào)試時很煩人,所以我們可以通過條件斷點(diǎn)跳過心跳消息。另外,我們需要把 client 里面的各種 timeout 都調(diào)大一些,避免調(diào)試時出現(xiàn)超時的錯誤。
這樣,啟動我們的測試用例,僅僅通過這一個斷點(diǎn),就能搞明白 Pulsar 發(fā)消息的流程了:
當(dāng)然,如果你想探究每一步具體做了什么,就跳進(jìn)具體的 handle 函數(shù)里一步步調(diào)試即可。
技巧三、利用各種可視化工具 。
你比如,上面說的網(wǎng)絡(luò)通信過程,我們知道了 produce 一條消息的流程,但每條 protobuf 數(shù)據(jù)包里面到底存了什么信息呢?
關(guān)于這個問題,社區(qū)有大佬寫了一個 lua 腳本, 可以用 wireshark 解析 Pulsar 協(xié)議格式 ,具體說明在這里:
https://github.com/apache/pulsar/tree/master/wireshark
按照說明配置并啟動 wireshark 之后,可以使用如下過濾命令過濾掉無關(guān)的數(shù)據(jù)包:
tcp.port eq 6650 and pulsar and protobuf.field.name ne "ping" and protobuf.field.name ne "pong"
接下來啟動 standalone,通過 Java client 發(fā)送一條消息,就可以在 wireshark 抓到 10 個數(shù)據(jù)包,和剛才通過 debug 得到的流程是一樣的:
同時,我們還可以查看每個包的具體數(shù)據(jù),比如PARTITITONED_METADATA
命令就是在查詢 topic 對應(yīng)的 partition 有多少,因?yàn)檫@里是個非分區(qū)的 topic,所以PARTITITONED_METADATA_RESPONSE
返回了 0:
再比如LOOKUP
命令用來查詢 broker 的 URL,因?yàn)槲覀儐拥?standalone 只有一個 broker,所以LOOKUP_RESPONSE
返回的只有一個 URL:
在真實(shí)的使用場景中肯定有多個 broker,所以這個LOOKUP_RESPONSE
應(yīng)該會返回多個 broker URL。
最后看一下真正發(fā)送消息的SEND
命令里面具體有什么數(shù)據(jù):
可以看到這里面有 producer_name, sequence_id 等數(shù)據(jù),每條消息的 sequence_id 單調(diào)遞增,用來防止由于網(wǎng)絡(luò)重傳導(dǎo)致的消息重復(fù),和 tcp 里面的 seq 差不多的原理。
另外可以看到真正的消息數(shù)據(jù)放在數(shù)據(jù)包的最后,通過一個字段記錄數(shù)據(jù)的長度。
具體的玩法可以有很多,我這里就不一一列舉了,其實(shí)除了 wireshark 分析 Pulsar 的網(wǎng)絡(luò)通信, 還可以使用 zookeeper 的可視化工具查看 Pulsar 的元數(shù)據(jù) 。
比如 prettyZoo 就是一款對 zookeeper 可視化的開源工具,那么我就可以在 Pulsar standalone 啟動之后(會自動啟動 zookeeper),讓 prettyZoo 連接到 zookeeper 的端口,很直觀地查看 zookeeper 里面的節(jié)點(diǎn)數(shù)據(jù):
這里面很多數(shù)據(jù)可能不好理解,但我們手上有源碼, 這些路徑大概率是以字符串常量的形式表現(xiàn)的,那全局搜索就行了 。
比如這個producer-name
的路徑,我們搜一下就定位出來了:
簡單瀏覽一下源碼,原來是借助 zookeeper 生成全局唯一的生產(chǎn)者名字。
最后
本文也夠長了,主要介紹了一些閱讀開源項(xiàng)目源碼的實(shí)用技巧,總結(jié)來說就是: 善于找資源,善于用工具 。
雖然本文是以 Pulsar 為例,但這些技巧都是通用的,可以運(yùn)用到任何比較成熟的開源項(xiàng)目上去。
如果你也有什么經(jīng)驗(yàn)分享,可以留言告訴我,掌握技巧只是漫漫長路的第一步,讓我們共同在開源社區(qū)里成長進(jìn)步。
-
IDE
+關(guān)注
關(guān)注
0文章
341瀏覽量
46886 -
開源
+關(guān)注
關(guān)注
3文章
3408瀏覽量
42720 -
DEBUG
+關(guān)注
關(guān)注
3文章
94瀏覽量
19981
發(fā)布評論請先 登錄
相關(guān)推薦
Matepad pro12.2 已上市半個月,但是還沒有在開源網(wǎng)站看到該項(xiàng)目的開源信息,違背開源精神
關(guān)于Linux下的源代碼閱讀問題
機(jī)友分享 | 導(dǎo)入機(jī)智云Android開源項(xiàng)目的正確姿勢
【HiSpark系列】潤和 HiHope 社區(qū) 開源項(xiàng)目集合
C語言開源項(xiàng)目
下載編譯源碼的要點(diǎn)和搭建源碼閱讀環(huán)境的方法
STM32項(xiàng)目開發(fā)中超級實(shí)用技巧分享
分享一個超級實(shí)用的源碼閱讀小技巧
![分享一個超級實(shí)用的<b class='flag-5'>源碼</b><b class='flag-5'>閱讀</b>小技巧](https://file.elecfans.com/web1/M00/F1/CC/pIYBAGCxutWAHcvlAAAIWQy5CQU999.png)
優(yōu)秀的 Verilog/FPGA開源項(xiàng)目介紹(一)
![優(yōu)秀的 Verilog/FPGA<b class='flag-5'>開源</b><b class='flag-5'>項(xiàng)目</b>介紹(一)](https://file.elecfans.com/web2/M00/17/53/poYBAGFj6ROABN5uAAAcuXS4qfU585.png)
矩陣顯示器上的新聞閱讀器開源項(xiàng)目
![矩陣顯示器上的新聞<b class='flag-5'>閱讀</b>器<b class='flag-5'>開源</b><b class='flag-5'>項(xiàng)目</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
閱讀開源項(xiàng)目源碼的實(shí)用技巧(上)
![<b class='flag-5'>閱讀</b><b class='flag-5'>開源</b><b class='flag-5'>項(xiàng)目</b><b class='flag-5'>源碼</b>的<b class='flag-5'>實(shí)用技巧</b>(上)](https://file1.elecfans.com/web2/M00/82/05/wKgZomQ2JYKAZ5oEAAEMniV7Qqg558.jpg)
如何去閱讀源碼,我總結(jié)了18條心法
![如何去<b class='flag-5'>閱讀</b><b class='flag-5'>源碼</b>,我總結(jié)了18條心法](https://file1.elecfans.com/web2/M00/8C/ED/wKgZomS09fWAQyitAAA7Z8o8AVs331.png)
評論