(六)深入淺出TCPIP之TCP擁塞控制

目錄

 

什麼是網絡擁塞

如何避免擁塞

擁塞點

避免擁塞

慢啓動算法

算法思想

慢啓動解析

啓動過程

擁塞避免算法

啓動過程

快速重傳算法

快速恢復

總結

連環發問:


專欄其他文章:

 

理論篇:

(一)深入淺出TCPIP之理解TCP報文格式和交互流程

  (二)深入淺出TCPIP之再識TCP,理解TCP三次握手(上)

  (三)深入淺出TCPIP之再識TCP,理解TCP四次揮手(上)

  (四)深入淺出TCPIP之TCP三次握手和四次揮手(下)的抓包分析

  (五)深入淺出TCPIP之TCP流量控制

  (六)深入淺出TCPIP之TCP擁塞控制

  (七)深入淺出TCPIP之深入淺出TCPIP之TCP重傳機制

 (八)深入淺出TCPIP之TCP長連接與短連接詳解

 (九)深入淺出TCPIP之網絡同步異步

 (十)深入淺出TCPIP之網絡阻塞和非阻塞

(十一)深入淺出TCPIP之TCP粘包問題

  (十二)深入淺出TCPIP之Nagle算法

  (十三) 深入淺出TCPIP之TCP套接字參數

  (十四)深入淺出TCPIP之初識UDP理解報文格式和交互流程

  (十五)非常全面的TCPIP面試寶典-進入大廠必備總結

 (十六)深入淺出TCPIP之Hello CDN

 ....

(二十)深入淺出TCPIP之epoll的一些思考

實踐篇:

   深入淺出TCPIP之實戰篇—用c++開發一個http服務器(二十一)

其他實踐篇+遊戲開發中的網絡問題疑難雜症解讀 正在完善。。。

什麼是網絡擁塞

當網絡中存在過多的數據包時,網絡的性能就會下降,這種現象稱爲擁塞
在網絡發生擁塞時,會導致吞吐量下降,嚴重時會發生“擁塞朋潰" (congestion clpse)現象。 

擁塞產生
       崩潰發生在網絡負載增加而導致網絡效率降低的時候。如圖1所示,源端A發送數據給目的端B,途經若干中間節點,而中間節點不只爲A和B服務,還爲甲、乙、丙服務,如果甲、乙。丙沒有發送數據的時候,整體鏈路爲A和B獨有,當它們開始發報文時,也不會通知A和B.那麼爲A-B服務的通道帶寬會變小,當達到一定程度後,鏈路上的中間節點就出現丟包,根據傳統IP行爲其QoS(Quality of Service,服務質量)能力較弱。這時B發現有丟包,於是通知A重發,這個通知重發,這個通知重發的報文也佔帶寬,通知重發報文到達A之後,A不得已真的重發,於是反覆多次,帶寬終於被這種沒有意義的重發報文佔滿。這導致了A. B及甲、乙、丙也得不到正常的網絡服務,其RI和R2之間的有效帶寬遠遠達不到實際的物理帶寬,對客戶的網絡投資是一種極大的浪費。

 

如何避免擁塞

擁塞點

實際的網絡環境是非常複雜的,每一跳路由的帶寬可能都不一樣,如果一下接收到太多的數據網絡就會發送擁塞,擁塞的結果就是丟包。導致網絡擁塞的數據量稱爲擁塞點。 擁塞點是一個在不斷變化的動態值,TCP需要在儘可能大的發送窗口下,避免觸碰到擁塞點。

避免擁塞

TCP主要使用以下幾種算法來避免擁塞的發生:

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

慢啓動算法

算法思想

慢啓動算法的思想是爲發送方增加了一個擁塞窗口(Congestion Window),記爲cwnd。

        擁塞窗口指的是在收到對端的ACK時還能發送的最大MSS數。擁塞窗口是發送端維護的一個值,不會像接收方窗口(rwnd)那樣通告給對端,發送方窗口的大小是cwnd和rwnd的最小值。目前的linux的擁塞窗口初始值爲10個MSS。

        慢啓動算法,每經過一個RTT,cwnd變爲之前的兩倍。發送方開始時發送initcwnd個報文段(假設接收方窗口沒有限制然後等待ACK。當收到該ACK時,擁塞窗口擴大爲initcwnd*2,即可以發送initcwnd*2個報文段。當收到這發出報文段的ACK時,擁塞窗口繼續擴大爲initcwnd*4,這是一種指數增加的關係。

慢啓動解析

          發送方一開始便向網絡發送多個報文段,直至達到接收方通告的窗口大小爲止。當發送方和接收方處於同一個局域網時,這種方式是可以的。但是如果在發送方和接收方之間存在多個路由器和速率較慢的鏈路時,就有可能出現一些問題。一些中間路由器必須緩存分組,並有可能耗盡存儲器的空間。
         現在,TCP需要支持一種被稱爲“慢啓動(slow start)”的算法。該算法通過觀察到新分組進入網絡的速率應該與另一端返回確認的速率相同而進行工作。
慢啓動爲發送方的TCP增加了另一個窗口:擁塞窗口(congestion window),記爲cwnd。當與另一個網絡的主機建立T C P連接,擁塞窗口被初始化爲 1個報文段(即另一端通告的報文段大小)。每收到一個ACK,擁塞窗口就增加一個報文段( c w n d以字節爲單位,但是慢啓動以報文段大小爲單位進行增加)。發送方取擁塞窗口與通告窗口中的最小值作爲發送上限。擁塞窗口是發送方使用的流量控制,而通告窗口則是接收方使用的流量控制。發送方開始時發送一個報文段,然後等待 A C K。當收到該A C K時,擁塞窗口從1增加爲2,即可以發送兩個報文段。當收到這兩個報文段的 A C K時,擁塞窗口就增加爲4。這是一種指數增加的關係。

啓動過程

慢啓動算法過程如下:

  1. 通信開始時,發送方的擁塞窗口大小爲 1。每收到一個 ACK 確認後,擁塞窗口翻倍。
  2. 由於指數級增長非常快,很快地,就會出現確認包超時。
  3. 此時設置一個“慢啓動閾值”,它的值是當前擁塞窗口大小的一半。
  4. 同時將擁塞窗口大小設置爲 1,重新進入慢啓動過程。
  5. 由於現在“慢啓動閾值”已經存在,當擁塞窗口大小達到閾值時,不再翻倍,而是線性增加。
  6. 隨着窗口大小不斷增加,可能收到三次重複確認應答,進入“快速重發”階段。
  7. 這時候,TCP 將“慢啓動閾值”設置爲當前擁塞窗口大小的一半,再將擁塞窗口大小設置成閾值大小(也有說加 3)。
  8. 擁塞窗口又會線性增加,直至下一次出現三次重複確認應答或超時。

    

擁塞避免算法

擁塞避免算法和慢啓動算法是兩個不同的算法,但是他們都是爲了解決擁塞,在實際中這兩個算法通常是在一起實現的。相比於慢啓動算法擁塞避免算法多維護了一個慢啓動閾值ssthresh。當cwnd<ssthresh時,擁塞窗口使用慢啓動算法,按指數級增長。 當cwnd>ssthresh時,擁塞窗口使用擁塞避免算法,按線性增長。

擁塞避免算法每經過一個RTT,擁塞窗口增加initcwnd

啓動過程

擁塞避免算法和慢啓動算法需要對每個連接維持兩個變量:一個擁塞窗口 cwnd和一個慢啓動門限ssthresh。這樣得到的算法的工作過程如下:
1) 對一個給定的連接,初始化cwnd爲1個報文段,ssthresh爲65535個字節。
2) TCP輸出例程的輸出不能超過 cwnd和接收方通告窗口的大小。擁塞避免是發送方使用的流量控制,而通告窗口則是接收方進行的流量控制。前者是發送方感受到的網絡擁塞的估
計,而後者則與接收方在該連接上的可用緩存大小有關。
3) 當擁塞發生時(超時或收到重複確認),ssthresh被設置爲當前窗口大小的一半( c w n d和接收方通告窗口大小的最小值,但最少爲 2個報文段)。此外,如果是超時引起了擁塞,則
cwnd被設置爲1個報文段(這就是慢啓動)。
4) 當新的數據被對方確認時,就增加cwnd,但增加的方法依賴於我們是否正在進行慢啓動或擁塞避免。如果 cwnd小於或等於ssthresh,則正在進行慢啓動,否則正在進行擁塞避免。
慢啓動一直持續到我們回到當擁塞發生時所處位置的半時候才停止(因爲我們記錄了在步驟 2中給我們製造麻煩的窗口大小的一半),然後轉爲執行擁塞避免。
慢啓動算法初始設置 cwnd爲1個報文段,此後每收到一個確認就加 1。這會使窗口按指數方式增長:發送 1個報文段,然後是2個,接着是4個⋯⋯。
擁塞避免算法要求每次收到一個確認時將 cwnd增加1 /cwnd。與慢啓動的指數增加比起來,這是一種加性增長(additive increase)。我們希望在一個往返時間內最多爲cwnd增加1個報文段(不管在這個RT T中收到了多少個ACK),然而慢啓動將根據這個往返時間中所收到的確認的個數增加cwnd。

         下圖是慢啓動和擁塞避免的一個可視化描述。我們以段爲單位來顯示cwnd和ssthresh,但它們實際上都是以字節爲單位進行維護的。










         在該圖中,假定當cwnd爲32個報文段時就會發生擁塞。於是設置 ssthresh爲16個報文段,而cwnd爲1個報文段。在時刻 0發送了一個報文段,並假定在時刻 1接收到它的 ACK,此時cwnd增加爲2。接着發送了2個報文段,並假定在時刻2接收到它們的ACK,於是cwnd增加爲4(對每個ACK增加1次)。這種指數增加算法一直進行到在時刻 3和4之間收到8個ACK後cwnd等於ssthresh時才停止,從該時刻起, cwnd以線性方式增加,在每個往返時間內最多增加 1個報文段。
正如我們在這個圖中看到的那樣,術語“慢啓動”並不完全正確。它只是採用了比引起擁塞更慢些的分組傳輸速率,但在慢啓動期間進入網絡的分組數增加的速率仍然是在增加的。只有在達到ssthresh擁塞避免算法起作用時,這種增加的速率纔會慢下來。

超時重傳對傳輸性能有嚴重影響。原因之一是在RTO階段不能傳數據,相當於浪費了一段時間;原因之二是擁塞窗口的急劇減小,相當於接下來傳得慢多了。

快速重傳算法

有時候擁塞比較輕微,只有少量包丟失,後續的包能夠正常到達。當後續的包到達接收方時,接收方會發現其Seq號比期望的大,所以它每收到一個包就Ack一次期望的Seq號,以此提醒發送方重傳。當發送方收到3個或以上重複確認(Dup Ack)時,就意識到相應的包已經丟了,從而立即重傳它。這個過程稱爲快速重傳。

爲什麼要規定湊滿3個呢?這是因爲網絡包有時會亂序,亂序的包一樣會觸發重複的Ack,但是爲了亂序而重傳沒有必要。由於一般亂序的距離不會相差太大,比如2號包也許會跑到4號包後面,但不太可能跑到6號包後面,所以限定成3個或以上可以在很大程度上避免因亂序而觸發快速重傳。

還有一個問題,如下圖:

如果2號和3號包都丟失了,但是後面4,5,6,7號都正常收到了,並觸發了三次Ack2。在重傳了2號包之後該傳哪個包那,是全部需要重傳還是隻傳2號包?

爲了解決這種問題,TCP在發送重複的Ack包的時候,會告訴接收方收到的已經收到包的序號,如下圖:

這樣發送方就知道該重傳哪個包了,這種方式被稱爲選擇性確認(Selective Acknowledgement)

快速恢復

如果在擁塞階段發生了快速重傳就沒有必要像超時重傳那樣處理擁塞窗口了,因爲此時的擁塞並不是很嚴重。RFC5681建議此時的慢啓動閾值ssthreh設置爲沒有被確認包的1/2,但是不小於2個MSS。擁塞窗口設置爲慢啓動閾值加3個MSS。這個過程被稱爲快速恢復

總結

超時重傳對性能的影響最大,因爲在RTO期間不能傳輸任何數據,而且擁塞窗口會急劇減小。所以應該儘量避免超時重傳。

丟包對極小文件的影響比大文件嚴重,因爲小文件可能不能觸發三次重複的Ack,導致無法快速重傳。

 

連環發問:

1. 發送端如何知道已經丟包?

  定時器超時 收到三個重複ACK。

2.既然有流量控制了,爲什麼還會有擁塞控制?

      首先要注意擁塞控制與流量控制的區別:

       擁塞控制是防止過多的數據注入網絡中,使得網絡中路由器或鏈路不致過載,有一個前提是,網絡能夠承受現有的網絡負荷,是一個全局性過程;

      流量控制是指點對點通信的控制,做的是抑制發送端發送數據的速率,便於接收端來得及接收。

      流量控制雖然可以高效可靠的傳送大量的數據,但是如果在剛開始階段就發送大量的數據,可能會導致網絡擁堵,因爲網絡上的計算機太多了,而且網絡之間的請求和轉發數據又是非常複雜和龐大的,因此這種複雜的網絡環境中會出現擁塞。

3.一般在工作中如何檢查當前服務器是否可能存在擁塞?

      這裏不得不提到擁塞的表現:  丟包或者延時變長,因此我們會用ping ip/hostname -t 來查看當前主機的丟包和延時情況,或者用tcpdump來查看連續兩個報文之間的時間差是否較大。

4.流量控制和擁塞控制的區別
1.相同點

(1)現象都是丟包;
(2)實現機制都是讓發送方發的慢一點,發的少一點

2.不同點

    (1)丟包位置不同
             流量控制丟包位置是在接收端上
             擁塞控制丟包位置是在路由器上
    (2)作用的對象不同
              流量控制的對象是接收方,怕發送方發的太快,使得接收方來不及處理
           擁塞控制的對象是網絡,怕發送發發的太快,造成網絡擁塞,使得網絡來不及處理




3.聯繫

       擁塞控制
             擁塞控制通常表示的是一個全局性的過程,它會涉及到網絡中所有的主機、
             所有的路由器和降低網絡傳輸性能的所有因素
      流量控制
            流量控制發生在發送端和接收端之間,只是點到點之間的控制



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章