【計算機網路筆記】3.7 TCP Congestion Control

Hello Guys, I’m LukeTseng. 歡迎你也感謝你點入本篇文章,本系列主要讀本為《Computer Networking: A Top-Down Approach, 8th Edition》,就是計算機網路的聖經,會製作該系列也主要因為修課上會用到。若你喜歡本系列或本文,不妨動動你的手指,為這篇文章按下一顆愛心吧,或是追蹤我的個人公開頁也 Ok。

3.7.1 Classic TCP Congestion Control(經典 TCP 壅塞控制)

TCP 壅塞控制(Congestion Control)是 TCP 協定中用來避免發送端把整個網路癱瘓的一套機制,與流量控制(Flow Control)不同,它保護的對象是網路而非接收端。

網路資源是共享的,如果每個終端系統(End System)的 Process 都毫無節制把資料塞入網路中,會導致路由器的 buffer 溢位,進而造成封包大量遺失,最終引發壅塞崩潰(Congestion collapse),讓所有人的吞吐量(Throughput)都降為零。

在此,經典 TCP 壅塞控制採用的是端到端(End-to-end)的壅塞控制,表示 IP 網路層並不會提供明確的壅塞警告給協定,TCP 只能依靠觀察封包遺失(Timeout 或收到三個重複的 ACK)來推測網路是否發生壅塞。

TCP 的壅塞控制可以想成是一個不斷在試探底線的過程,主要遵循三個基本原則:掉封包就減速、收到 ACK 就加速、不斷試探直到掉封包為止。

術語解析

  • 遺失事件(Loss Event):TCP 用來判斷網路壅塞的唯一訊號,包含兩種情況:
    1. 逾時(Timeout)
    2. 收到三個重複的 ACK。
  • 壅塞視窗(congestion window):以 cwnd 表示。限制 TCP 傳送端在尚未收到 ACK 前,可以送出多少未確認的 Byte 或 Bit 進入連結(Link),傳送端的傳輸速率大約為 cwndRTT\frac{cwnd}{RTT} bytes/sec。
  • 緩啟動門檻(slow start threshold):以 ssthresh 縮寫表示。當 cwnd 小於這個值時,TCP 處於緩啟動階段;當 cwnd 大於等於這個值時,TCP 進入壅塞迴避(Congestion Avoidance)階段。

緩啟動(Slow Start)

當一個 TCP Session 剛建立(完成三次握手(Three-way handshake))時,TCP 想要盡快摸清網路的極限,但又不敢一開始就送太多,所以才稱為緩啟動。

  • 初始狀態:
    • cwnd 值通常被設為 1 MSS。[RFC 3390]
    • 承上,這樣設使得初始傳輸速率大約是 MSS/RTT。
      • 如:假設 MSS = 500 bytes, RTT = 200 ms,則得到的速率為 20 kbps。
  • 增長行為:每當所傳輸的區段得到第一次確認,增加 1 MSS。
  • 指數級成長:
    • 下圖 3.51 中:
      • TCP 會將第一筆 segment 送入網路,然後等待確認,當該筆確認訊息抵達時,TCP 傳送端會將壅塞視窗 +1 MSS。
      • TCP 接著送出兩份大小調整至最大的 segment,然後這兩份 segment 也得到確認,接著 TCP 又把這兩份個別給它的壅塞視窗 +1 MSS,然後就得到大小為 4 MSS 的壅塞視窗,以此類推。
    • 這會導致 cwnd 在每個 RTT 呈指數級增長(1, 2, 4, 8...),雖然叫緩啟動,但它的增長速度其實非常快,只是起點很低而已。
  • 這種指數級成長何時結束?
    1. 發生逾時(Timeout),即壅塞情況:cwnd 歸零重設為 1ssthresh 設為發生壅塞時 cwnd 的一半。
    2. 達到門檻(cwnd ≥ ssthresh):切換至壅塞迴避(Congestion Avoidance)模式。
    3. 收到三個重複的 ACK:切換至快速復原(Fast Recovery)模式。

image

Image Source:Computer Networking: A Top-Down Approach (8th ed., p. 296, Figure 3.50)

image

Image Source:Computer Networking: A Top-Down Approach (8th ed., p. 298, Figure 3.51)

壅塞迴避(Congestion Avoidance)

cwnd 達到 ssthresh 時,代表可能快要逼近網路極限了,此時必須踩一點煞車,改為穩紮穩打的策略。

也就是增長行為更改(從原本指數成長變線性成長):每個 RTT 期間,不管收到多少個 ACK,cwnd 總共只增加 1 個 MSS,這是一種線性增長。

每個 RTT 增加 1 MSS的動作,通常是透過分散在每一個收到的 ACK 來達成的。

具體的做法是每當發送端收到一個新的 ACK,就會將 cwnd 增加 MSS * (MSS / cwnd) 個位元組。

例子

假設 MSS 為 1,460 bytes,目前的 cwnd 為 14,600 bytes(剛好是 10 個 MSS 的大小)。

由於上述條件,因此在一個 RTT 內,發送端大約會送出 10 個區段。

每收到一個區段的 ACK,cwnd 就會增加 1/10 個 MSS(即 146 bytes),當這 10 個區段的 ACK 在一個 RTT 內全數被收到後,cwnd 剛好累計增加了 1 個完整的 MSS。

結束條件與對遺失事件的反應

壅塞迴避的線性增長會一直持續,直到 TCP 發送端偵測到遺失事件(Loss Event)發生,代表網路已經出現了實質的壅塞。

TCP 會根據遺失事件的種類,採取不同的降速與狀態切換策略:

  1. 發生逾時(Timeout):逾時代表封包遺失非常嚴重,網路可能處於極度壅塞的狀態。
    • 遇到這種情況,TCP 的反應與在緩啟動時完全相同:它會將 ssthresh 更新為發生遺失時 cwnd 值的一半,並將 cwnd 重設為 1 個 MSS,然後重新開始緩啟動階段。
  2. 收到三個重複的 ACK:收到三個重複的 ACK 代表某個封包遺失了,但網路仍能將後續的封包送達接收端,情況不如逾時那麼糟。
    • 此時 TCP 會將 ssthresh 設為當前 cwnd 的一半,接著將 cwnd 減半(再加上 3 個 MSS,以補償那三個已經離開網路到達接收端的重複 ACK 封包),並切換成快速復原(Fast Recovery)狀態。

AIMD 特性與鋸齒狀曲線

若忽略發生機率較低的逾時(Timeout)事件,並假設網路封包遺失主要由「三個重複的 ACK」來觸發,那 TCP 在壅塞迴避階段的行為可以總結為:

  1. 沒遇到壅塞時:每個 RTT 線性增加 1 個 MSS(Additive Increase, 累加遞增)。
  2. 遇到壅塞時:將 cwnd 減半(Multiplicative Decrease, 倍數削減)。

這套機制稱為 AIMD(Additive-Increase, Multiplicative-Decrease)壅塞控制。

這就解釋了為什麼 TCP 的傳輸速率隨時間變化時,在圖表上會呈現出鋸齒狀的曲線。

正是 TCP 不斷試探網路可用頻寬(直到發生掉封包為止),接著退讓,然後再次重新試探的行為,造成了鋸齒狀的曲線。

快速復原(Fast Recovery)

前面說過,這是用來處理收到三個重複 ACK的特殊狀態,收到重複 ACK 代表封包雖然亂序或遺失,但網路還有能力把後續的封包送達,情況沒有逾時那麼糟。

此時,TCP 會執行以下動作:

  1. 將緩啟動門檻 ssthresh 設定為當前 cwnd 的一半:ssthresh = cwnd / 2
  2. cwnd 的值設定為新的門檻值加上 3 個 MSS:cwnd = ssthresh + 3 * MSS
  3. 執行快速重傳,把那個疑似遺失的封包重送出去。

+ 3 * MSS 是因為收到了 3 個重複的 ACK,就表示有 3 個後續的封包已離開網路、抵達接收端的緩衝區了,既然網路騰出了 3 個封包的空間,就要在視窗上補回這 3 個空間。

快速復原狀態:持續收到重複 ACK

進入快速復原後,在尚未收到新資料的 ACK 前,發送端可能會繼續收到針對同一個遺失封包的重複 ACK(因為接收端可能還在消化後續的失序封包)。

  • 動作:每收到一個重複的 ACK,就把 cwnd 增加 1 個 MSS:cwnd = cwnd + 1 * MSS
  • 結果:如果 cwnd 膨脹後允許發送新的資料,TCP 就會繼續把新的封包送進網路中,保持資料流的連續性,而非停下來空等。

退出快速復原狀態:收到新的 ACK 或逾時

要結束快速復原的狀態,會遇到兩種情形:

  1. 最好的情況(收到新的 ACK):剛剛提早重傳的封包抵達,接收端回傳了一個確認新資料的 ACK。此時,TCP 會將 cwnd 降回剛剛記下的 ssthreshcwnd = ssthresh),稱為視窗收縮,然後切回壅塞迴避(Congestion Avoidance)狀態。
  2. 最壞的情況(發生 Timeout):如果在快速復原期間計時器逾時了,就代表網路已造成壅塞,TCP 會立刻將 ssthresh 設為當前 cwnd 的一半,然後把 cwnd 指定為 1 個 MSS,並切回緩啟動狀態。

TCP Tahoe、TCP Reno

TCP Tahoe 是較早期的保守版本,遇到任何壅塞都會讓速率歸零。

而 TCP Reno 則是引入了快速復原機制的現代版本,能區分壅塞的嚴重程度並做出更平滑的降速。

透過了解 Tahoe 與 Reno 的差異,能讓我們深刻體會到區分錯誤類型對於提升網路整體效能有多麼大的影響。

TCP Reno 解決了 Tahoe 過度反應的問題,成為了後來許多 TCP 版本的基礎,並創造了我們熟知的鋸齒狀效能特徵,但兩者都是基於封包遺失來判斷壅塞的,這是一種被動的探測方式。

連線建立初期

:::info
註:傳輸回合(Transmission Round):發送端送出一批封包,並等待接收端回傳 ACK 的一個 RTT 週期。
:::

在連線剛開始時,Tahoe 和 Reno 的行為是完全一模一樣的:

  1. 緩啟動:假設初始的緩啟動門檻 ssthresh 設為 8 個 MSS,兩者都會從 cwnd = 1 開始,呈指數型增長(1, 2, 4, 8)。
  2. 壅塞迴避:到了第 4 個傳輸回合,cwnd 觸碰到了門檻 8,於是切換成線性增長的壅塞迴避模式。
  3. 發生壅塞:隨著每個回合加 1,到了第 8 個回合結束時,cwnd 爬升到了 12 個 MSS,這時網路塞車了,發送端收到了三個重複的 ACK。

3 個重複 ACK 的不同選擇

cwnd = 12 時收到三個重複 ACK,Tahoe 與 Reno 會有截然不同的選擇:

  • TCP Tahoe:只要掉封包,TCP Tahoe 就認為網路嚴重壅塞。
    1. ssthresh 設為當前 cwnd 的一半,也就是 12/2=6 MSS。
    2. 無條件將 cwnd 砍到剩下 1 個 MSS。
    3. 從頭開始緩啟動,以指數增長爬回 6,然後再慢慢線性增加。
  • TCP Reno:Reno 知道三個重複 ACK 代表網路其實還有流動性,啟動了快速復原機制。
    1. 同樣將 ssthresh 設為當前 cwnd 的一半,即 6 MSS。
    2. 減半微調:將 cwnd 設為新的 ssthresh 加上 3 個 MSS 來補償已經抵達的封包,所以 cwnd 變成 6+3=9 MSS。
    3. 進入快速復原,等收到新的 ACK 後,視窗降回 6,並直接進入壅塞迴避的線性增長,免去從 1 慢慢爬的痛苦。

下圖是 TCP 壅塞視窗的變化過程(Tahoe 與 Reno):

image

Image Source:Computer Networking: A Top-Down Approach (8th ed., p. 300, Figure 3.52)

下圖是 TCP 壅塞視窗的變化過程(Tahoe 與 Reno):

image

Image Source:Computer Networking: A Top-Down Approach (8th ed., p. 301, Figure 3.53)

TCP Tahoe vs. TCP Reno

觸發事件TCP TahoeTCP Reno
遇到逾時1. ssthresh 減半。
2. cwnd 降回 1 MSS。
3. 進入緩啟動
1. ssthresh 減半。
2. cwnd 降回 1 MSS。
3. 進入緩啟動
遇到 3 個重複 ACK 時1. ssthresh 減半。
2. cwnd 降回 1 MSS。
3. 進入緩啟動
1. ssthresh 減半。
2. cwnd 設為 ssthresh + 3。
3. 進入快速復原。
吞吐量曲線特徵頻繁跌至谷底(1 MSS),傳輸效能起伏劇烈。呈現鋸齒狀,效能維持在高水準。

註:只有當發生真正嚴重的逾時,Reno 才會做出和 Tahoe 一樣退回 1 MSS 的決策。

TCP Cubic

TCP Cubic 是 TCP Reno 的改良版,它在壅塞迴避階段不再用傳統的線性增長,而是利用三次函數(Cubic function)來動態調整壅塞視窗,以更聰明、更快速的方式逼近網路極限。

在傳統的 TCP Reno 中,一旦遇到掉封包(表示塞車),傳送速率就會直接砍半,接著每個 RTT 才慢吞吞地加 1 個 MSS。

在現代高頻寬的 Link 中,這種線性增加要爬回原本的高速狀態會花費太長的時間,導致網路頻寬被白白浪費、整體吞吐量(Throughput)難以提升。

TCP Cubic 現已被廣泛部署,且是 Linux 作業系統預設的 TCP 協定(Protocol)。

術語解析

  • WmaxW_{max}(Maximum Window):TCP 發生封包遺失(偵測到壅塞)那一瞬間的壅塞視窗大小,代表網路發生壅塞的臨界點。
  • tt(Current Time):從上一次發生封包遺失後,到目前為止所經過的時間。
  • KK(Target Time):一個未來的目標時間點,代表 Cubic 預計要在哪一刻讓壅塞視窗大小剛好恢復到原本的 WmaxW_{max},這個 KK 值是透過 Cubic 內部的參數計算出來的。

技術原理細節

TCP Cubic 和 TCP Reno 其實是親兄弟,兩者在緩啟動與快速復原階段的行為完全相同。

唯一的差異在於它們如何處理壅塞迴避。

Cubic 的壅塞視窗大小是時間 tt 與目標時間 KK 之間距離的三次函數(Cubic),這個數學特性能產生三個增長階段:

  1. 快速恢復期:當剛發生壅塞、視窗被砍半後,此時時間 tt 距離目標時間 KK 還很遙遠(tKt≪K),既然離極限 WmaxW_{max} 還很遠,Cubic 會大幅增加視窗大小,讓速率用最快的速度飆升,彌補了 Reno 爬升太慢的缺點。
  2. 平穩試探期:當時間 tt 越來越接近 KK 時(tKt≈K),代表目前的速率已快要逼近上次發生塞車的臨界點 WmaxW_{max} 了,此時三次函數的曲線會變平緩,Cubic 會變得非常謹慎,讓視窗大小緩慢地增加,試著在不觸發壅塞的情況下,盡可能地維持在最佳的高速狀態。
  3. 最大試探期:如果時間 tt 已經超過了 KKt>Kt>K),代表網路的狀況可能已經改變(或許別人讓出了頻寬),極限已經不再是以前的 WmaxW_{max} 了,此時三次函數的曲線會再次向上陡升,Cubic 會快速增加視窗大小,去尋找網路新的極限。

下圖是 TCP 壅塞迴避發送率(細線是 TCP Reno,粗線是 TCP CUBIC,可看見三次函數的特性能迅速爬升到一定高度後,又趨於平緩,不像線性增長的 TCP Reno 要花比較久時間):

image

Image Source:Computer Networking: A Top-Down Approach (8th ed., p. 302, Figure 3.54)

TCP Reno vs. TCP Cubic

比較項目TCP Reno(傳統)TCP CUBIC(現代)
壅塞迴避的增長方式線性增加(每個 RTT 加 1 MSS)三次函數增加(根據時間 ttKK 的距離)
恢復到 WmaxW_{max} 的速度慢(受限於 RTT 的長度)快(在初期大幅拉升)
逼近極限時繼續線性增加,直到掉封包趨緩,維持在 WmaxW_{max} 附近
對 RTT 的依賴性高(RTT 越長的連線,爬升越吃虧)較低(增長幅度主要與絕對時間 tt 相關,而非 RTT 回合數)
圖形特徵鋸齒狀圓滑的三次曲線(有平緩的停頓區間)

可以把 TCP Reno 想像成是一個死踩著油門的駕駛,直到看到快被撞上(封包遺失)了才煞停。

而 TCP Cubic 就像是自動駕駛或技術高超的駕駛,再當離前車很遠時(tKt ≪ K)猛踩油門,快接近前車時(tKt≈K)放開油門滑行,發現前車加速開走時(t>Kt>K)又再次踩下油門。

3.7.2 Network-Assisted Explicit Congestion Notification and Delayed-based Congestion Control(網路輔助的顯性壅塞通知與基於延遲的壅塞控制)

在此之前 TCP 的緩啟動、壅塞迴避都是被動的,也就是都不是從 Network Layer 接收到明確的壅塞指示,而是透過觀察封包是否遺失來判斷有沒有壅塞。

在這節要探討的是主動式的壅塞控制機制,透過網路層路由器主動發送警告(ECN),或是由發送端自己觀察網路延遲的變化(Delay-based),在封包真正遺失之前就提早降低傳送速率。

這些現代機制廣泛應用於現代資料中心(Data Center)或像是 Google 的 B4 骨幹網路中,但 ECN 的限制在於它需要網路路徑上的路由器(Network-layer)和終端系統(End System)的協定(Protocol)共同支援才能運作。

術語解析

  • 顯式壅塞通知(Explicit Congestion Notification, ECN):一種由路由器主動標記 IP 資料包,用來警告接收端與發送端網路快塞爆了的機制。
  • 顯式壅塞通知回應(Explicit Congestion Notification Echo, ECE):TCP 接收端用來告訴發送端「我收到路由器的塞車警告了」的 TCP 標頭位元。
  • 壅塞視窗縮減(Congestion Window Reduced, CWR):TCP 發送端用來回覆接收端「我已經收到警告並降速了」的 TCP 標頭位元。
  • 基於延遲的壅塞控制(Delay-based Congestion Control):發送端不靠路由器警告,而是自己測量封包的往返時間(RTT),若發現延遲變高,就推測網路快要塞車並提早降速的機制。

顯式壅塞通知(Explicit Congestion Notification, ECN)

ECN 打破了以往網路層(IP)不介入傳輸層(TCP)壅塞控制的規矩,其運作流程如下:

  1. 協商與標記(Negotiation & Marking):
    • 首先,發送端會利用 IP 資料包標頭的服務類型(Type of Service, TOS)欄位中的 2 個位元,來告訴網路中的路由器:「我是支援 ECN 機制的喔」。
    • 當路由器發現自己的緩衝區快要滿了(但還沒滿到要丟棄封包時),它會修改 IP 資料包 TOS 欄位中的 ECN 位元,作為壅塞即將發生的警告。
  2. 接收端代為傳話(Receiver Echo):
    • 帶有警告標記的 IP 資料包抵達目的地的接收端後,接收端必須把這個警告轉達給發送端。
    • 接收端會在下一個回傳給發送端的 TCP ACK 區段中,將 ECE(Explicit Congestion Notification Echo)位元設為 1。
  3. 發送端降速(Sender Reaction):
    • 發送端收到帶有 ECE 標記的 ACK 後,會採取與快速重傳(收到三個重複 ACK)一樣的動作:將壅塞視窗(cwnd)減半。
    • 接著,發送端會在下一個送出的 TCP 區段中,將 CWR(Congestion Window Reduced)位元設為 1,告訴接收端:「放心,我已經減速了」。

image

Image Source:Computer Networking: A Top-Down Approach (8th ed., p. 305, Figure 3.55)

除了經典的 TCP 之外,ECN 機制也被廣泛應用於其他傳輸層協定中(如 DCCP、DCTCP、DCQCN),幫助它們在發生丟包前就能提早降速。

:::info
資料包壅塞控制協定(Datagram Congestion Control Protocol, DCCP):一種提供類似 UDP 般不可靠(Unreliable)傳輸服務的協定,但它額外加入了壅塞控制機制,並且支援使用 ECN 來控制發送速率。

資料中心 TCP(Data Center TCP, DCTCP):專為現代巨型資料中心內部網路設計的 TCP 變體,它依賴 ECN 訊號來維持極低的交換器緩衝區占用率,從而實現微秒級的超低延遲。

資料中心量化壅塞通知(Data Center Quantized Congestion Notification, DCQCN):一種專為資料中心設計的先進壅塞控制演算法,常用於 RDMA(遠端直接記憶體存取)技術中,同樣高度依賴 ECN 來運作。
:::

跨協定的 ECN 應用:

  1. DCCP 的輕量級控制:一般的影片或語音串流是用 UDP 傳送資料包(Datagram),掉了就算了,不需要重傳,但如果大家都在狂傳 UDP,網路就會崩潰。
    • DCCP 解決了此問題:它像 UDP 一樣不保證送達,但會看網路層傳來的 ECN 標記,如果發現網路快塞車了,DCCP 就會主動降低發送速率,做一個「有禮貌的」串流協定。
  2. DCTCP / DCQCN 的極致效能:在資料中心裡,成千上萬台伺服器在互相傳遞運算結果,對延遲的要求是 10610^{-6} 秒等級。
    • 傳統 TCP 遇到 ECN 是直接砍半速率(Multiplicative Decrease),這在資料中心會導致效能大幅震盪。
    • DCTCP 和 DCQCN 則是根據收到 ECN 標記的比例,來微調降速的幅度,藉此將交換器的佇列(Queue)維持在極短的狀態。

傳輸層協定特性比較表

協定名稱傳輸可靠性是否具備壅塞控制?是否支援/依賴 ECN?主要應用
傳統 UDP不可靠(Unreliable)一般的 DNS、傳統語音視訊
傳統 TCP可靠(reliable)支援(但非必須)網頁瀏覽(HTTP)、檔案傳輸
DCCP不可靠(Unreliable)支援(高度利用)具備流量控制的即時串流
DCTCP可靠(reliable)強烈依賴現代巨型資料中心內部網路

基於延遲的壅塞控制(Delay-based Congestion Control)

如果路由器不支援 ECN 怎麼辦?發送端可以靠自己測量延遲來預測塞車,最經典的代表是 TCP Vegas。

  • 測量基準:TCP Vegas 傳送端會測量所有已確認封包的來源到目的地端路徑的 RTT,並記錄下最小的那個值,稱之為 RTTminRTT_\text{min} ,這個值代表了網路「完全沒塞車、沒有排隊延遲」時的最快速度。
  • 計算理想吞吐量:在沒塞車(即無壅塞)的理想狀況下,連線的吞吐量(Throughput)應該會等於目前的壅塞視窗除以最小延遲:$$\frac{\text{cwnd}}{RTT_\text{min}}$$
  • 動態調整:
    • 如果發送端測量到的「實際吞吐量」跟上述的「理想吞吐量」很接近,代表網路上還沒什麼人在排隊,可以放心增加傳送速率。
    • 如果「實際吞吐量」顯著低於「理想吞吐量」,代表封包已經塞在路由器的隊伍裡了,此時發送端就會主動降低傳送速率。

這種機制秉持著一個設計哲學:“Keep the pipe just full, but no fuller”(讓管子剛好滿載,但不要更滿),保持滿載能確保高吞吐量,但不讓多餘的封包堆積在路由器,就能把延遲降到最低。

現代網路實務中的 BBR 演算法

基於 TCP Vegas 的理念,Google 團隊開發了 BBR(Bottleneck Bandwidth and Round-trip propagation time)演算法。

BBR 不僅能維持低延遲,還加入了一些機制讓它能與傳統的 TCP 傳輸流公平競爭,2016 年時 Google 已在他們龐大的 B4 內部資料中心骨幹網路,以及 YouTube 伺服器上廣泛部署 BBR 演算法。

經典 TCP vs. ECN vs. Delay-based TCP

比較維度經典 TCP(Tahoe / Reno / CUBIC)Network-Assisted ECNDelay-based TCP(Vegas / BBR)
壅塞判斷訊號封包遺失(Timeout 或 3個重複 ACK)路由器主動標記 IP 標頭(ECE bit)封包往返延遲(RTT)變高
反應時機已經塞車且掉封包後(被動)封包遺失前,緩衝區快滿時(主動)封包遺失前,隊伍開始變長時(主動)
網路層(IP)支援不需要(純端對端控制)需要(路由器必須支援 ECN 標記)不需要(純端對端測量)
效能特徵容易造成路由器緩衝區滿載,排隊延遲高減少掉封包機率,降低重傳成本致力於維持極低延遲(“Keep pipe just full”)

3.7.3 Fairness(公平性)

該節主要探討當多條 TCP 連線共同經過一個頻寬有限的瓶頸連結(Bottleneck Link)時,TCP 的壅塞控制演算法能夠自動讓每條連線大致均分該連結的頻寬。

網路是一個共享資源的環境,如果某些行程(Process)佔據了過多的頻寬,會導致其他使用者的服務品質嚴重下降。TCP 需要一套分散式的機制,在沒有中央主管指揮的情況下,讓大家自動達到資源共享的平衡。

而這種理想的公平性主要建立在「每條連線的網路延遲相似」且「大家都遵守 TCP 協定」的前提下,在現實的網際網路中,UDP 流量和惡意開啟多條平行連線的應用程式,都會打破公平性。

術語解析

  • 公平性(Fairness):假設有 KK 條 TCP 連線共同通過一個傳輸速率為 RR bps 的瓶頸連結,如果每條連線的平均傳輸速率都能逼近 R/KR/K,則稱該壅塞控制機制具備公平性。
  • 瓶頸連結(Bottleneck Link):在一條端對端(End-to-End)的網路路徑中,傳輸容量最小、最容易發生壅塞的那一段網路連結。
  • AIMD(Additive-Increase, Multiplicative-Decrease):TCP 核心的壅塞控制演算法,沒塞車時累加遞增(線性加速),塞車掉封包時倍數削減(速率砍半)。

AIMD 如何收斂至公平

為了方便理解,書中舉了一個只有兩條 TCP 連線(Connection 1 與 Connection 2)共享一條容量為 RR 的瓶頸連結的例子,並假設它們的 RTT 和最大區段大小(Maximum Segment Size, MSS)都相同。

image

Image Source:Computer Networking: A Top-Down Approach (8th ed., p. 307, Figure 3.56)

可把這兩條連線的吞吐量畫在一個二維座標圖上:X 軸是 Connection 1 的吞吐量,Y 軸是 Connection 2 的吞吐量。

  1. 理想的公平線(Equal bandwidth share):是從原點出發的 45 度對角線(即 X=Y),我們希望系統最終能落在這條線上。
  2. 累加遞增(Additive Increase):當兩者總和沒有超過 RR 時,兩條連線每個 RTT 都會各加 1 個 MSS,在圖上,代表兩者的吞吐量會沿著 45 度角(斜率為 1)往右上角爬升。
  3. 倍數削減(Multiplicative Decrease):當總和超過 RR 導致掉封包時,兩條連線的視窗大小都會除以 2,在圖上,相當於座標點直接朝著原點 (0,0)(0,0) 的方向縮減一半。

這會形成一個不斷向公平線逼近的鋸齒狀軌跡,不管這兩條連線一開始的速率差異有多大(例如 Connection 1 已經很快,Connection 2 剛啟動),只要經過幾次「撞牆砍半、都加 1」的循環,擁有較大頻寬的一方被扣除的絕對數值會比較大,而增加時大家又是一視同仁加 1,久而久之,兩者的速率就會自動收斂到 R/2R/2 的公平狀態。

image

Image Source:Computer Networking: A Top-Down Approach (8th ed., p. 308, Figure 3.57)

RTT 的差異

剛才的推導假設是大家的 RTT 一樣,但在真實的網際網路中,情況並非如此。

如果 Connection 1 的 RTT 比 Connection 2 小(代表 Connection 1 離伺服器較近),那 Connection 1 收發 ACK 的頻率就會比較高。

在同樣的時間內,Connection 1 執行 Additive Increase 的次數會比 Connection 2 多。

結果:RTT 較短的 TCP 連線能夠更快地搶佔釋放出來的頻寬,因此會獲得比長 RTT 連線更多的吞吐量(Throughput),這是不公平的一大來源。

破壞公平性的兩大元兇:UDP 與平行連線

  • UDP 流量:UDP 沒有內建壅塞控制。
    • 當網路塞車、TCP 將速率砍半時,UDP 依然會維持恆定速率繼續送資料包(Datagram),這會導致 TCP 的頻寬被 UDP 徹底擠壓、甚至霸佔。
    • 許多多媒體應用(如網路電話、視訊會議)寧可掉封包,也不願意因為降速而導致畫面卡頓延遲,進而導致公平性破壞。
  • 平行 TCP 連線(Parallel TCP Connections):應用程式不只開一條 TCP 連線,而是同時開啟多條(例如 11 條)。
    • 假設原先有 9 個用戶各開 1 條,你開了 11 條,那麼這條水管 R 就被切成 20 份,你一個人就獨佔了 11/20 的總頻寬。
    • 現代網頁瀏覽器為了加速載入網頁中的眾多圖片與物件,經常預設開啟多條平行 TCP 連線。

總整理

經典 TCP 壅塞控制(Classic TCP)

TCP 壅塞控制屬於端到端(End-to-end)機制,用來保護網路資源避免癱瘓。

主要遵循三個原則:

  1. 掉封包就減速
  2. 收到 ACK 就加速
  3. 不斷試探直到掉封包。

術語:

  • 遺失事件(Loss Event):網路壅塞的唯一訊號,分為逾時(Timeout)與收到 3 個重複 ACK。
  • 壅塞視窗(cwnd):傳送端在未收到 ACK 前能送出的最大資料量,傳輸速率約為 cwndRTT\frac{cwnd}{RTT} bytes/sec。
  • 緩啟動門檻(ssthresh):判斷 TCP 該處於緩啟動或壅塞迴避階段的分水嶺。

運作三階段:

  1. 緩啟動(Slow Start):起始狀態,cwnd 預設為 1 MSS。每收到一個 ACK,cwnd 增加 1 MSS,每個 RTT 呈指數級成長。
  2. 壅塞迴避(Congestion Avoidance):當 cwnd 達到 ssthresh 時觸發,改為線性成長(每個 RTT 總共增加 1 MSS),呈現出 AIMD(累加遞增、倍數削減)特性與鋸齒狀效能曲線。
  3. 快速復原(Fast Recovery):收到 3 個重複 ACK 時觸發,ssthresh 減半,cwnd 設為 ssthresh + 3 MSS,收到新資料 ACK 時退回壅塞迴避,若逾時則跌回緩啟動狀態。

TCP 版本演進比較

比較項目TCP Tahoe(早期保守版)TCP Reno(現代基礎版)TCP CUBIC(現代改良版 / Linux 預設)
遇到逾時cwnd 歸零重回 1 MSS,進入緩啟動與 Tahoe 相同與 Reno 相同
遇到 3 個重複 ACKcwnd 歸零重回 1 MSS,進入緩啟動啟動快速復原,降速更平滑啟動快速復原
壅塞迴避增長方式線性增加線性增加三次函數增加(基於時間與目標點距離)
圖形特徵頻繁跌至谷底,起伏劇烈鋸齒狀圓滑的三次曲線(平緩停頓與快速爬升)
恢復極限(Wmax)速度慢(受限於 RTT)快(不受限於 RTT,能迅速拉升速率)

主動式壅塞控制(網路輔助與 Delay-based)

傳統 TCP 必須等到掉封包才知道塞車,現代資料中心或骨幹網路則採用主動降速機制。

顯式壅塞通知(ECN)

需要網路層路由器與終端系統共同支援,在封包遺失前主動警告。

  • 路由器標記:緩衝區快滿時,修改 IP 標頭 TOS 欄位的 ECN 位元。
  • 接收端傳話:收到標記後,在下一個回傳的 TCP ACK 中將 ECE 位元設為 1。
  • 發送端降速:收到 ECE 警告後,將 cwnd 減半,並在下一個區段將 CWR 位元設為 1 確認已降速。
  • 應用協定:DCCP(具備壅塞控制的 UDP)、DCTCP / DCQCN(資料中心專用,依賴 ECN 微調降速以維持極低延遲)。

基於延遲的壅塞控制(Delay-based)

不依賴路由器,由發送端自行測量延遲(如 TCP Vegas、Google BBR)。

  • 運作原理:紀錄無塞車時的最小延遲 RTTminRTT_{min},計算出理想吞吐量 cwndRTTmin\frac{cwnd}{RTT_{min}}
  • 動態調整:若實際吞吐量遠低於理想吞吐量,代表封包正在路由器排隊,提早主動降速以維持極低延遲(保持管子剛好滿載)。

公平性 (Fairness)

KK 條 TCP 連線共享傳輸容量為 RR 的瓶頸連結時,理想狀態下每條連線應均分頻寬(速率逼近 R/KR/K)。

AIMD 如何收斂至公平連線

在沒塞車時大家都線性加 1(累加遞增)與塞車時大家速率皆除以 2(倍數削減)的循環下,擁有較大頻寬的一方被扣除的絕對數值較大,最終圖表軌跡會自動逼近公平狀態的斜線。

破壞公平性的兩大元兇

  • RTT 差異:RTT 較短的連線收發頻率高,執行線性增加的次數多,能更快搶佔釋放的頻寬。
  • UDP 與平行連線:
    • UDP 流量:不具備壅塞控制,塞車時不降速,會霸佔守規矩降速的 TCP 頻寬。
    • 平行 TCP 連線:應用程式若同時開啟多條 TCP(如瀏覽器預設行為),將直接瓜分並獨佔更多的總頻寬比例。