最近生產上出現一個性能問題,表現為:行情延時5s左右。從log一路追查下去,發現是我們自己寫的一個行情網關(部署在xx.xx.xx.132)<->第三方的中轉網關(部署在xx.xx.xx.133)之間的通信產生的。
Who to blame? 這是個問題,是我們的行情網關、網絡、還是第三方的中轉網關。所以想到用WireShark抓包進行分析。抓到的包在這里:CaptureData-20160905.pcapng,用WireShark打開后,在統計里有很多有用的信息,有用的是這幾個:
- 捕獲文件屬性:能看到基本信息,抓包起始時間、跨度(01:04,共64秒)、大小(7624KB)、分組(28068個包)等
- 協議分級:能看到各級協議的包的占比
- IO圖表:能看到每秒的包數量,還可以自定義過濾器,對Y軸加一些sum、count、avg等統計方法
- TCP-時間序列:很能反映通信特征,任何一方的seq不變表示不再發數據,只發長度為0的應答包
- TCP-吞吐量:反映每秒吞吐的包長度
- TCP-往返時間:rtt round trip time, 這個圖很能說明132處理的快,133發的慢
- TCP-窗口尺寸:表示一方接收數據的能力,132一直在5萬以上,而133到過0
首先要設置合適的過濾器,過濾出我們感興趣的包,試下來最有用的是:ip.addr == xx.xx.xx.132 && ip.addr == xx.xx.xx.133。通過分析,整個60秒的通信過程分為3個部分:
- 132:50012端口與133:7777端口的3次握手,syn->syn ack->ack。建立連接后,狀態變為established
- 132:50013端口向133:7777端口發送數據,主要是發送要訂閱的標的。在最下面的data窗口能看到ascii碼里會顯示標的的代碼,比如au1609等
- 132:50013端口接收133:7777端口發來的數據,主要是期貨行情。
分析的一些小結論如下:
- 數據的邏輯關系:
發送端seq + data bytes = 接收端ack
以及發送端seq + data bytes = 發送端next seq
- 接收端有時會將若干個ack確認包合並成1個。
- 包15281到15673,注意到133的windowSize一直在不斷減少,突然變大就是window update。包16073開始各種window full、zero window,因為133的winSize=0滿了,132開始發送0窗口探測報文。訂閱完成后133的win就不再減少了,沒壓力了。換成133給132發送行情數據了。
- Frame在網線級別,Ethernet在mac級別,IP在IP地址(v4、v6)級別,tcp在端口port級別。
- 注意前兩次握手syn和syn ack里有關於Selective Ack、Maximum Segment Size和Windows Scale(比如:8,表示位移8位,即乘數為256)等選項的協商
- 吞吐量(bytes/sec) = Window Size(bytes) / RTT(round trip time, sec) = 64KB/0.000128s = 500MB/s
- 右鍵Follow this stream,會產生一個過濾器:tcp.stream eq 604,其實對應於每個ip+port對都會產生一個stream index,不論方向。這個index應該是wireshark在抓取過程中順序產生的,類似於Frame Number。這個過濾器的效果類似於:ip.addr == xx.xx.xx.132 && ip.addr == xx.xx.xx.133 && tcp.port == 7777 && tcp.port == 50012,還是蠻方便實用的。
- 性能分析:syn、ack在tcp協議級別,不包括任何數據,與應用層無關,握手不卡說明網絡沒問題。發送行情的過程中,雙方的win=65535,表示窗口這塊都有富余,雙方的網絡都不卡。132收到行情處理再回復ack只用了<0.1ms,說明接收端的速度也很快。所以只能有一個解釋,133發送端發的慢。其實從133的日志里也能看出來,“客戶端發送隊列已滿,將丟棄xx報文”。
- 由於中轉網關是第三方的程序,我們沒法控制,因此只能我們減少訂閱的標的數,發送的壓力小了,自然就不慢了。