TCP協議探究(三):RTT、滑動窗口和阻塞處理


1 RTT算法

1.1 概述

  • 上一節說了重傳機制需要設置一個重傳超時值(RTO,Retransmission TimeOut),RTO設長了,重發太慢;設短了,可能導致包沒有丟,就重發了,可能導致雪崩效應(重發多,失敗多,失敗多,導致更多的重發...請參考: 暴風門事件)。

  • 那么該值怎么設置?

    • 由於一開始無法確定設置某個值,所以需要程序自動適應,動態地去設置
    • RTT,Round Trip Time,設置的參考值為數據報來回所需要的時間

1.2 經典算法

  • 采樣最近幾次的RTT

  • SRTT計算(Smoothed RTT):α (加權移動平均)取值在0.8 到 0.9之間
    $$
    SRTT = ( α * SRTT ) + ((1- α) * RTT)
    $$

  • 計算RTO:UBOUND為最大RTT(上限值),LBOUND為最小RTT(下限值),β 值一般在1.3到2.0之間
    $$
    RTO = min [ UBOUND, max [ LBOUND, (β * SRTT) ] ]
    $$

1.3 Karn / Partridge 算法(SRTT算法的優化)

  • 經典算法的問題:
    • 原始 + 重傳 + ACK = 總時間作為RTO,算長了(特殊情況)
    • 重傳 + ACK = 總時間作為RTO,算短了(特殊情況)

img

  • 該算法的最大特點:忽略重傳,不把重傳作為采樣

1.4 Jacobson / Karels 算法

  • 忽略重傳的問題:

    • 在某一時間,網絡閃動,突然變慢了,產生了比較大的延時,這個延時導致要重傳所有的包(RTO設置的比較小)
    • 但是由於重傳不會重新更新RTO,導致一直丟包,一直重試了。
  • SRTT算法以及優化都逃不出RTT有一個大的波動的話,很難被發現,所以需要綜合考慮。

  • 公式:

SRTT = SRTT + α (RTT – SRTT) —— 計算平滑RTT
DevRTT = (1-β)DevRTT + β(|RTT-SRTT|) ——計算平滑RTT和真實的差距(加權移動平均)
RTO= µ * SRTT + ∂ *DevRTT —— 神一樣的公式
# 在Linux下,α = 0.125,β = 0.25, μ = 1,∂ = 4 —— nobody knows why, it just work.

2 滑動窗口

2.1 概述

  • 第一節說過TCP可靠性的保證之一就是流量控制(Flow Control)
  • TCP需要知道現在網絡的數據處理速度,才能更好防止丟包,而流量控制就是為了測量現在的網絡數據處理速度的。
  • TCP報頭有一個字段:窗口,該字段是接收端告知發送端自己的緩沖空間,防止發送端發送太快緩沖區溢出。

2.2 緩沖空間

img

  • 其實類似java的NIO中的ByteBuffer
  • 發送端
    • LastByteWritten:上層應用可寫入的位置
    • LastByteSent:正在發送的位置
    • LastByteAcked:已經收到ACK的位置
    • LastByteAcked ~ LastByteSent區間:表示已經發送但是未收到ACK的數據
    • LastByteSent ~ LastByteWritten區間:表示未發送出去的數據
  • 接收端
    • LastByteRead:TCP緩沖區中讀到的位置
    • NextByteExpected:收到的連續包的最后一個位置
    • LastByteRcved:收到的包的最后一個位置
    • NextByteExpected ~ LastByteRcved區間:未到達的數據區間
    • LastByteRead ~ NextByteExpected區間:已收到的數據區間
  • 接收端回復
    • ACK中會匯報自己的Window = MaxRcvBuffer – LastByteRcvd – 1(只剩下這么多的空間能裝新的數據)
    • 發送方會根據窗口來控制發送數據的大小,以保證接收方可以處理

2.3 滑動窗口

(1)發送方滑動窗口示意圖:

img

  • #1 已收到ACK確認的數據
  • #2 已發送到未收到ACK確認的數據
  • #3 在窗口中未發出的(接收方還有空間)
  • #4 窗口以外的數據(接收方沒有空間)
  • 其中#2 + #3的黑框就是滑動窗口
(2)發送方滑動后的滑動窗口示意圖:

img

  • 紅色是已經新收到ACK的數據
  • 綠色是新加入滑動窗口的數據
(3)接收端控制發送端的圖示:

img

(4)Zero Window(堅持定時器實現):
  • 上圖一個處理緩慢的Server將Client的TCP 滑動窗口給降到0.
  • 降到0之后,發送端發送Zero Window Probe包(ZWP)給接收方,讓接收方ACK它的Window尺寸,一般發送3次,每次30~60秒。
  • 連續3次為0,有些TCP Client將發送RST把連接斷開。
(5)Silly Window Syndrome(糊塗窗口綜合症)
  • 由於處理緩慢的Server把TCP接收方的滑動窗口不斷降低,導致滑動窗口很少(如:4個字節),此時發送端仍然義無反顧的發送。

  • MSS默認為536,有效數據才4個字節,帶寬利用率1%不到,造成了巨大的浪費。

  • 窗口是為了控制傳輸過程中的速度。而MSS是為了控制TCP報文段大小

  • MTU = MSS + TCP頭(20字節) +IP頭(20字節)。

  • 解決方案:
    • 問題由Receiver引起,那么Receiver收到的數據導致window size(rwnd,receiver window)小於某個值,可以直接ack window size為0給Sender,這樣就把window關閉了,也阻止Sender再發數據過來,等到Receiver處理了一些數據后window size大於等於MSS時,或者Receiver Buffer有一般為空(具體策略有很多),可以把window 打開讓Sender發送數據過來。
    • 問題由Sender引起,使用延時處理,禁止大量小包發送。(打開之后無法使用telnet或者SSH這種交互性比較強的程序
      • 等到Window Size >= MSS 或者 Data Size >= MSS
      • 收到之前發送數據的ACK包,它才會發送數據,否者繼續積攢數據

3 阻塞處理

3.1 概述

  • 前面說過網絡波動時,TCP報文超時,引起重傳,但是重傳導致網絡負擔更大,可能導致網絡更加繁忙。
  • 所以TCP不會這么自私,它在發現阻塞時,會主動讓路(並不是直接停止發送TCP報文)。
  • 阻塞控制算法
    • 慢啟動
    • 阻塞避免
    • 阻塞發生時快速重傳(上一節說過)
    • 快速恢復

3.2 慢啟動算法

  • 程序剛剛加入網絡時,一點一點提升速度。
  • 算法流程
    • 連接建好的開始先初始化cwnd = 1(窗口),表明可以傳一個MSS大小的數據
    • 每當收到一個ACK,cwnd++,線性上升
    • 每當過了一個RTT,cwnd = cwnd*2, 呈指數上升。
    • ssthresh(slow start threshold),是一個上限,當cwnd >= ssthresh時,就會進入“擁塞避免算法”

img

3.3 阻塞避免算法

  • 一般來說ssthresh的值是65535,單位是字節,當cwnd達到這個值時后
  • 算法流程
    • 收到一個ACK時,cwnd = cwnd + 1/cwnd
    • 每過一個RTT時,cwnd = cwnd + 1

img

3.4 阻塞狀態時的算法

當丟包的時候,有兩種情況

  • 等到RTO超時,重傳數據包,TCP認為該情況太糟糕了

    • sshthreash = swnd / 2
    • cwnd 重置為1
    • 進入慢啟動算法
  • 快速重傳算法,即收到3個重復的ACK就開始重傳,無需等待RTO超時

    • TCP Tahoe(代表版本)的實現和RTO超時一樣。
    • TCP Reno的實現:
      • cwnd = cwnd / 2
      • sshthresh = cwnd
      • 進入快速恢復算法——Fast Recovery

3.5 快速恢復算法(TCP Reno)

  • 這里就講解TCP Reno版本的快速恢復算法,想了解更多請參考:TCP 的那些事兒(下)

  • 算法流程

    • cwnd = sshthresh + 3 * MSS(3的意思是確認有3個數據包被收到了)
    • 重傳Duplicated ACKs指定的數據包
    • 如果再收到 Duplicated ACKs,那么cwnd = cwnd +1
    • 如果收到了新的Ack,那么,cwnd = sshthresh ,然后就進入了擁塞避免的算法了。
  • 缺點:由於3個重復的ACKs,並不代表只丟了一個數據包;如果丟了多個數據包,將導致RTO。

img

參考:https://coolshell.cn/articles/11609.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM