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