tcp的擁塞控制

tcp的擁塞控制

滑動窗口

滑動窗口的單位是字節。其值能夠爲MSS*N(mss的整數倍)算法

若是咱們在任一時間點對於這一過程作一個「快照」,那麼咱們能夠將TCP buffer中的數據分爲如下四類,並把它們看做一個時間軸:緩存

  • 狀態1 已發送已確認數據流中最先的字節已經發送並獲得確認。這些數據是站在發送設備的角度來看的。以下圖所示,31個字節已經發送並確認。
  • 狀態2 已發送但還沒有確認已發送但還沒有獲得確認的字節。發送方在確認以前,不認爲這些數據已經被處理。下圖所示14字節爲第2類。
  • 狀態3 未發送而接收方已Ready設備還沒有將數據發出,但接收方根據最近一次關於發送方一次要發送多少字節確認本身有足夠空間。發送方會當即嘗試發送。如圖,第3類有6字節。
  • 狀態4 未發送而接收方Not Ready因爲接收方not ready,還不容許將這部分數據發出。
    img

注意: 在tcp的一次報文傳輸過程當中,會發送多個字節,其做爲一個總體,對端只會對此報文的最後一個字節進行ack,代表此報文的全部字節都接收成功。相應的,客戶端也會將這些字節放入狀態2,滑動窗口往前移動。服務器

擁塞窗口

實際的發送窗口,是min(cwnd, wnd).這就保證了網絡

  • 發送的流量不會超過服務器緩存剩餘的空間
  • 發送的流量不會超過當前網絡鏈路的負荷

這裏爲了表述簡單,咱們將擁塞窗口大小稱爲N,N的值爲N mss字節.
tcp的擁塞控制主要有4個算法ssh

  • 慢啓動
  • 擁塞避免
  • 快重傳
  • 快恢復

ssthresh

關於慢啓動的ssthresh值,有篇文章講的比較好。TCP核心概念-慢啓動,ssthresh,擁塞避免,公平性的真實含義,同時也剪藏在evernote中。tcp

  • 2N = rttr (r爲發送的速率)
    N指什麼呢?N是指字節數。當咱們站在上帝視角,咱們能清楚的知道這條鏈路的承載能力的,即這條TCP鏈路某一時刻承載的最大字節數。可是主機是不知道的,主機並不知道鏈接的TCP鏈路情況,所以主機要作的就是使ssthresh迫近N.
  • 2*N = wnd (N是肯定但未知的,而wnd是須要咱們不斷迫近的)
    從理論上講,wnd的值等於當前鏈路N*2,N=wnd/2.可是惋惜的是咱們不知道N,也就無從知道理論wnd是多少。咱們的目標就是找到理論wnd和N,在尋找的過程當中,咱們給N起個變量名: ssthresh. 這就清楚了,ssthresh就是咱們假定當前鏈路的承載能力。

疑問: 爲何2*N = wnd
咱們假設當前的N爲4,即:當前的TCP鏈路可承載4字節的信息。那麼,咱們該將wnd設置爲多大,才能充分利用此鏈路呢?
充分利用鏈路,就是說,此鏈路充滿數據,服務器從接收一個,客戶端發送一個,數據流不斷
img
可見,在理想的狀況下,當wnd=8的時候,客戶端不用等待ack能夠一直髮送數據,不然客戶端須要收到ack並將滑動窗口向前移動,才能發送新的數據。
注意: 在一個rtt中,共發送了wnd 字節的流量。spa


慢啓動

初始化cwnd=1, 在每收到一個對新的報文段的確認後,把擁塞窗口增長至多一個MSS的數值。用這樣的方法逐步增大發送方的擁塞窗口 cwnd ,可使分組注入到網絡的速率更加合理。.net

當cwnd<ssthresh時,採用慢啓動算法,當cwnd>ssthresh時,採用擁塞避免算法。
那麼這個值具體的有什麼講究呢?這個在上面的連接中講的比較清楚了,我把我本身的理解再簡單的闡述一下。
ssthresh代表了當前網絡鏈路中可容納的最大字節數。當新建tcp連接的時候,並不清楚此tcp鏈路的情況,因此將sshthresh設置爲一個巨大的值。而後每收到一個報文的ack,都將cwnd的值加1。所以,通過一個rtt, cwnd是呈指數級在增加。code

可是通常來講cwnd是達不到初始 ssthresh的值的,在cwnd增加的過程當中,可能初始ssthresh的值遠遠大於鏈路的帶寬,所以很快鏈路就會出現阻塞。注意這裏區分兩種狀況:blog

  • 1 網絡出現阻塞
  • 2 網絡出現丟包,可是後續的報文被服務端成功收到。
    當網絡出現阻塞的時候,須要進行以下操做:
  • ssthresh 減小爲當前cwnd的一半
  • cwnd 設置爲1 並開始新一輪的計算
    須要考慮一個問題,爲何ssthresh須要設置爲原來的一半?

當前的cwnd值過大,根本緣由是咱們假定當前鏈路的承載能力ssthresh過大,須要縮減,ssthresh = cwnd/2,就是說,在當前的cwnd狀況下,其對應的ssthresh_new爲 cwnd/2。所以咱們將ssthresh_old替換爲ssthresh_new,即減爲當前cwnd值得一半,並開始新一輪的迫近過程。
舉個例子

理論狀況:ssthresh=2 cwnd=4
初始化: ssthresh=5 cwnd=1
rtt1:  ssthresh 5 cwnd=1
rtt2:  ssthresh 5 cwnd=2(cwnd==ssthresh,改成擁塞避免算法)
rtt3:  ssthresh 5 cwnd=3
rtt4:  ssthresh 5 cwnd=4
rtt5:  ssthresh 5 cwnd=5
rtt6:  ssthresh 5 cwnd=6(可能開始出現阻塞丟包)
rtt7:  ssthresh 3 cwnd=1(reset)
...

疑問:那會不會存在cwnd/2>ssthresh_old的狀況呢?這樣不是ssthresh反而加大了?


擁塞避免

wnd = rtt*r
在一個rtt中,共發送了wnd 字節的流量。若是這wnd字節的流量都成功ack,那麼咱們將cwnd+1
即:一個rtt 結束後,沒有網絡阻塞的話 ,cwnd+1。

能夠很明顯看到擁塞避免和慢啓動的差別,慢啓動時一個rtt後,cwnd增長一倍。

相關文章
相關標籤/搜索