什麼是TCP擁塞控制算法?

最近花了些時間在學習TCP/IP協議上,首要緣由是因爲本人長期以來對TCP/IP的認識就只限於三次握手四次分手上,因此但願深刻了解一下。再者,TCP/IP和Linux系統層級的不少設計均可以用於中間件系統架構上,好比說TCP 擁塞控制算法也能夠用在以響應時間來限流的中間件上。更深一層,像TCP/IP協議這種基礎知識和原理性的技術,都是通過長時間的考驗的,都是前人智慧的結晶,能夠給你們不少啓示和幫助。面試

本文中會出現一些縮寫,由於篇幅問題,沒法每一個都進行解釋,若是你不明白它的含義,請本身去搜索瞭解,作一個主動尋求知識的人。算法

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

TCP協議經過滑動窗口來進行流量控制,它是控制發送方的發送速度從而使接受者來得及接收並處理。而擁塞控制做用於總體網絡,它是防止過多的包被髮送到網絡中,避免出現網絡負載過大,網絡擁塞的狀況。架構

擁塞算法須要掌握其狀態機和四種算法。擁塞控制狀態機的狀態有五種,分別是:"Open,Disorder、CWR、Recovery和Loss狀態"。四個算法爲"慢啓動,擁塞避免,擁塞發生時算法和快速恢復"ide

Congestion Control State Machine

和TCP同樣,擁塞控制算法也有其狀態機。當發送方收到一個ACK時,Linux TCP經過狀態機的狀態來決定其接下來的行爲,是應該下降擁塞窗口cwnd大小,或者保持cwnd不變,仍是繼續增長cwnd。若是處理不當,可能會致使丟包或者超時。學習

什麼是TCP擁塞控制算法?

一、Open狀態優化

Open狀態是擁塞控制狀態機的默認狀態。這種狀態下,當ACK到達時,發送方根據擁塞窗口cwnd(Congestion Window)是小於仍是大於慢啓動閾值ssthresh(slow start threshold),來按照慢啓動或者擁塞避免算法來調整擁塞窗口。設計

二、Disorder狀態中間件

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

三、CWR狀態

發送方接收到一個顯示擁塞通知時,並不會馬上減小擁塞窗口cwnd,而是每收到兩個ACK就減小一個段,直到窗口的大小減半爲止。當cwnd正在減少而且網絡中有沒有重傳包時,這個狀態就叫CWR(Congestion Window Reduced,擁塞窗口減小)狀態。CWR狀態能夠轉變成Recovery或者Loss狀態。

四、Recovery狀態

當發送方接收到足夠(推薦爲三個)的DACK(重複確認)後,進入該狀態。在該狀態下,擁塞窗口cnwd每收到兩個ACK就減小一個段(segment),直到cwnd等於慢啓動閾值ssthresh,也就是剛進入Recover狀態時cwnd的一半大小。 發送方保持 Recovery 狀態直到全部進入 Recovery狀態時正在發送的數據段都成功地被確認,而後發送方恢復成Open狀態,重傳超時有可能中斷 Recovery 狀態,進入Loss狀態。

五、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。這些咱們後續也會繼續探討,請你們繼續關注。

寫在最後:

歡迎你們關注我新開通的公衆號【風平浪靜如碼】,海量Java相關文章,學習資料都會在裏面更新,整理的資料也會放在裏面。

以爲寫的還不錯的就點個贊,加個關注唄!點關注,不迷路,持續更新!!!

海量面試、架構資料分享

什麼是TCP擁塞控制算法?

相關文章
相關標籤/搜索