天天看點

TCP 擁塞控制算法簡介

 最近花了些時間在學習TCP/IP協定上,首要原因是由于本人長期以來對TCP/IP的認識就隻限于三次握手四次分手上,是以希望深入了解一下。再者,TCP/IP和Linux系統層級的很多設計都可以用于中間件系統架構上,比如說TCP 擁塞控制算法也可以用于以響應時間來限流的中間件。更深一層,像TCP/IP協定這種基礎知識和原理性的技術,都是經過長時間的考驗的,都是前人智慧的結晶,可以給大家很多啟示和幫助。

 本文中會出現一些縮寫,因為篇幅問題,無法每個都進行解釋,如果你不明白它的含義,請自己去搜尋了解,做一個主動尋求知識的人。

 TCP協定有兩個比較重要的控制算法,一個是流量控制,另一個就是阻塞控制。

 TCP協定通過滑動視窗來進行流量控制,它是控制發送方的發送速度進而使接受者來得及接收并處理。而擁塞控制是作用于網絡,它是防止過多的包被發送到網絡中,避免出現網絡負載過大,網絡擁塞的情況。

 擁塞算法需要掌握其狀态機和四種算法。擁塞控制狀态機的狀态有五種,分别是Open,Disorder,CWR,Recovery和Loss狀态。四個算法為慢啟動,擁塞避免,擁塞發生時算法和快速恢複。

Congestion Control State Machine

 和TCP一樣,擁塞控制算法也有其狀态機。當發送方收到一個Ack時,Linux TCP通過狀态機(state)來決定其接下來的行為,是應該降低擁塞視窗cwnd大小,或者保持cwnd不變,還是繼續增加cwnd。如果處理不當,可能會導緻丢包或者逾時。

TCP 擁塞控制算法簡介

1 Open狀态

 Open狀态是擁塞控制狀态機的預設狀态。這種狀态下,當ACK到達時,發送方根據擁塞視窗cwnd(Congestion Window)是小于還是大于慢啟動門檻值ssthresh(slow start threshold),來按照慢啟動或者擁塞避免算法來調整擁塞視窗。

2 Disorder狀态

 當發送方檢測到DACK(重複确認)或者SACK(選擇性确認)時,狀态機将轉變為Disorder狀态。在此狀态下,發送方遵循飛行(in-flight)包守恒原則,即一個新包隻有在一個老包離開網絡後才發送,也就是發送方收到老包的ACK後,才會再發送一個新包。

3 CWR狀态

 發送方接收到一個擁塞通知時,并不會立刻減少擁塞視窗cwnd,而是每收到兩個ACK就減少一個段,直到視窗的大小減半為止。當cwnd正在減小并且網絡中有沒有重傳包時,這個狀态就叫CWR(Congestion Window Reduced,擁塞視窗減少)狀态。CWR狀态可以轉變成Recovery或者Loss狀态。

4 Recovery狀态

 當發送方接收到足夠(推薦為三個)的DACK(重複确認)後,進入該狀态。在該狀态下,擁塞視窗cnwd每收到兩個ACK就減少一個段(segment),直到cwnd等于慢啟動門檻值ssthresh,也就是剛進入Recover狀态時cwnd的一半大小。

 發送方保持 Recovery 狀态直到所有進入 Recovery狀态時正在發送的資料段都成功地被确認,然後發送方恢複成Open狀态,重傳逾時有可能中斷 Recovery 狀态,進入Loss狀态。

5 Loss狀态

 當一個RTO(重傳逾時時間)到期後,發送方進入Loss狀态。所有正在發送的資料标記為丢失,擁塞視窗cwnd設定為一個段(segment),發送方再次以慢啟動算法增大擁塞視窗cwnd。

 Loss 和 Recovery 狀态的差別是:Loss狀态下,擁塞視窗在發送方設定為一個段後增大,而 Recovery 狀态下,擁塞視窗隻能被減小。Loss 狀态不能被其他的狀态中斷,是以,發送方隻有在所有 Loss 開始時正在傳輸的資料都得到成功确認後,才能退到 Open 狀态。

四大算法

 擁塞控制主要是四個算法:1)慢啟動,2)擁塞避免,3)擁塞發生,4)快速恢複。這四個算法不是一天都搞出來的,這個四算法的發展經曆了很多時間,到今天都還在優化中。

TCP 擁塞控制算法簡介

慢熱啟動算法 – Slow Start

 所謂慢啟動,也就是TCP連接配接剛建立,一點一點地提速,試探一下網絡的承受能力,以免直接擾亂了網絡通道的秩序。

 慢啟動算法:

1) 連接配接建好的開始先初始化擁塞視窗cwnd大小為1,表明可以傳一個MSS大小的資料。

2) 每當收到一個ACK,cwnd大小加一,呈線性上升。

3) 每當過了一個往返延遲時間RTT(Round-Trip Time),cwnd大小直接翻倍,乘以2,呈指數讓升。

4) 還有一個ssthresh(slow start threshold),是一個上限,當cwnd >= ssthresh時,就會進入“擁塞避免算法”(後面會說這個算法)

擁塞避免算法 – Congestion Avoidance

 如同前邊說的,當擁塞視窗大小cwnd大于等于慢啟動門檻值ssthresh後,就進入擁塞避免算法。算法如下:

1) 收到一個ACK,則cwnd = cwnd + 1 / cwnd

2) 每當過了一個往返延遲時間RTT,cwnd大小加一。

 過了慢啟動門檻值後,擁塞避免算法可以避免視窗增長過快導緻視窗擁塞,而是緩慢的增加調整到網絡的最佳值。

擁塞狀态時的算法

 一般來說,TCP擁塞控制預設認為網絡丢包是由于網絡擁塞導緻的,是以一般的TCP擁塞控制算法以丢包為網絡進入擁塞狀态的信号。對于丢包有兩種判定方式,一種是逾時重傳RTO[Retransmission Timeout]逾時,另一個是收到三個重複确認ACK。

 逾時重傳是TCP協定保證資料可靠性的一個重要機制,其原理是在發送一個資料以後就開啟一個計時器,在一定時間内如果沒有得到發送資料報的ACK封包,那麼就重新發送資料,直到發送成功為止。

 但是如果發送端接收到3個以上的重複ACK,TCP就意識到資料發生丢失,需要重傳。這個機制不需要等到重傳定時器逾時,是以叫

做快速重傳,而快速重傳後沒有使用慢啟動算法,而是擁塞避免算法,是以這又叫做快速恢複算法。

 逾時重傳RTO[Retransmission Timeout]逾時,TCP會重傳資料包。TCP認為這種情況比較糟糕,反應也比較強烈:

  • 由于發生丢包,将慢啟動門檻值ssthresh設定為目前cwnd的一半,即ssthresh = cwnd / 2.
  • cwnd重置為1
  • 進入慢啟動過程

 最為早期的TCP Tahoe算法就隻使用上述處理辦法,但是由于一丢包就一切重來,導緻cwnd又重置為1,十分不利于網絡資料的穩定傳遞。

 是以,TCP Reno算法進行了優化。當收到三個重複确認ACK時,TCP開啟快速重傳Fast Retransmit算法,而不用等到RTO逾時再進行重傳:

  • cwnd大小縮小為目前的一半
  • ssthresh設定為縮小後的cwnd大小
  • 然後進入快速恢複算法Fast Recovery。
TCP 擁塞控制算法簡介

快速恢複算法 – Fast Recovery

 TCP Tahoe是早期的算法,是以沒有快速恢複算法,而Reno算法有。在進入快速恢複之前,cwnd和ssthresh已經被更改為原有cwnd的一半。快速恢複算法的邏輯如下:

  • cwnd = cwnd + 3 MSS,加3 MSS的原因是因為收到3個重複的ACK。
  • 重傳DACKs指定的資料包。
  • 如果再收到DACKs,那麼cwnd大小增加一。
  • 如果收到新的ACK,表明重傳的包成功了,那麼退出快速恢複算法。将cwnd設定為ssthresh,然後進入擁塞避免算法。
TCP 擁塞控制算法簡介

 如圖所示,第五個包發生了丢失,是以導緻接收方接收到三次重複ACK,也就是ACK5。是以将ssthresh設定當當時cwnd的一半,也就是6/2 = 3,cwnd設定為3 + 3 = 6。然後重傳第五個包。當收到新的ACK時,也就是ACK11,則退出快速恢複階段,将cwnd重新設定為目前的ssthresh,也就是3,然後進入擁塞避免算法階段。

後記

 本文為大家大緻描述了TCP擁塞控制的一些機制,但是這些擁塞控制還是有很多缺陷和待優化的地方,業界也在不斷推出新的擁塞控制算法,比如說谷歌的BBR。這些我們後續也會繼續探讨,請大家繼續關注。

個人部落格:

Remcarpediem

引用

繼續閱讀