技巧二、多猜,多搜索,可以在底層庫(標準庫、網(wǎng)絡框架等)打條件斷點過篩選出關鍵流程 。
這句話其實是高效 debug 的關鍵。初看源碼時「猜」是很重要且很有效的手段,結(jié)合 IDE 的搜索功能,能夠幫我們快速定位關鍵代碼。
為什么底層庫適合打斷點呢?因為出看大項目的代碼很難搞清楚其中的細節(jié),加上各種異步、多線程的操作,很容易把代碼「跟丟」。如果把斷點打在底層庫的接口/方法上,就可以根據(jù)調(diào)用棧分析調(diào)用過程。
當然,底層庫被調(diào)用的次數(shù)比較多,可能出現(xiàn)很多無關的調(diào)用,所以要結(jié)合條件斷點來過濾掉無關的調(diào)用。
還是用 Pulsar 舉例,我現(xiàn)在想探究 producer 發(fā)送消息的流程,那么 producer 和 broker 之間的網(wǎng)絡通信過程就是一個重要的切入點。
首先發(fā)現(xiàn) Pulsar 的網(wǎng)絡協(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 框架實現(xiàn)網(wǎng)絡通信,那么我們可以大膽猜測, 源碼里肯定有一個大 switch 語句 ,來根據(jù) command 里面的 type 分類處理對應的 command。
所以我們可以全局搜索一下case SEND_RECEIPT
,就找到了PulsarDecoder
這個文件:
這里會根據(jù)不同的 command type 調(diào)用不同的 handle 函數(shù),所以可以認為這里是 Pulsar 關鍵功能的入口。
而且注意這是 common 包,也就是說 client 和 broker 都會依賴這個包, 所以斷點打在 switch 這里就可以看到 client 和 broker 的網(wǎng)絡交互 ,每次跳轉(zhuǎn)的 case 就是網(wǎng)絡命令的交互順序:
PS:因為 ping/pong 心跳消息在調(diào)試時很煩人,所以我們可以通過條件斷點跳過心跳消息。另外,我們需要把 client 里面的各種 timeout 都調(diào)大一些,避免調(diào)試時出現(xiàn)超時的錯誤。
這樣,啟動我們的測試用例,僅僅通過這一個斷點,就能搞明白 Pulsar 發(fā)消息的流程了:
當然,如果你想探究每一步具體做了什么,就跳進具體的 handle 函數(shù)里一步步調(diào)試即可。
技巧三、利用各種可視化工具 。
你比如,上面說的網(wǎng)絡通信過程,我們知道了 produce 一條消息的流程,但每條 protobuf 數(shù)據(jù)包里面到底存了什么信息呢?
關于這個問題,社區(qū)有大佬寫了一個 lua 腳本, 可以用 wireshark 解析 Pulsar 協(xié)議格式 ,具體說明在這里:
https://github.com/apache/pulsar/tree/master/wireshark
按照說明配置并啟動 wireshark 之后,可以使用如下過濾命令過濾掉無關的數(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 對應的 partition 有多少,因為這里是個非分區(qū)的 topic,所以PARTITITONED_METADATA_RESPONSE
返回了 0:
再比如LOOKUP
命令用來查詢 broker 的 URL,因為我們啟動的 standalone 只有一個 broker,所以LOOKUP_RESPONSE
返回的只有一個 URL:
在真實的使用場景中肯定有多個 broker,所以這個LOOKUP_RESPONSE
應該會返回多個 broker URL。
最后看一下真正發(fā)送消息的SEND
命令里面具體有什么數(shù)據(jù):
可以看到這里面有 producer_name, sequence_id 等數(shù)據(jù),每條消息的 sequence_id 單調(diào)遞增,用來防止由于網(wǎng)絡重傳導致的消息重復,和 tcp 里面的 seq 差不多的原理。
另外可以看到真正的消息數(shù)據(jù)放在數(shù)據(jù)包的最后,通過一個字段記錄數(shù)據(jù)的長度。
具體的玩法可以有很多,我這里就不一一列舉了,其實除了 wireshark 分析 Pulsar 的網(wǎng)絡通信, 還可以使用 zookeeper 的可視化工具查看 Pulsar 的元數(shù)據(jù) 。
比如 prettyZoo 就是一款對 zookeeper 可視化的開源工具,那么我就可以在 Pulsar standalone 啟動之后(會自動啟動 zookeeper),讓 prettyZoo 連接到 zookeeper 的端口,很直觀地查看 zookeeper 里面的節(jié)點數(shù)據(jù):
這里面很多數(shù)據(jù)可能不好理解,但我們手上有源碼, 這些路徑大概率是以字符串常量的形式表現(xiàn)的,那全局搜索就行了 。
比如這個producer-name
的路徑,我們搜一下就定位出來了:
簡單瀏覽一下源碼,原來是借助 zookeeper 生成全局唯一的生產(chǎn)者名字。
最后
本文也夠長了,主要介紹了一些閱讀開源項目源碼的實用技巧,總結(jié)來說就是: 善于找資源,善于用工具 。
雖然本文是以 Pulsar 為例,但這些技巧都是通用的,可以運用到任何比較成熟的開源項目上去。
如果你也有什么經(jīng)驗分享,可以留言告訴我,掌握技巧只是漫漫長路的第一步,讓我們共同在開源社區(qū)里成長進步。
-
IDE
+關注
關注
0文章
352瀏覽量
47788 -
開源
+關注
關注
3文章
3695瀏覽量
43858 -
DEBUG
+關注
關注
3文章
95瀏覽量
20589
發(fā)布評論請先 登錄
Matepad pro12.2 已上市半個月,但是還沒有在開源網(wǎng)站看到該項目的開源信息,違背開源精神
關于Linux下的源代碼閱讀問題
機友分享 | 導入機智云Android開源項目的正確姿勢
【HiSpark系列】潤和 HiHope 社區(qū) 開源項目集合
C語言開源項目
下載編譯源碼的要點和搭建源碼閱讀環(huán)境的方法
STM32項目開發(fā)中超級實用技巧分享
分享一個超級實用的源碼閱讀小技巧

優(yōu)秀的 Verilog/FPGA開源項目介紹(一)

評論