TCP 重送導致工業相機通訊停頓的原因與釐清方法

· 更新日期: · · TCP, 網路, 故障調查, Windows 開發, 工業相機

更新紀錄(3 筆,最後更新 2026年09月04日)

本文的修改紀錄。已保存的更新前版本,可透過附有 DOI 的永久連結閱讀。

已將繁體中文版改寫為日文原文的完整翻譯。先前的繁體中文版只譯出日文原文的一部分,遺漏了章節、表格、Mermaid 圖、圖說與 FAQ。本次依日文原文將這些內容全部補回,並新增本文的知識地圖章節。技術主張與日文版一致。 查看更新前的版本 (DOI: 10.5281/zenodo.22279330)
補上了日文原文中已有的諮詢引導(consultation_services)。內文沒有改動。
修正了參考連結等處含有豎線(管線)符號的行被算繪為表格、導致連結無法點擊的顯示錯誤。內文內容未變動。
初次發布
引用本文(DOI: 10.5281/zenodo.21616251)

本文保存於 Zenodo。以下同時提供一律指向最新版本的 DOI,以及固定於您正在閱讀版本的 DOI。

Go Komura(2026)。〈TCP 重送導致工業相機通訊停頓的原因與釐清方法〉。小村軟體有限公司。https://doi.org/10.5281/zenodo.21616251 https://comcomponent.com/zh-TW/blog/2026/03/11/001-tcp-retransmission-rfc1323-industrial-camera/

DOI(最新版本)
10.5281/zenodo.21616251
DOI(此版本)
10.5281/zenodo.22297084

在工業相機或設備控制的通訊中,最棘手的現象是平均很快,卻 偶爾停上幾秒。重現率很低,平時什麼事也沒有,於是 UI、執行緒、GC、相機 SDK、NIC、交換器,全部看起來都有一點嫌疑。

這次要談的,是控制工業相機的應用程式與主機之間的 TCP 通訊,偶爾會有幾秒完全不動的現象。實際查下去,真正的原因並不是應用程式停住,而是 封包遺失所引起的 TCP 重送等待。再進一步,啟用 RFC1323 系的 timestamp 機制(以目前的標準整理來說是 RFC 7323)之後,這套系統的等待時間就被壓到了最低。

設備名稱、組態與數值都做過一般化,但整套思路可以直接用在實務上。

目錄

  1. 先講結論(一句話)
  2. 症狀看起來的樣子
    • 2.1. 應用程式還活著,只有回應停了幾秒
    • 2.2. 頻率低,光看日誌很難發現
  3. 實際發生了什麼(圖解)
    • 3.1. 從封包遺失進入重送等待
    • 3.2. 秒級的停頓與 RTO 的形狀吻合
  4. 調查時檢視的重點
    • 4.1. 先排除應用程式內部的停頓原因
    • 4.2. 用封包擷取確認重送
    • 4.3. 查看實際協商到的 TCP 選項
  5. RFC1323 timestamp 有效的理由
    • 5.1. timestamp 是為了 RTTM 與 PAWS
    • 5.2. 可以消除重送時 RTT 量測的模糊
    • 5.3. 本案例能壓縮等待時間的理由
  6. 實際採取的對策
    • 6.1. 啟用 timestamp
    • 6.2. 在 SYN / SYN-ACK 上確認 TSopt
    • 6.3. 這樣做仍然沒效時該看哪裡
  7. Wireshark 上的觀察重點
  8. 大致的取捨
  9. 總結
  10. 參考資料

圖中實線表示始終成立的關係,虛線表示附帶條件的關係(成立條件寫在詳細頁面中各關係的說明中)。關係的完整清單(共 19 條,附依據與可信度)以及主要概念的定義,彙整在知識地圖詳細頁面(日文)。資料:JSON-LD / Turtle

1. 先講結論(一句話)

  • 偶爾停上幾秒的 TCP 通訊,真正的原因往往不是應用程式停住,而是 封包遺失之後的重送等待
  • 如果封包擷取看得到 Retransmission 與明顯的時間差,而且停頓時間與 RTO 的等待方式吻合,嫌疑就相當大
  • TCP timestamps option 是為了 RTT 量測與 PAWS 而存在的機制,同時也能消除重送時 RTT 量測的模糊
  • 在這個案例中,啟用 RFC1323 系的 timestamp 機制之後,RTO 估計停留在過時且保守狀態的時間變短,秒級的停頓被壓到了最低
  • 不過,這 不是消除遺失本身的魔法。物理層、NIC、交換器、中介設備、驅動程式與緩衝區設計,仍然需要另外重新檢視

簡單說,如果「偶爾停上幾秒」的真面目是 TCP 內部的等待時間,那麼只在應用程式的重試上使力就會打偏。先看 wire,先確定是不是重送等待,反而比較快。

本文結論的流程說明偶爾停上幾秒的 TCP 通訊要先看 wire 確定是不是重送等待,若是重送等待則 timestamps 有機會壓縮等待時間,但封包遺失來源仍須另外調查的圖。偶爾停上幾秒的 TCP 通訊先看 wire確定是不是重送等待timestamps 有機會壓縮等待遺失來源要另外調查

圖 1: 在應用程式的重試上使力之前,先用 wire 鎖定「到底卡在哪裡等」。

接下來 TCP 的縮寫會接連出現。為了不以網路為專長的 Windows 開發者,先在這裡整理一次。只要先掌握這些,後面應該就不會卡住。

術語 全稱 意義
ACK Acknowledgment 確認回應。用來告訴對方「我收到這裡為止了」的機制
RTT Round-Trip Time 往返時間。從送出到 ACK 回來為止的時間
RTO Retransmission Timeout 重送計時器。在這段時間內等不到 ACK 就重送。數值由 RTT 的估計值算出
RTTM Round-Trip Time Measurement RTT 的量測。這是 timestamp 機制的目的之一
PAWS Protect Against Wrapped Sequences 針對序號繞回一圈這種事故的防護。這是 timestamp 機制的另一個目的
TSopt TCP Timestamps Option 掛在 TCP 標頭上的選項之一。種類 8、長度 10 位元組,會攜帶下面兩個值
TSval Timestamp Value 送出端填入的值,也就是自己這一端的時鐘值
TSecr Timestamp Echo Reply 把收到的 TSval 原樣送回的欄位。有了它就知道「這是在回應哪一次送出的 ACK」
SACK Selective Acknowledgment 接收端逐段告知「自己收到了哪些範圍」的機制
Dup ACK Duplicate ACK 指向同一個序號的 ACK 重複回來。這是中間有缺漏的訊號
fast retransmit — Dup ACK 累積到一定數量後,不等 RTO 到期就重送的機制。Windows 的預設是「收到 3 個指向同一序號的 ACK(最初的 1 個加上重複的 2 個)」
Karn 演算法 — 規定不可以從重送過的區段取 RTT 樣本。因為分不出那是在回應哪一次送出

2. 症狀看起來的樣子

2.1. 應用程式還活著,只有回應停了幾秒

一開始最麻煩的是,整個應用程式看起來並沒有凍住。

  • UI 沒有完全死掉
  • 處理程序也沒有當掉
  • CPU 也沒有一直滿載
  • 只有相機控制命令的回應會 偶爾 缺個幾秒

這種症狀很難跟應用程式內部的死結或無窮迴圈分辨開來。而且在設備控制上,一次數秒的停頓就會直接給人整條產線停線的印象。就算平均值很漂亮,第一線的體感還是會差很多。

2.2. 頻率低,光看日誌很難發現

這類缺陷麻煩的地方在於發生頻率很低。可能一小時一次、半天一次,或是只有幾個條件疊在一起時才出現。

只靠日誌追,大概會變成這樣。

  • 應用程式日誌上停在「送出了」「沒回來」
  • 接收端日誌看起來是「什麼都沒收到」
  • 剛好同一個時段還發生了別的事件,嫌疑就分散掉了

這種時候,如果只想用應用程式日誌去還原因果關係,很容易就陷入泥沼。往下降一層到通訊層來看,反而比較快。

光看日誌無法鎖定原因的結構說明應用程式日誌停在送出了卻沒回來,接收端日誌看起來什麼都沒收到,加上同一時段的其他事件讓嫌疑分散,所以不要只用應用程式日誌還原因果,往下降到通訊層比較快的圖。應用程式日誌:送出了卻沒回來嫌疑分散而陷入泥沼接收端日誌:什麼都沒收到同一時段的其他事件往下降一層到通訊層

圖 2: 低頻率的停頓只靠日誌追會陷入泥沼。用封包看比較快。

3. 實際發生了什麼(圖解)

3.1. 從封包遺失進入重送等待

這次的來龍去脈很單純。封包在途中某處被丟掉,送出端等 ACK,等不到就等 RTO 到期後才重送。

相機端網路主機應用程式相機端網路主機應用程式在這裡遺失等不到 ACK 只好繼續等這次要求的恢復要先等 RTO通訊在這裡恢復控制命令 (Seq=N)重送控制命令重送封包送達ACKACK

圖 3: 封包被丟掉時 ACK 就不會回來,要等 RTO 到期後才重送。這段時間在應用程式眼中就是「數秒的停頓」。

從應用程式的角度看像是「停了幾秒」,但以 TCP 的角度來說,只是「ACK 還沒回來,所以在等重送計時器到期」而已。雖然不起眼,這種停頓方式其實相當常見。

這次的控制通訊多半是小型的 request/response,一次來回並不會有大量還沒被 ACK 的資料在飛。因此在累積到足夠的 duplicate ACK 去觸發 fast retransmit 之前,RTO 等待 就很容易先浮上檯面。

控制通訊容易讓 RTO 等待浮上檯面的理由說明以小型 request/response 為主的控制通訊中未被 ACK 的資料很少,duplicate ACK 累積不足因此難以觸發 fast retransmit,結果 RTO 等待就浮上檯面的圖。以小型 request/response 為主未被 ACK 的資料很少Dup ACK 累積不到足夠數量難以觸發 fast retransmitRTO 等待浮上檯面

圖 4: 和大量資料流動的通訊不同,控制通訊發生遺失時容易變成等 RTO 到期。

3.2. 秒級的停頓與 RTO 的形狀吻合

TCP 的重送等待雖然有實作差異,大體上都採取保守的等待方式。RFC 6298 中,初始 RTO 以 1 秒為基準,計算結果若小於 1 秒就向上取到 1 秒,發生逾時就加倍。

是否封包遺失等不到 ACK等待 RTO重送ACK 回來了嗎?通訊恢復把 RTO 加倍

圖 5: RTO 每次等不到 ACK 就加倍。1 秒、2 秒、4 秒這種等法就是從這個形狀來的。

所以,即使是希望在幾百毫秒內結束的場合,條件一差也可能看起來像 1 秒、2 秒、4 秒這樣的等待。這次的「偶爾停上幾秒」,跟這個形狀吻合得相當自然。

4. 調查時檢視的重點

4.1. 先排除應用程式內部的停頓原因

沒有一開始就認定是 TCP,而是先把應用程式端的典型原因排除掉。

檢查的項目 檢查的理由 本次的結論
UI 執行緒/工作者執行緒 檢查是否停止回應或互相等待 不是主因
CPU 使用率 檢查高負載造成的處理延遲 停頓時也不是滿載狀態
GC/記憶體壓力 檢查是否有暫停 停頓時間的形狀對不上
相機 SDK 呼叫 檢查 SDK 內部的等待 與 wire 上的延遲不一致
封包擷取 檢查通訊層的重送 在這裡看見了原因的線索

這裡重要的是,不要只憑應用程式日誌的時刻就認定原因。在設備控制的應用程式中,上層的等待往往只是把下層的等待照樣映出來而已。

先排除應用程式內部原因的釐清順序說明不要一開始就認定是 TCP,先排除執行緒、CPU、GC、相機 SDK 這些應用程式內部的典型停頓原因,再用封包擷取確認通訊層重送的釐清順序的圖。先排除執行緒、CPU、GC、SDK用封包擷取檢視通訊層重送的線索浮現出來不要只憑日誌的時刻認定原因

圖 6: 不要一開始就認定。先排除應用程式內部的典型原因,再往 wire 下去。

4.2. 用封包擷取確認重送

抓下封包擷取之後,可以看到停頓的時段出現 TCP Retransmission,而且緊接在它之前的 ACK 根本沒有回來。

該看的地方大致是這幾個。

  • 是否出現相同 Seq 的重送
  • 到重送為止的時間差是否與停頓時間一致
  • 看起來是不是等 RTO 到期,而不是 Dup ACK 或 Fast Retransmission
  • 出問題的連線是否每次都落在同一個 tcp.stream

這幾點對上之後,「應用程式停住」的說法就會退位,「TCP 在等重送」的可能性會相當高。

確定是重送等待的檢查點說明相同 Seq 是否出現重送、到重送為止的時間差是否與停頓時間一致、看起來是否為等 RTO 到期這三點對上之後,就能判斷不是應用程式停住而是 TCP 在等重送的圖。相同 Seq 是否出現重送TCP 正在等重送時間差是否與停頓時間一致看起來是否為等 RTO 到期並不是應用程式停住

圖 7: 這 3 點都對上,「TCP 在等重送」的可能性就遠大於「應用程式停住」。

4.3. 查看實際協商到的 TCP 選項

接著看的是連線建立時的 SYN / SYN-ACK。timestamp 是在 TCP 連線的三向交握階段協商的,所以這裡如果沒有出現 TSopt,那條連線就不會用到它。

相機端主機相機端主機在這裡協商成功,之後的區段才用得到 TSoptSYN + TSopt ?SYN/ACK + TSopt ?ACK

圖 8: timestamp 是在三向交握中協商的。SYN / SYN-ACK 沒有 TSopt,那條連線就不會使用它。

不看這裡就只動 OS 設定的話,就會出現「明明已經啟用了卻沒有效」這種同樣不起眼的意外。設定值比不上 wire 上的事實有力。

5. RFC1323 timestamp 有效的理由

實務上還留著「RFC1323 的 timestamp」這種叫法,但現行的標準整理是 RFC 7323。本文沿用慣稱寫成 RFC1323,意思指的就是 TCP timestamps option。

5.1. timestamp 是為了 RTTM 與 PAWS

TCP 的 timestamps option 主要用在兩個目的上。

  • RTTM(Round-Trip Time Measurement)
  • PAWS(Protect Against Wrapped Sequences)

這次派上用場的是 RTTM 這一邊。送出的區段所帶的 TSval,會由對方在 ACK 的 TSecr 中送回,送出端因此更容易把 RTT 量得更細、更準。

timestamps option 的兩個目的說明 TCP 的 timestamps option 用在 RTTM 也就是往返時間的量測,以及 PAWS 也就是序號繞回一圈的防護這兩個目的上,而本案例派上用場的是 RTTM 這一邊的圖。timestamps optionRTTM(往返時間的量測)PAWS(序號繞回一圈的防護)這次派上用場的是這一邊把 TSval 用 ACK 的 TSecr 送回來量

圖 9: timestamp 的目的是 RTTM 與 PAWS 兩個。這個案例派上用場的是 RTT 量測那一邊。

5.2. 可以消除重送時 RTT 量測的模糊

一旦發生重送,沒有 timestamp 就會分不清楚「這個 ACK 是在回應最初的那次送出,還是在回應重送」。這正是 Karn 演算法所在意的地方。

RFC 6298 規定,重送過的區段不可以拿來取 RTT 樣本。理由是分不出那是在回應哪一次送出。不過只要有 timestamps option,就能把這個模糊拿掉。因為看 ACK 帶回來的 TSecr,就能辨認出是帶著哪一個 TSval 的區段送達了。

接收端送出端接收端送出端這個區段遺失等不到 ACK 只好繼續等可以判別是在回應哪一次送出Seq=N, TSval=1000重送 Seq=N, TSval=2000ACK, TSecr=2000

圖 10: 看 TSecr 就能判別那個 ACK 是在回應最初的送出還是重送。

這裡就是這次改善的核心。

5.3. 本案例能壓縮等待時間的理由

這個案例中,封包遺失時不時就會發生,每發生一次,RTT/RTO 的估計就容易往保守的方向偏。啟用 timestamp 之後,即使在包含重送的場面,RTT 的估算也比較容易更新,於是 RTO 估計維持在過時狀態一路膨脹的時間就被壓下來了。

這裡很容易跳過推論,所以再拆解得細一點。

首先,RTO 的下限本身並不會因為有沒有 timestamp 而改變。 RFC 6298 規定,算出來的 RTO 若小於 1 秒就應該向上取到 1 秒。實作也可能自己另有下限,在 Windows 上就是 Get-NetTCPSetting 會列出的 MinRtoMs(以 10 毫秒為刻度,取 20 至 300 毫秒的範圍)。也就是說,並不是「加了 timestamp 所以下限降低了」。

真正發揮作用的是更前面一步。RFC 6298 定下了以下 3 件事。

  1. 重送計時器每到期一次,就把 RTO 乘以 2(指數退避)
  2. 退避後的 RTO,會 在取得新的 RTT 量測值時回到原本的水準
  3. 那個「新的 RTT 量測值」,只有在送出未經重送的資料並被 ACK 時才拿得到

再加上 Karn 演算法,重送過的區段不可以拿來取 RTT 樣本。不過,使用 timestamps option 時這條限制就解除了。 如同 5.2 所述,看 TSecr 就能判別那是在回應哪一次送出。

把這些排在一起,脈絡就清楚了。在遺失零星持續發生的系統裡,沒有 timestamp 時第 2 點與第 3 點的條件很難同時成立,加倍後的 RTO 要靠實測回到原本水準所需的時間就會拖得很長。 在那個狀態下如果又碰到下一次遺失,等待就不是從 1 秒開始,而是從 2 秒、4 秒開始。有 timestamp 的話,連含有重送的區間也能重新量測,於是這段「回不去的時間」變短了 ── 這就是這次發揮作用的路徑。

加倍後的 RTO 回復的條件與 timestamp 發揮作用的方式說明每次逾時 RTO 都會加倍,取得新的 RTT 量測值時才會回到原本水準,但那個量測值只能從未經重送的資料的 ACK 取得,因此用 timestamps 解除這條限制後加倍的 RTO 回不去的時間就縮短的圖。每次逾時 RTO 就加倍靠新的 RTT 量測回到原本水準量測只能來自未重送資料的 ACK用 timestamps 連重送區間也能量重新量測的機會增加加倍後的 RTO 回不去的時間縮短

圖 11: 核心不在下限降低,而是加倍後的 RTO 能靠實測更快回到原本水準。

老實寫在這裡:本文並沒有量到改善之後 RTO 的實測值。 已知的只到「秒級的停頓減少到不再造成第一線困擾的程度」為止。若想用數字呈現效果,最近的路徑是用第 7 章的顯示過濾器與 Time delta from previous displayed packet 欄,把到重送為止的時間差分布做成 before/after 的統計。

換句話說,這次做的並不是讓 TCP 變快的魔法,而是 減少 TCP 不必要地觀望過久的時間。

當然,RFC 7323 也沒有說「RTT 樣本變多就什麼都能漂亮解決」。它對 RTO 最佳化的助益確實有其侷限。不過,能消除重送時的模糊 這一點,在這次這種系統上有時會直接見效。

也有要注意的地方。

  • 這部分有一些取決於 TCP stack 的實作
  • 光靠 timestamp 並不會讓封包遺失本身消失
  • 物理層或中介設備有問題的話,根本原因在別的地方
  • SACK、NIC 驅動程式、卸載(offload)設定、交換器端的問題,也建議另外檢視

不過,像這次「遺失不是零,但真正痛的是秒級的等待」這種系統,它有時效果相當顯著。

6. 實際採取的對策

6.1. 啟用 timestamp

對策上,是讓連線兩端都處於可以協商 timestamps option 的狀態。在 Windows 系統上有時會被當成 RFC 1323 選項來處理,會受到 OS 設定與網路設定的影響。

把具體步驟寫下來。首先,查看目前是什麼狀態。

netsh interface tcp show global

輸出當中會有 RFC 1323 timestamp 這個項目,看那裡是不是已啟用。若要啟用,就在具備系統管理員權限的命令提示字元中這樣下。

netsh interface tcp set global timestamps=enabled

timestamps 可以指定的值有 disabled/enabled/default 三種,default 是回到系統預設的指定方式。

要從 PowerShell 查看與設定的話是這樣。

Get-NetTCPSetting | Select-Object SettingName, Timestamps, MinRtoMs, InitialRtoMs
Set-NetTCPSetting -SettingName InternetCustom -Timestamps Enabled

Timestamps 可以指定的值是 Enabled/Disabled。可以變更的 SettingName 會隨 Windows 版本而不同,所以不要一上來就打 Set-,先用 Get-NetTCPSetting 查看實際存在的名稱。傳入不存在的名稱就會在那裡停住。

如果是在舊環境直接查看登錄檔,就是下面這個登錄機碼下的 Tcp1323Opts(REG_DWORD)。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

值的意義是,0 為停用 RFC 1323 選項,1 為只啟用 window scaling,2 為只啟用 timestamps,3 為兩者都啟用。記成位元 0 對應 window scaling,位元 1 對應 timestamps,就不會弄混。

設定時有 3 個要注意的地方。

  • 只對新的連線生效。 timestamp 是在三向交握中協商的,所以對已經建立好的連線沒有作用。必須讓設備端重新建立連線
  • 兩端都要支援才會成立。 只在主機端啟用,如果相機端沒有在 SYN/ACK 回傳 TSopt,那條連線就不會用到它
  • 這個設定也會改變連線的性質。 timestamp 會讓 TCP 標頭變大,因此一個區段能載的資料會少一些

不過在實務上,比起「設定畫面顯示為已啟用」,「SYN / SYN-ACK 的實際封包帶著 TSopt」更重要。這點真的是如此。

設定 timestamp 時的 3 個注意事項說明 timestamp 的設定因為在三向交握中協商所以只對新連線生效、兩端都要支援才會成立、標頭變大使一個區段能載的資料略減這三個注意事項的圖。設定時的 3 個注意事項只對新連線生效需要兩端都支援標頭變大資料略減讓設備端重新建立連線

圖 12: 設定完並不算結束。還要重新建立連線,並確認對方是否支援。

6.2. 在 SYN / SYN-ACK 上確認 TSopt

啟用之後確認了 3 點。

  • 出問題的連線,SYN 上是否帶有 TSopt
  • SYN/ACK 那一側是否也回傳了 TSopt
  • 之後的資料區段與 ACK 上,TSopt 是否持續帶著

確認到這裡,才能說「那條連線實際上有在使用 timestamps」。

6.3. 這樣做仍然沒效時該看哪裡

即使啟用了 timestamp,遇到下列情況時改善的幅度仍可能有限。

  • 遺失率本身就很高
  • 中介設備會破壞、丟棄或改寫 TCP option
  • NIC/驅動程式/卸載相關另有其他問題
  • 應用程式把整體流程都掛在一個同步呼叫上,一次等待看起來就像全面停頓
  • 真正的主因其實不在 TCP,而是相機端處理停住或設備內部佇列塞住

因此,對策照這個順序推進會比較清楚。

  1. 先在 wire 上確認是重送等待
  2. 查看 TSopt 有沒有協商成功
  3. 啟用 timestamps,看改善的差異
  4. 若問題仍在,再分別追究遺失來源與應用程式設計
推進對策的順序說明先在 wire 上確認是重送等待,接著查看 TSopt 有沒有協商,再啟用 timestamps 觀察改善差異,若問題仍在就分別追究遺失來源與應用程式設計的對策順序的圖。在 wire 上確認重送等待查看 TSopt 有沒有協商啟用 timestamps 觀察差異仍在的話分別追究遺失來源與設計

圖 13: 依照確認、協商、啟用、追查剩餘問題的順序推進,比較容易釐清沒效的原因。

7. Wireshark 上的觀察重點

先列出釐清問題時好用的顯示過濾器。

tcp.stream eq <目標串流>
tcp.analysis.retransmission
tcp.analysis.fast_retransmission
tcp.analysis.lost_segment
tcp.options.timestamp.tsval
tcp.options.timestamp.tsecr

看的方式也有幾個訣竅。

  • 用 tcp.stream 只留下目標連線
  • 把 Time delta from previous displayed packet 顯示出來,直接看停住了幾秒
  • 確認問題發生的瞬間有沒有出現 Retransmission
  • 確認連線開始時的 SYN / SYN-ACK 有沒有協商 TSopt
  • 查看 ACK 有沒有帶回 TSecr

畫面看起來是什麼樣子,也用文字寫下來。這個症狀習慣之後一眼就能認出來。

觀察的位置 看起來是什麼樣子
封包清單的 Info 欄 重送的封包會標上 [TCP Retransmission]
該列的顏色 因為符合 Wireshark 預設的著色規則「Bad TCP」,只有那一列會變成黑底紅字。隨手掃過也撿得到
詳細窗格 選取該列後展開 Transmission Control Protocol,再打開其中的 SEQ/ACK analysis,就會顯示被判定為重送
時間差 把 Time delta from previous displayed packet 加成一欄,就能讀出該列距離前一個顯示的封包隔了幾秒。這裡會排出 1 秒、2 秒
SYN 的 Options 選取 SYN 那一列並展開 Options,看有沒有 Timestamps 這個項目,就知道有沒有 TSopt

典型的排列方式是這樣。先是相同 Seq 的那一列在 1 秒後出現,再過 2 秒又出現一次,最後那一列之後緊接著 ACK 回來,通訊便從這裡恢復正常來回。只要這段「空白的數秒」與應用程式日誌上回應停住的時間一致,原因大致就確定了。

在把日誌與封包對照時,還要留意應用程式時間與擷取時間的基準差。這裡一旦錯開,就很容易把不相干的事件當成原因。

在 Wireshark 上確定原因的流程說明用 tcp.stream 只留下目標連線,用時間差的欄位直接看停住的秒數,若那段空白的數秒與應用程式日誌上回應停住的時間一致就大致確定原因的流程的圖。是否用 tcp.stream 只留下目標連線用時間差的欄位看空白的秒數確認相同 Seq 的重送並排出現與應用程式的停頓時間一致?原因大致確定懷疑時刻基準差或其他因素

圖 14: 篩選、看時間差、互相對照。用這 3 步確定「空白的數秒」的真面目。

8. 大致的取捨

症狀 先懷疑的對象 最先要做的事
偶爾停頓數秒 TCP 的 RTO 等待 用封包確認重送與時間差
每次幾乎都在同一個時機停住 應用程式內部的等待、設備端處理、固定的逾時值 查看執行緒、SDK 呼叫與設備日誌
只有高負載時惡化 CPU、GC、佇列塞住 查看 CPU、中斷、記憶體與佇列長度
大範圍的連線一起變差 物理層、交換器、中介設備 查看 NIC、網路線、連接埠統計與中介設備日誌
改了設定卻沒有變化 TCP option 根本沒有協商成功 重新確認 SYN / SYN-ACK

最後一列真的很常見。動了設定的滿足感,和 wire 上實際被採用的事實,是兩回事。

9. 總結

這次的重點:

  • 「偶爾停上幾秒」有時不是應用程式停住,而是 TCP 的重送等待
  • 停頓時間與 RTO 的等待方式吻合,而且看得到 Retransmission,方向就相當對
  • TCP timestamps option 是 RTTM 與 PAWS 的機制,可以消除重送時 RTT 量測的模糊
  • 在這個案例中,啟用 RFC1323 系的 timestamp 之後,RTO 停留在過度保守狀態的時間被壓下來了

想避免的做法:

  • 只憑應用程式日誌就認定通訊停頓的原因
  • 只看 OS 設定,不看實際封包
  • 以為啟用 timestamp 就連遺失的原因也一併消失

實務上有效的做法:

  • 先看 wire
  • 確認重送與等待時間的形狀
  • 確認 TSopt 的協商
  • 改善之後,遺失來源與應用程式設計仍要另外追究

也就是說,這類缺陷「先鎖定卡在哪裡等」比「讓它變快」更優先。只要這一點沒有偏掉,調查就會縮短很多。

10. 參考資料

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

在整理與改善方式上相近的案例頁面。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

常見問題

整理諮詢這個主題時常見的問題。

什麼是 TCP Retransmission(TCP 重送)?
這是當送出的封包等不到 ACK(確認回應)時,TCP 再次送出相同資料的機制。封包在途中某處被丟掉,送出端就會等 ACK,等不到時便等重送計時器(RTO)到期後才重送。從應用程式的角度看像是「停了幾秒」,但以 TCP 的角度來說只是「ACK 還沒回來,所以在等重送計時器到期」,這種停頓方式其實相當常見。在封包擷取中可以觀察到它被標示為 TCP Retransmission。
造成 TCP Retransmission 的原因是什麼?
直接的觸發點是封包遺失,因為等不到 ACK 才會發生重送。至於遺失的來源,必須分別檢視物理層(網路線與連接埠)、NIC 及其驅動程式與卸載設定,以及交換器或中介設備的問題。另外,啟用 TCP timestamps 之類的做法確實可以壓縮重送之後的等待時間,但那不是消除遺失本身的魔法,因此遺失來源仍要另外調查。也有中介設備破壞或丟棄 TCP 選項的情況,甚至有主因根本不在 TCP,而是設備端處理停住的情況。
為什麼 TCP 重送會讓通訊停上好幾秒?
因為 TCP 的重送計時器(RTO)採取保守的等待方式。RFC 6298 中初始 RTO 以 1 秒為基準,計算結果比它小也會向上取到 1 秒,而且每發生一次逾時就加倍。因此條件一差,就會出現 1 秒、2 秒、4 秒這樣的等待。在以小型 request/response 為主的控制通訊中,還沒累積到足夠的 duplicate ACK 去觸發 fast retransmit,RTO 等待就先浮上檯面,於是表現為偶發的數秒停頓。啟用 TCP timestamps option 之後,有機會消除重送時 RTT 量測的模糊,縮短 RTO 估計停留在過度保守狀態的時間。
要用 Wireshark 調查 TCP Retransmission 該怎麼做?
顯示過濾器可以用 tcp.analysis.retransmission、tcp.analysis.fast_retransmission、tcp.analysis.lost_segment 等等。先用 tcp.stream 只留下目標連線,再把 Time delta from previous displayed packet 顯示出來直接查看停頓了幾秒,然後看問題發生的瞬間有沒有出現 Retransmission、重送前的時間差是否與停頓時間一致。至於是否真的用上 TCP timestamps,則要看連線開始時的 SYN / SYN-ACK 有沒有協商 TSopt。比起設定畫面顯示為已啟用,實際封包上帶著 TSopt 這個事實更重要。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽