擁塞控制

爲了防止網絡的擁塞現象,TCP提出了一系列的擁塞控制機制。最初由V. Jacobson在1988年的論文中提出的TCP的擁塞控制由“慢啓動(Slow start)”和“擁塞避免(Congestion avoidance)”組成,後來TCP Reno版本中又針對性的加入了“快速重傳(Fast retransmit)”、“快速恢復(Fast Recovery)”算法,再後來在TCP NewReno中又對“快速恢復”算法進行了改進,近些年又出現了選擇性應答( selective acknowledgement,SACK)算法,還有其他方面的大大小小的改進,成爲網絡研究的一個熱點。

1.擁塞控制和流量控制

網絡擁塞現象是指到達通信子網中某一部分的分組數量過多,使得該部分網絡來不及處理,以致引起這部分乃至整個網絡性能下降的現象,嚴重時甚至會導致網絡通信業務陷入停頓,即出現死鎖現象。擁塞控制是處理網絡擁塞現象的一種機制。
流量控制是指數據的傳送與接收過程當中很可能出現收方來不及接收的情況,這時就需要對發方進行控制,以免數據丟失。

2.接收窗口和擁塞窗口
TCP的擁塞控制主要原理依賴於一個擁塞窗口(cwnd)來控制,在之前我們還討論過TCP還有一個對端通告的接收窗口(rwnd)用於流量控制。窗口值的大小就代表能夠發送出去的但還沒有收到ACK的最大數據報文段,顯然窗口越大那麼數據發送的速度也就越快,但是也有越可能使得網絡出現擁塞,如果窗口值爲1,那麼就簡化爲一個停等協議,每發送一個數據,都要等到對方的確認才能發送第二個數據包,顯然數據傳輸效率低下。TCP的擁塞控制算法就是要在這兩者之間權衡,選取最好的cwnd值,從而使得網絡吞吐量最大化且不產生擁塞。
由於需要考慮擁塞控制和流量控制兩個方面的內容,因此TCP的真正的發送窗口=min(rwnd, cwnd)。但是rwnd是由對端確定的,網絡環境對其沒有影響,所以在考慮擁塞的時候我們一般不考慮rwnd的值,我們暫時只討論如何確定cwnd值的大小。關於cwnd的單位,在TCP中是以字節來做單位的,我們假設TCP每次傳輸都是按照MSS大小來發送數據的,因此你可以認爲cwnd按照數據包個數來做單位也可以理解,所以有時我們說cwnd增加1也就是相當於字節數增加1個MSS大小。

3.慢啓動

慢啓動:最初的TCP在連接建立成功後會向網絡中發送大量的數據包,這樣很容易導致網絡中路由器緩存空間耗盡,從而發生擁塞。因此新建立的連接不能夠一開始就大量發送數據包,而只能根據網絡情況逐步增加每次發送的數據量,以避免上述現象的發生。具體來說,當新建連接時,cwnd初始化爲1個最大報文段(MSS)大小,每收到一個ack,擁塞窗口就增加一個報文段。這樣cwnd的值就隨着網絡往返時間(Round Trip Time,RTT)呈指數級增長,事實上,慢啓動的速度一點也不慢,只是它的起點比較低一點而已。我們可以簡單計算下:
開始           --->     cwnd = 1
經過1個RTT後   --->     cwnd = 2*1 = 2
經過2個RTT後   --->     cwnd = 2*2= 4
經過3個RTT後   --->     cwnd = 4*2 = 8
如果帶寬爲W,那麼經過RTT*log2W時間就可以佔滿帶寬。

4.擁塞避免

擁塞避免:從慢啓動可以看到,cwnd可以很快的增長上來,從而最大程度利用網絡帶寬資源,但是cwnd不能一直這樣無限增長下去,一定需要某個限制。TCP使用了一個叫慢啓動門限(ssthresh)的變量,當cwnd超過該值後,慢啓動過程結束,進入擁塞避免階段。對於大多數TCP實現來說,ssthresh的值是65536(同樣以字節計算)。擁塞避免的主要思想是加法增大,也就是cwnd的值不再指數級往上升,開始加法增加。此時當窗口中所有的報文段都被確認時,cwnd的大小加1,cwnd的值就隨着RTT開始線性增加,這樣就可以避免增長過快導致網絡擁塞,慢慢的增加調整到網絡的最佳值。
上面討論的兩個機制都是沒有檢測到擁塞的情況下的行爲,那麼當發現擁塞了cwnd又該怎樣去調整呢?
首先來看TCP是如何確定網絡進入了擁塞狀態的,TCP認爲網絡擁塞的主要依據是它重傳了一個報文段。上面提到過,TCP對每一個報文段都有一個定時器,稱爲重傳定時器(RTO),當RTO超時且還沒有得到數據確認,那麼TCP就會對該報文段進行重傳,當發生超時時,那麼出現擁塞的可能性就很大,某個報文段可能在網絡中某處丟失,並且後續的報文段也沒有了消息,在這種情況下,TCP反應比較“強烈”:

(1)把ssthresh降低爲cwnd值的一半
(2)把cwnd重新設置爲1
(3)重新進入慢啓動過程

從整體上來講,TCP擁塞控制窗口變化的原則是AIMD原則,即加法增大、乘法減小。可以看出TCP的該原則可以較好地保證流之間的公平性,因爲一旦出現丟包,那麼立即減半退避,可以給其他新建的流留有足夠的空間,從而保證整個的公平性。

5.快速重傳

其實TCP還有一種情況會進行重傳:那就是收到3個相同的ACK。TCP在收到亂序到達包時就會立即發送ACK,TCP利用3個相同的ACK來判定數據包的丟失,此時進行快速重傳,快速重傳做的事情有:
(1)把ssthresh設置爲cwnd的一半
(2)把cwnd再設置爲ssthresh的值(具體實現有些爲ssthresh+3)
(3)重新進入擁塞避免階段。

6.快速恢復

後來的“快速恢復”算法是在上述的“快速重傳”算法後添加的,當收到3個重複ACK時,TCP最後進入的不是擁塞避免階段,而是快速恢復階段。快速重傳和快速恢復算法一般同時使用。快速恢復的思想是“數據包守恆”原則,即同一個時刻在網絡中的數據包數量是恆定的,只有當“老”數據包離開了網絡後,才能向網絡中發送一個“新”的數據包,如果發送方收到一個重複的ACK,那麼根據TCP的ACK機制就表明有一個數據包離開了網絡,於是cwnd加1。如果能夠嚴格按照該原則那麼網絡中很少會發生擁塞,事實上擁塞控制的目的也就在修正違反該原則的地方。
具體來說快速恢復的主要步驟是:
(1)當收到3個重複ACK時,把ssthresh設置爲cwnd的一半,把cwnd設置爲ssthresh的值加3,然後重傳丟失的報文段,加3的原因是因爲收到3個重複的ACK,表明有3個“老”的數據包離開了網絡。 
(2)再收到重複的ACK時,擁塞窗口增加1。
(3)當收到新的數據包的ACK時,把cwnd設置爲第一步中的ssthresh的值。原因是因爲該ACK確認了新的數據,說明從重複ACK時的數據都已收到,該恢復過程已經結束,可以回到恢復之前的狀態了,也即再次進入擁塞避免狀態。
快速重傳算法首次出現在4.3BSD的Tahoe版本,快速恢復首次出現在4.3BSD的Reno版本,也稱之爲Reno版的TCP擁塞控制算法。

參考資料:

1.轉:http://hi.baidu.com/iruler/blog/item/c49ca211a9174f1eb9127b8c.html

2.《TCP/IP詳解 VOL.1》21章

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