tcp協議 擁塞控制

補充tcp協議與滑動窗口
咱們在向對端發送數據時,並非一股腦子任意發送,由於TCP創建鏈接後,就是創建了一根管道,這跟管道上,實際上有不少的工做設備,好比路由器和交換機等等,他們都會對接收到的TCP包進行緩存,以便實現排序,而後發送,可是這些設備並非只爲一個TCP鏈接中轉數據包,大量的網絡包也許會耗盡存儲空間,從而致使TCP鏈接的吞吐量急劇降低。爲了不這種狀況的發送,TCP的設計必須是一種無私的協議,它必須去探測這種網絡擁塞的問題,不然咱們想一想,一旦出現擁塞(判斷是否丟包或者是否發生重傳),若是TCP只能作重傳,那麼重傳數據包會使得網絡上的包更多,網絡的負擔更重,因而致使更大的延遲以及丟更多的包,因而會進入一個惡性循環,若是網絡上的全部TCP鏈接都是如此行事的話,那麼立刻就會造成「網絡風暴」,會拖垮整個網絡,這也是一個災難。那麼TCP就應該可以檢測出來這種情況,當擁塞出現時,要作自我犧牲,就像交通阻塞同樣,每一輛車都應該把路給讓出來,而不是再去搶路了。這說的就是擁塞控制。那是如何控制的呢?算法

首先,咱們得看TCP是如何充分利用網絡的,TCP實際上就是逐步探測這個通道的傳輸的最大能力,這個逐步探索就是咱們要講的慢啓動算法,這個慢啓動算法就是:新創建的鏈接不能一開始就大量發送數據包,而是應該根據網絡情況,逐步地增長每次發送數據包的量。segmentfault

具體的工做步驟就是:緩存

  • 慢啓動算法:網絡

    • 發送方維護一個擁塞窗口,剛開始時,這個擁塞窗口(cwnd,congestion window)設置爲1,這個1表明是一個MSS個字節。
    • 若是每收到一個ACK,那麼就指數增加這個cwnd(2,4,8,16,32,64)等,
    • 實際上不會這麼一直指數級增加下去,TCP會設置一個慢啓動的閾值(ssthresh,slow start threshold,65535個字節) ,當cwnd >= ssthresh時,進入擁塞避免階段。
  • 擁塞避免階段ssh

    • 每收到一個ACK時,cwnd = cwnd + 1/cwnd;
    • 每當每過一個RTT時,cwnd = cwnd + 1;

這樣放緩了擁塞窗口的增加速率,避免增加過快致使網絡擁塞,慢慢的增長調整到網絡的最佳值。在這個過程當中若是出現了擁塞,則進入擁塞狀態。
擁塞狀態 那是如何判斷出現擁塞狀態呢?只要出現丟包就認爲進入了擁塞狀態。進入擁塞狀態也分兩種狀況:
1) 等到RTO超時(重傳超時),重傳數據包。TCP認爲這種狀況太糟糕,反應也很強烈:tcp

  • sshthresh = cwnd /2
  • cwnd 重置爲 1
  • 進入慢啓動過程

快速重傳
2)連續收到3個duplicate ACK時,重傳數據包,無須等待RTO。此狀況即爲下面的快速重傳。網站

【問題】什麼狀況下會出現3個duplicate ACK?設計

TCP在收到一個亂序的報文段時,會當即發送一個重複的ACK,而且此ACK不可被延遲。排序

若是連續收到3個或3個以上重複的ACK,TCP會斷定此報文段丟失,須要從新傳遞,而無需等待RTO。這就叫作快速重傳。路由

TCP Tahoe的實現和RTO超時同樣。 TCP Reno的實現是:

  • sshthresh = cwnd
  • cwnd = cwnd /2
  • 進入快速恢復算法——Fast Recovery

上面咱們能夠看到RTO超時後,sshthresh會變成cwnd的一半,這意味着,若是cwnd<=sshthresh時出現的丟包,那麼TCP的sshthresh就會減了一半,而後等cwnd又很快地以指數級增漲爬到這個地方時,就會成慢慢的線性增漲。咱們能夠看到,TCP是怎麼經過這種強烈地震盪快速而當心得找到網站流量的平衡點的。

快速恢復算法

  • TCP Reno

這個算法定義在RFC5681。快速重傳和快速恢復算法通常同時使用。快速恢復算法是認爲,你還有3個Duplicated Acks說明網絡也不那麼糟糕,因此沒有必要像RTO超時那麼強烈。 注意,正如前面所說,進入Fast Recovery以前,cwnd 和 sshthresh已被更新:

  • sshthresh = cwnd
  • cwnd = cwnd /2

而後,真正的Fast Recovery算法以下:

  • cwnd = sshthresh + 3 * MSS (3的意思是確認有3個數據包被收到了)
  • 重傳Duplicated ACKs指定的數據包
  • 若是再收到 duplicated Acks,那麼cwnd = cwnd +1
  • 若是收到了新的Ack,那麼,cwnd = sshthresh ,表明恢復過程結束,而後就進入了擁塞避免的算法了。

若是咱們仔細思考一下上面的這個算法,你就會知道,上面這個算法也有問題,那就是——它依賴於3個重複的Acks。注意,3個重複的Acks並不表明只丟了一個數據包,頗有多是丟了好多包。但這個算法只會重傳一個,而剩下的那些包只能等到RTO超時,因而,進入了惡夢模式——超時一個窗口就減半一下,多個超時會超成TCP的傳輸速度呈級數降低,並且也不會觸發Fast Recovery算法了。

  • TCP New Reno

因而,1995年,TCP New Reno(參見 RFC 6582 )算法提出來:

  • 當sender這邊收到了3個Duplicated Acks,進入Fast Retransimit模式,開發重傳重複Acks指示的那個包。若是隻有這一個包丟了,那麼,重傳這個包後回來的Ack會把整個已經被sender傳輸出去的數據ack回來。若是沒有的話,說明有多個包丟了。咱們叫這個ACK爲Partial ACK。
  • 一旦Sender這邊發現了Partial ACK出現,那麼,sender就能夠推理出來有多個包被丟了,因而乎繼續重傳sliding window裏未被ack的第一個包。直到再也收不到了Partial Ack,才真正結束Fast Recovery這個過程。

咱們能夠看到,這個「Fast Recovery的變動」是一個很是激進的玩法,他同時延長了Fast Retransmit和Fast Recovery的過程。

相關文章
相關標籤/搜索