TCP快速重傳與快速恢復原理分析
轉自 http://blog.csdn.net/zhangskd/article/details/7174682
超時重傳是TCP協議保證資料可靠性的一個重要機制,其原理是在傳送一個數據以後就開啟一個計時器,
在一定時間內如果沒有得到傳送資料報的ACK報文,那麼就重新發送資料,直到傳送成功為止。這是數據
包丟失的情況下給出的一種修補機制。一般來說,重傳發生在超時之後,但是如果傳送端接收到3個以上
的重複ACK,就應該意識到,資料丟了,需要重新傳遞。這個機制不需要等到重傳定時器溢位,所以叫
做快速重傳,而快速重傳以後,因為走的不是慢啟動而是擁塞避免演算法,所以這又叫做快速恢復演算法。
快速重傳和快速恢復旨在:快速恢復丟失的資料包。
沒有快速重傳和快速恢復,TCP將會使用定時器來要求傳輸暫停。在暫停這段時間內,沒有新的資料包
被髮送。
快速重傳和快速恢復演算法是在4.3BSD中提出的,並在RFC2001和RFC2581中描述。
快速重傳與快速恢復經歷了幾個階段。
1. Tahoe
Tahoe演算法是TCP的早期版本。它的核心思想是:讓cwnd以指數增長方式迅速逼近可用通道容量,然後
慢慢接近均衡。Tahoe包括3個基本的擁塞控制演算法:慢啟動、擁塞避免、快速重傳。
我們可以看到,Tahoe不存在快速恢復演算法。這也是它的不足之處。
在收到3個重複ACK或者在超時的情況下,Tahoe置cwnd為1,然後進入慢啟動階段。這一方面會引起網
絡的激烈震盪,另一方面大大降低了網路的利用率。
也就是說,一旦發現掉包,那麼cwnd就被打回原形。
沒有快速恢復演算法,在恢復丟失資料包期間,不能傳送新的資料包,這段時間的吞吐量為0。而實際上
如果利用這段時間來發送適量的新資料包,可以大大的提高丟包時的傳輸效率。這就是快速恢復名稱的
由來。
2. Reno
Reno與Tahoe相比,增加了快速恢復階段,也就是說,完成快速重傳後,進入了擁塞避免階段而不是慢
啟動階段。
Reno prevents the communication path from going empty after Fast Retransmit.
Reno sender uses additional incoming dup ACKs to clock subsequent outgoing packets.
演算法描述:
- step1:
- if ( dupacks >= 3 ) {
- ssthresh = max( 2
- cwnd = ssthresh + 3 * SMSS ;
- }
- step2:重傳丟失的分組
- step3:此後每收到一個重複的ACK確認時,cwnd++
- step4:當收到對新發送資料的ACK確認時,cwnd = ssthresh,這個ACK能夠對那些在
- 丟失的分組之後,第一個重複ACK之前傳送的所有包進行確認。
在快速恢復階段,每收到重複的ACK,則cwnd加1;收到非重複ACK時,置cwnd = ssthresh,
轉入擁塞避免階段;如果發生超時重傳,則置ssthresh為當前cwnd的一半,cwnd = 1,重新進入
慢啟動階段。
Reno快速恢復階段退出條件:收到非重複ACK。
3. NewReno
Reno不能有效的處理多個分組從同一資料視窗丟失,於是有了NewReno。
NewReno修改了Reno的快速恢復演算法,處理一個視窗中的多個報文段同時丟失時出現的“部分確認”
(Partial ACKs,它在快速恢復階段到達並且確認新資料,但它只確認進入快速重傳之前傳送的一部分
資料)。
在這種情況下,Reno會退出快速恢復狀態,等待定時器溢位或者重複的確認ACK到達,但是NewReno
並不退出快速恢復狀態,而是:
- step1:重傳緊接著那個部分ACK之後的報文段,擁塞視窗等於其減去partial ACK的部分。
- step2:對於得到確認的新資料,cwnd++
- step3:對於第一個或每一個Partial ACK,重傳定時器復位。且每次都重置cwnd = 原cwnd / 2。
NewReno演算法中有變數recover,其值為檢測到丟包時的最大發送序列號。只有當recover之前的資料
報都確認完後,才能推出快速恢復,進入擁塞避免階段。
當超時時,將傳送的最大序列號儲存在recover變數中,結束快速恢復過程。
NewReno不支援SACK。
4. SACK
During Fast Recovery, SACK maintains a variable calledpipe that represents the estimated number
of packets outstanding in the path.
The sender only sends new or retransmitted data when the estimated number of packets in the path
is less than the congestion window. The variable pipe is incremented by one when the sender either
sends a new packet or retransmits an old packet. It is decremented by one when the sender receives
a dup ACK packet with a SACK option reporting the new data has been received at the receiver.
Use of the pipe variable decouples the decision of when to send a packet from the decision of which
packet to send.
The sender maintains a data structure, thescoreboard, that remenbers acknowledgements from
previous SACK option. When the sender is allowed to send a packet, it retransmits the next packet
from the list of packets inferred to be missing at the receiver. If there are no such packets and the
receiver's advertised window is sufficiently large, the sender sends a new packet.
When a retransmitted packet is itself dropped, the SACK implementation detects the drop with a
retransmit timeout, retransmitting the dropped packet and then slow-starting.
The sender exits Fast Recovery when a recovery acknowledgement is received acknowledging
all data that was outstanding when Fast Recovery was entered.
- step 1:
- Fast Recovery is initiated,
- pipe -1 ( for the packet assumed to have been dropped).
- pipe +1 ( for the packet retransmitted)
- cwnd = cwnd / 2
- step 2 :
- If pipe <= cwnd,sender retransmits packets inferred to be missing.
- If there are no such packets, sender sends new packets.
- step 3:
- when sender receives a dup ACK, pipe = pipe - 1
- when sender sends a new / retransmit an old packet, pipe = pipe +1
- step 4:
- For partial ACKs :pipe = pipe - 2
- (one for original dropped packet,one for retransmitted packet)
- step 5:
- all packets outstanding before Fast Recovery were ACKed,
- exit Fast Recovery.
- 當退出Fast Recovery時,cwnd同樣恢復成ssthresh,進入擁塞避免。
與Reno不同的是:
(1)when to send packet:由計算pipe變化決定,不再是計算cwnd變化。
(2)which packet to send:由SACK攜帶資訊決定,反應更迅速。
問題1:在一個視窗內重複丟包會造成影響嗎?
答案:會。如果只丟一個包,那麼收到非重複ACK時,就能確認完本視窗內所有的包。然後進入擁塞
避免階段。這就是Reno想達到的。
而如果丟失多個包,那麼收到非重複ACK時,不能確認完本視窗內所有的包。但是,也會退出快速恢復,
進入擁塞避免階段。
這個時候可能會發生兩種情況:
(1)多次進行快速重傳和快速恢復。又發現丟包,再次進入快速重傳和快速恢復。注意,每次進入
快速重傳和快速恢復時,ssthresh和cwnd都要減半。多次丟包最終會導致ssthresh指數減小。
通過畫cwnd(t)圖可以發現,不僅這段時間吞吐量非常低,而且導致恢復完後擁塞避免的起點非常低,從
而導致之後的吞吐量也很低。
(2)經過多次快速重傳和快速恢復,接著發生傳輸超時。
那麼,發生傳輸超時需要什麼樣的條件呢?
1) when two packets are dropped from a window of data, the Reno sender is forced to wait for a
retransmit timeout whenever the congestion window is less than 10 packets when Fast
Recovery is initiated, and whenever the congestion window is within two packets of the receiver's
advertised window when Fast Recovery is initiated.
2) when three packets are dropped from a window of data, the Reno sender is forced to wait for
a retransmit timeout whenever the number of packets between the first and the second dropped
packets is less than 2 + 3W/4, for W the congestion window just before the Fast Retransmit.
這種情況出現的概率極大,也就是說一個窗口出現3個丟包,有大概率出現超時。當丟包時視窗大小
為15,有三個丟包,那麼無論丟包的順序如何,2次FR/FR之後,總會出現超時。
超時一般是因為未確認的資料包 > 可以使用的cwnd,不能傳送新的資料,而網路中有沒有足夠的
重複ACK來觸發FR/FR。
問題2:為什麼發生擁塞時,還增加cwnd?
答案:在檢測到丟包時,視窗為cwnd。這時候網路中最多有cwnd個包(in_flight < cwnd )。每當收到
一個重複的ACK,則說明有資料包離開網路,達到接收端了。那麼,此時網路中還可以再容納1個包。由
於傳送端滑動視窗不能移動了,所以如果想保持in_flight,可以使cwnd++。
這樣一來,可以提高吞吐量。而實際上,在fast recovery期間傳送的新資料包比起發生丟包的cwnd來說,
已經是大大減少了。
效能分析
Tahoe沒有快速恢復機制,在丟包後,它不僅重發了一些已經成功傳輸的資料,而且在恢復期間吞吐量
也不高。
利用SACK option攜帶的資訊,我們能夠提前知道哪些資料包丟失了。NewReno每個RTT內只能恢復
一個丟失的資料包,所以如果丟失了N個數據包,那麼Fast Recovery就要持續N*RTT的時間,當N比較
大時,這是一段相當長的時間。而SACK則沒有這個限制,依靠SACK option的資訊,它能夠同時恢復
多個數據包,更加快速和平穩的恢復。
當發生同一視窗多個丟包時,SACK和NewReno最終都能夠較為快速和平穩的恢復過來。而Reno則經
常出現超時,然後再用慢啟動來恢復,這個時候Reno的表現就如同Tahoe,會造成已接受資料的重複
傳送。Reno恢復期間會出現吞吐量低、恢復時間長、不必要重發資料、恢復結束後閾值過低等一些問
題,嚴重的影響效能。
結論
經過上述分析我們可以看出:
It is a fundamental consequence of the absence of SACK that the sender has to choose between
the following strategies to recover from lost data:
(1)retransmitting at most one dropped packet per round-trip time
(2)retransmitting packets that might have already been successfully delivered.
Reno and New-Reno use the first strategy, and Tahoe uses the second.
With SACK, a sender can avoid unnecessary delays and retransmissions, resulting in improved
throughput.
SACK的不足
上面說了很多SACK的好話,現在來談談它的不足之處。
For a large BDP network where the number of packets are in flight, the procesing overhead of
SACK information at the end points can be quite overhelming because each SACK block invokes
a research into the large packet buffers of the sender for acked packets in the block, and every
recovery of a loss packet causes the same search at the receiver.
在BDP網路,這個問題尤其明顯,會嚴重的消耗CPU而導致一系列問題。在一定程度上來說,此時
的SACK就像DOS攻擊一樣,每次遍歷都要消耗大量CPU,時間複雜度為O(n^2),n為packets in
flight的數量。
The system overload can cause serious problem : it can cause multiple timeouts (as even packet
retransmission and receptions are delayed) and a long period of zero throughput.
當然,這是中等規模的BDP(100~1000)或大規模的BDP網路才需考慮的問題,對於一般的BDP而
言不會出現太大的問題。