問題背景
仍然是來自於朋友分享的一個案例,實際案例不難,原因也就是網際網路線路丟包產生的重傳問題。但從一開始只看到資料包截圖的判斷結果,和最後拿到實際資料包的分析結果,卻不是一個結論,方向有點跑偏,所以記錄下本篇。
問題資訊
開局的資料包截圖大概就如下,一堆超時重傳資訊,問題是什麼,不熟悉的可能直接就說是丟包了,像我稍微熟悉的,一眼感覺就像是網際網路常見的 MTU 問題,客戶端傳送的資料包 Len 2760 也就是 2 個 MSS 1380 的大小,在中間傳輸過程中碰到了 MTU 問題, 以至於 1380 大小的資料包被丟棄,因此產生了眾多超時重傳。
基於以上截圖,初始結論就是網際網路線路問題,根因是 MTU 。但總有意外的事發生,等我拿到了實際資料包仔細分析,雖然還是網際網路線路產生的丟包問題,但根因卻不是 MTU 了,初始結論錯誤。
資料包跟蹤檔案資訊主要如下:
λ capinfos 1220.pcapng File name: 1220.pcapng File type: Wireshark/... - pcapng File encapsulation: Ethernet File timestamp precision: microseconds (6) Packet size limit: file hdr: (not set) Packet size limit: inferred: 54 bytes Number of packets: 40 File size: 4264 bytes Data size: 37 kB Capture duration: 14.583142 seconds First packet time: 2023-12-18 07:35:28.365933 Last packet time: 2023-12-18 07:35:42.949075 Data byte rate: 2553 bytes/s Data bit rate: 20 kbps Average packet size: 931.10 bytes Average packet rate: 2 packets/s SHA256: 096e0919a13f8ff2c0b8b4691ff638c14345df621ecd9157daa3b3ce3447b88c SHA1: 3267274c4fce576dde3446d001372b9b34f15717 Strict time order: True Capture application: Editcap (Wireshark) 4.2.0 (v4.2.0-0-g54eedfc63953) Capture comment: Sanitized by TraceWrangler v0.6.8 build 949 Number of interfaces in file: 1 Interface #0 info: Encapsulation = Ethernet (1 - ether) Capture length = 262144 Time precision = microseconds (6) Time ticks per second = 1000000 Time resolution = 0x06 Number of stat entries = 0 Number of packets = 40
客戶端透過 Wireshark 捕獲資料包,捕獲時長 14.58s,資料包數量 40 個,檔案大小 4.264 位元組,平均速率約 20kbps,總體上來說速率很低。資料包經過 Editcap 編輯和 TraceWrangler 處理,一方面是改了檔案格式,另一方面就是重要的匿名。
專家資訊如下,資料包總數 40 的情況下,疑似重傳資料包數量就有 12 個,該 TCP 連線的質量可想而知。
問題分析
首先是 TCP 三次握手,客戶端和伺服器各自所通告的 MSS 為 1460 和 1380 ,兩者取小為 1380 ,所以最後傳輸遵循的最大 TCP 分段就是 1380。另 IRTT 0.027269 秒,同時支援 SACK 和 WS 。
客戶端 192.168.38.134 所傳送的資料,在直到產生問題的 No.18 Len 2760 之前,資料包長度還是小分段 213、129、105、737 等,這也確實容易第一眼給人錯覺,像是 No.18 之後 MSS 1380 的資料分段發生了 MTU 問題造成丟包重傳。
我們將資料包分成三段,No.1-3 TCP 三次握手,No.4-16 正常資料互動,No.17 以及之後為問題點,重點分析。
分析全過程如下:
No.17-22 均為客戶所傳送的資料分段,除了 No.17 Len 683 較小分段外,其他均為 1 或 2 個 MSS 1380 分段;
經過一個 RTT 時間,伺服器端返回的 No.23 ACK Num 969 僅僅確認了 No.17 ,緊接著的 No.24 即判斷為 TCP Dup ACK,因為它的 ACK Num 仍為 969,並攜帶有 SACK 標識 SLE 7869,SRE=9249。此處關鍵,代表說明確認收到了客戶端所傳送的 Seq Num 969 之前以及 Seq Num 7869-9249 之間的資料,意味著伺服器端還是收到了一個 9249-7869=1380 MSS 大小的資料分段,所以並不是初始結論,超出了中間路徑 MTU 大小而造成所有 MSS 1380 大小的資料包被丟棄;
但問題仍是中間網際網路線路中間發生了丟包,哪些資料分段丟失了?No.18-20 , Seq Num 969 - 7869 之間的資料。 由於客戶端收到了 No.24 SACK ,所以緊接著進行了 No.25-26、No.28-29 的快速重傳,考慮到擁塞視窗減小的緣故,只重傳了 Seq Num 969 - 6489 的資料,而 Seq Num 6489 - 7869 並未傳送。期間也收到了一個客戶端 No.27 SACK,確認又收到了一個 Seq Num 9249 - 10629 =1380 MSS 大小的資料分段;
不幸的是,經過一個 RTT 時間,伺服器端返回的 No.30 SACK 僅確認了 Seq Num 2349 之間的資料,也就是相較之前,只多確認收到了一個 MSS 1380 的資料分段,而 SLE,SRE 沒有任何變化,說明之前重傳的資料包又發生了丟包;
此時擁塞視窗繼續減小,客戶端僅傳送了一個 No.31 的新資料分段,以及再次重傳了 No.32 Seq Num 為 2349 的資料分段,因為 No.30 代表缺失了 Seq Num 2349 - 7869 之間的資料;
伺服器返回的 No.33 SACK 繼續僅多確認了一個 MSS 1380 大小的資料,ACK Num 為 3729,客戶端再次重傳 No.34-35;
之後 No.34 - No.40 ,客戶端進行了多次超時重傳,超時時間明顯不斷翻倍,此時不管是中間網際網路線路持續丟包,還是伺服器端因長時間等待已釋放連線,總之不再有確認返回。
問題總結
整個分析過程中因為多出了 SLE SRE 的緣故,判斷出的問題根因也發生了變化,並非 MTU 問題。而最終經朋友反饋,應用傳輸丟包問題的原因就是運營商線路丟包,符合實際資料包現象(丟失的資料分段無規律可言),畢竟資料包從不說謊。