1. 程式人生 > 其它 >聊一聊tcp 擁塞控制 一

聊一聊tcp 擁塞控制 一

核心:標記正在傳輸、已經確認段、已經重傳段,然後調整擁塞視窗以及重傳演算法達到最優傳輸!

enum tcp_ca_state {
    TCP_CA_Open = 0,
#define TCPF_CA_Open    (1<<TCP_CA_Open)
    TCP_CA_Disorder = 1,
#define TCPF_CA_Disorder (1<<TCP_CA_Disorder)
    TCP_CA_CWR = 2,
#define TCPF_CA_CWR    (1<<TCP_CA_CWR)
    TCP_CA_Recovery = 3,
#define TCPF_CA_Recovery (1<<TCP_CA_Recovery) TCP_CA_Loss = 4 #define TCPF_CA_Loss (1<<TCP_CA_Loss) };

上圖中描述了各個狀態!

open狀態:

   open狀態是常態, 這種狀態下tcp 傳送放通過優化後的快速路徑來接收處理ack,當一個ack到達時, 傳送方根據擁塞視窗是小於還是大於 滿啟動閾值,按照慢啟動或者擁塞避免來增大擁塞視窗

disorder 狀態:

  當傳送方收到 DACK 或者SACK的時候, 將變為disorder 狀態, 再次狀態下擁塞視窗不做調整,但是沒到一個新到的段 就回觸發傳送一個新的段傳送出去此時TCP 遵循發包守恆原則,就是一個新包只有在一個老的包離開網路後才傳送;擁塞視窗恆定,網路中資料包守恆

cwr 狀態:

  傳送發被通知出現擁塞通知, 直接告知!! 比喻通過icmp 源端抑制 等方式通知,當收到擁塞通知時,傳送方並不是立刻減少擁塞視窗, 而是每個一個新到的ack減小一個段 知道視窗減小到原來的一半為止,傳送方在減小視窗過程中如果沒有明顯重傳,就回保持cwr 狀態, 但是如果出現明顯重傳,就回被recovery 或者loss 中斷而進入 loss recovery 狀態;擁塞視窗減小,且沒有明顯的重傳。

recovery狀態:

  在收到足夠多的連續重複的ack 後,傳送方重傳第一個沒有被確認的段,進入recovery 狀態,預設情況下 連續收到三個重複的ack 就回進入recovery狀態,在recovery狀態期間,擁塞視窗的大小每隔一個新到的確認就會減少一個段, 和cwr 一樣 出於擁塞控制期間,這種視窗減少 終止於大小等於ssthresh,也就是進入recovery狀態時視窗的一半。傳送方重傳被標記為丟失的段,或者根據包守恆原則 傳送資料,傳送方保持recovery 狀態直到所有recovery狀態中被髮送的資料被確認,此時recovery狀態就回變為open,超時重傳可能中斷recovery狀態;、

  1. 經典 Reno 模式(非 SACK 模式)下,時退出 Recovery 狀態。

如上圖,資料包 A、B、C 可能沒有丟失只是被延遲接收,然而沒有 SACK 機制下無法判斷是 A、B、C 的重傳觸發的 3 次重複 ACK 還是新資料 1、2、3 丟失 1(或者 1、2 或者 1、2、3)導致的重複 ACK,兩種情況均會馬上把擁塞狀態機帶入到 Recovery 狀態,然而前一種是不必要的。如果在 SND_UNA== SND_HIGH 即轉為 Open 態,那麼當發生上述 1、2、3 的延遲到達後,緊接著的 Recovery 狀態會再次將擁塞視窗減半,最終降低到一個極低值。

  1. SACK/FACK 模式下,時退出 Recovery 狀態。 因為即使發生經典 Reno 模式下的 A、B、C 失序到達,由於存在 SACK 資訊,狀態機會將此三個重複 ACK 記為三個重複的 DSACK,在 SACK 模式下,判斷是否進入 Recovery 狀態的條件是被 SACK 的資料包數量大於 dupthresh,而 DSACK 不被計入到 SACKed 數量中。FACK 模式下隻影響進入 Recovery 狀態的時機,其核心仍建立在 SACK 之上,所以不影響退出的時機。

Loss 狀態 :

  當一個RTO到期,傳送方進入Loss 狀態 , 所有正在傳送的段都被標記為丟失段,擁塞視窗設定為一個段。傳送方啟動滿啟動演算法增大視窗。Loss 狀態是 擁塞視窗在被重置為一個段後增大,但是recovery狀態是擁塞視窗只能被減小, Loss 狀態不能被其他狀態中斷,所以只有所有loss 狀態下開始傳輸的資料得到確認後,才能到open狀態, 也就是快速重傳不能在loss 狀態下觸發。當一個RTO 超時, 或者收到ack 的確認已經被以前的sack 確認過, 則意味著我們記錄的sack資訊不能反應接收方實際的狀態,此時就回進入Loss 狀態。

  • (1)Open:Normal state, no dubious events, fast path.
  • (2)Disorder:In all respects it is Open, but requres a bit more attention.It is entered when we see some SACKs or dupacks. It is split of Openmainly to move some processing from fast path to slow one.
  • (3)CWR:cwnd was reduced due to some Congestion Notification event.It can be ECN, ICMP source quench, local device congestion.
  • (4)Recovery:cwnd was reduced, we are fast-retransmitting.
  • (5)Loss:cwnd was reduced due to RTO timeout or SACK reneging.

偽超時與重傳

  在很多情況下,即使沒有出現數據丟失也可能引發重傳。這種不必要的重傳稱為偽重傳,其主要造成原因是偽超時,即過早判定超時,其他因素如包失序、包重複,或 ACK 丟失也可能導致該現象。在實際 RTT 顯著增長,超過當前 RTO 時,可能出現偽超時。在下層協議效能變化較大的環境中(如無線環境),這種情況出現得比較多。

  TCP 為處理偽超時問題提出了許多方法。這些方法通常包含檢測演算法與響應演算法。檢測演算法用於判斷某個超時或基於計時器的重傳是否真實,一旦認定出現偽超時則執行響應演算法,用於撤銷或減輕該超時帶來的影響。 檢測演算法包含 DSACK 、Eifel 檢測演算法、遷移 RTO 恢復演算法(F-RTO) 三種

DSACK 擴充套件

  DSACK 的主要目的是判斷何時的重傳是不必要的,並瞭解網路中的其他事項。通過 DSACK 傳送端至少可以推斷是否發生了包失序、 ACK 丟失、包重複或偽重傳。 D-SACK 使用了 SACK 的第一個段來做標誌, a. 如果 SACK 的第一個段的範圍被 ACK 所覆蓋,那麼就是 D-SACK。 b.如果 SACK 的第一個段的範圍被 SACK 的第二個段覆蓋,那麼就是 D-SACK。 RFC2883]沒有具體規定傳送端對 DSACK 怎樣處理。 [RFC3708]給出了一種實驗演算法,利用 DSACK 來檢測偽重傳,響應演算法可採用 Eifel 響應演算法。

Eifel 檢測演算法 [RFC3522]

  實驗性的 Eifel 檢測演算法利用了 TCP 的 TSOPT 來檢測偽重傳。在發生超時重傳後,Eifel 演算法等待接收下一個 ACK,若為針對第一次傳輸(即原始傳輸)的確認,則判定該重傳是偽重傳。

與 DSACK 的比較: 利用 Eifel 檢測演算法能比僅採用 DSACK更早檢測到偽重傳行為,因為它判斷偽重傳的 ACK 是在啟動丟失恢復之前生成的。相反, DSACK 只有在重複報文段到達接收端後才能傳送,並且在 DSACK 返回至傳送端後才能有所響應。及早檢測偽重傳更為有利,它能使傳送端有效避免“回退 N”行為。

SACK 重傳

  1. 未啟用 SACK 時,TCP 重複 ACK 定義為收到連續相同的 ACK seq。[RFC5681]
  2. 啟用 SACK 時,攜帶 SACK 的 ACK 也被認為重複 ACK。[RFC6675]

如下圖所示(綠色為已傳送並且被 ack 的資料包,黃色表示已傳送還未確認的資料包,淺綠色為被 Sack 確認的資料包,藍色表示還未傳送的資料包),設 dupthresh = 3,SACKed_count = 6,從 unAcked 包開始的 SACKed_count - dupthresh 個數據包,即 3 個數據包會被標記為 LOST。

dupthresh 是指重複ACK閾值,一定數目的重複ACK,預設通常為3

記分板狀態如下,紅色表示該資料包丟失:

RACK重傳

  RACK(Recent ACKnowledgment)是一種新的基於時間的丟包探測演算法,RACK的目的是取代傳統的基於dupthresh門限的各種快速重傳及其變種。

  RACK基本思想:如果傳送端收到的確認包中的SACK選項確認收到了一個數據包,那麼在這個資料包之前傳送的資料包要麼是在傳輸過程中發生了亂序,要麼是發生了丟包。RACK使用最近投遞成功的資料包的傳送時刻來推測在這個資料包之前傳輸的資料包是否已經過期(expired),RACK把這些過期的資料包標記為lost。RACK可以修復丟包而不用等一個比較長的RTO超時,RACK可以用於快速恢復也可以用於超時恢復,既可以利用初傳的資料包探測丟包也可以利用重傳的資料包探測丟包,而且可以探測初傳丟包也可以探測重傳丟包,因此RACK是一個適應多種場景的丟包恢復機制。

  傳統的基於系列號空間的亂序度來探測丟包時,如果發生報文重傳,初傳報文和重傳報文在系列號空間就會重疊。而RACK基於時間的亂序來探測丟包的時候,重傳報文和初傳報文在時間線上是不重疊的,因此RACK可以同時利用初傳報文和重傳報文來探測丟包。

RACK使用的需要三個條件:

  • 1、TCP連線必須使用SACK選項
  • 2、對於每個傳送的資料包,傳送端必須儲存這個資料包的傳送時間,時間精度至少要達到毫秒精度。如果連線的RTT小於1ms,那麼微秒精度將會更有利於RACK探測丟包。
  • 3、對於每個傳送出去的資料包,傳送端必須儲存這個資料包是否已經重傳過。

二、RACK演算法描述

RACK目前還是一個實驗演算法,RACK需要使用到的幾個狀態變數:

  • Packet.xmit_ts:資料包上次傳輸所對應的時間,如果是重傳也需要記錄這個時間。傳送端需要對每個資料包都記錄這個時間,且時間精度至少是毫秒
  • RACK.xmit_ts:在所有被ack number或者SACK確認的資料包中,最近傳送的資料包的Packet.xmit_ts
  • RACK.end_seq:上面用於記錄RACK.xmit_ts的資料包的終止系列號
  • RACK.RTT:上面用於記錄RACK.xmit_ts的資料包對應的RTT
  • RACK.reo_wnd:表示這個TCP連線的時間亂序度,這個變數的單位是時間。RACK使用這個變數來推測丟包
  • RACK.min_RTT:估計的這個連線的最小RTT

注意這些變數的粒度,每個資料包都有一個Packet.xmit_ts變數,每個TCP連線維護一組RACK.xmit_ts, RACK.RTT, RACK.reo_wnd和RACK.min_RTT變數

演算法實現:

  • 1、當傳輸一個新的資料包或者重傳一箇舊的資料包的時候,把當前時間記錄在與這個資料包對應的Packet.xmit_ts變數中。
  • 2、當接收到一個ACK的時候

   Step2.1:根據測量到的RTT更新RACK.min_RTT。

        傳送端可以使用這個連線的全域性最小RTT來維護RACK.min_RTT,也可以使用一個每傳送視窗最小RTT的濾波值來維護RACK.min_RTT。

   Step2.2:更新RACK.reo_wnd。RACK.reo_wnd預設值為1ms,當探測到包亂序的時候可以設定RACK.reo_wnd=RACK.min_RTT/4

   Step2.3:更新RACK.xmit_ts、RACK.RTT 和 RACK.end_seq。

    首先在這個ACK新確認的資料包(包括通過ack number和SACK確認的資料包)中排除下面兩類重傳資料包

      1、如果這個資料包中的TSecr指示這個確認包並不是確認的重傳資料包。這個實際上是Eifel探測演算法。

      2、這個資料包上次重傳時間距離當前時間小於RACK.min_rtt。這個也意味著這個資料包多半是虛假重傳。

    接著在剩餘的新確認的資料包中找出最近傳送的資料包的Packet.xmit_ts,

        如果Packet.xmit_ts比RACK.xmit_ts在時間上更靠後,那麼更新RACK.xmit_ts =Packet.xmit_ts。

        如果RACK.xmit_ts發生了更新,那麼更新RACK.RTT = Now() - RACK.xmit_ts,RACK.end_seq = Packet.end_seq。

        如果RACK.xmit_ts沒有更新,那麼退出針對這個確認包的RACK處理流程,不再執行下面的丟包探測過程。

  • Step2.4:丟包探測

    對於每個還沒有被SACK完全確認的資料包,如果在時間上RACK.xmit_ts比Packet.xmit_ts + RACK.reo_wnd更靠後,說明這個資料包已經超過預計的時間亂序度,標記這個資料包為lost狀態。另外對於未被標記為lost的資料包,傳送端可以等待下次收到ACK確認包的時候再次進行RACK標記處理,      也可以設定一個"reordering settling"定時器,以待定時器超時的時候把這個資料包標記為lost。設定定時器的方法可以防止大量丟包或者應用層傳送資料受限而造成RTO超時。定時器的超時時間協議給出的是timeout = Packet.xmit_ts + RACK.RTT + RACK.reo_wnd + 1。

這裡值得一提的是,RACK功能可以很好的與TLP功能配合,因為RACK可以使用重傳包來探測丟包,因此TLP其實可以傳送第一個未被確認的資料包來進行丟包探測,這樣就可以應用層傳輸時延。

擁塞控制

擁塞的發生是因為路由器快取溢位,擁塞會導致丟包,但丟包不一定觸發擁塞。擁塞控制是快速傳輸的基礎。一個擁塞控制演算法一般包括慢啟動演算法擁塞避免演算法快速重傳演算法快速恢復演算法四部分。

http代理伺服器(3-4-7層代理)-網路事件庫公共元件、核心kernel驅動 攝像頭驅動 tcpip網路協議棧、netfilter、bridge 好像看過!!!! 但行好事 莫問前程 --身高體重180的胖子