重送逾時(retransmission timeout)
當你寄出一封信並期待回覆時,你會等上一段合理的時間,才認定它遺失了並再寫一封。等太短,你會去煩一個只是回得慢的人;等太久,你會為一封真的消失了的信白白浪費好幾天。重送逾時(retransmission timeout,RTO)正是 TCP 對這個兩難的答案:在認定一個封包已遺失而重送之前,要等確認等多久。
TCP 不能用固定的計時器,因為往返時間變化極大——在一個房間內是幾毫秒,跨越一片海洋是數百毫秒,而且隨著佇列堆積分分鐘都在變。所以它從自己的 RTT 量測中自適應地計算 RTO:大約是平滑後的平均 RTT,加上一個與 RTT 波動幅度(RTT 變異)成比例的寬裕餘量。經典公式是 RTO = SRTT + 4 × RTTVAR,其中 SRTT 是平滑後的 RTT。這個餘量很重要:把 RTO 設得只比平均高一絲,就會對每個稍微慢一點的封包都觸發,所以要把它留在舒適地高出許多的位置,以避免誤報。
另有兩個細節讓 RTO 更穩健。第一,指數退避:每當計時器觸發、而重送的封包又同樣沒被確認,TCP 就把 RTO 加倍——1 秒、2 秒、4 秒、8 秒——這樣在嚴重斷線期間它會退讓,而不是猛敲一條死路。第二,逾時被當成最強烈的壅塞信號:當 RTO 觸發,TCP 把壅塞視窗一路崩落到一個封包並重新進入慢啟動,遠比三重重複 ACK 遺失所用的溫和砍半激烈得多。TCP 認定,沉默意味著有什麼大大地出錯了。
假設 SRTT 穩定在 100 毫秒、RTTVAR 為 20 毫秒;那麼 RTO = 100 + 4 × 20 = 180 毫秒。一個封包送出去,180 毫秒內沒有任何回音,於是 TCP 重送它、把 cwnd 降到 1、並開始慢啟動。若那次重送也逾時,RTO 加倍到 360 毫秒,再到 720 毫秒,依此類推——在路徑持續沉默期間進行指數退避。
RTO 隨量測到的 RTT 加上變異餘量而調整,遇到反覆遺失就加倍,並觸發最嚴厲的 cwnd 重置。
逾時的懲罰遠比快速重傳重:它把 cwnd 打到 1 並重跑慢啟動,而三重重複 ACK 遺失只透過快速恢復把視窗砍半。這正是 TCP 努力靠重複 ACK 偵測遺失、並把逾時當成最後手段的原因——也是為何即使只有一次逾時,都可能嚴重損及一次長傳輸的吞吐量。