1. 程式人生 > >TCP的超時重傳之深入瞭解RTT與RTO

TCP的超時重傳之深入瞭解RTT與RTO

TCP提供一種面向連線的、可靠的位元組流服務,其中可靠的保證方法之一就是卻讓從另一端收到的資料。但是資料和確認訊號都有可能丟失,。TCP通過在傳送資料時設定一個重傳定時器(注意這裡的超時定時器和第四節講的定時器不一樣)來監控資料的丟失狀態,如果重傳定時器溢位時還沒收到確認訊號,則重傳該資料。這就是建立重傳機制的原因。
下面解釋兩個名詞:
RTT(Round Trip Time):一個連線的往返時間,即資料傳送時刻到接收到確認的時刻的差值;
RTO(Retransmission Time Out):重傳超時時間,即從資料傳送時刻算起,超過這個時間便執行重傳。
RTT和RTO 的關係是:由於網路波動的不確定性,每個RTT都是動態變化的,所以RTO也應隨著RTT動態變化。

一、RTT估計器

首先要明白一個問題,為什麼要做一個RTT估計器?在開篇就講到了TCP連線在重傳定時器溢位就會重傳資料。那麼溢位時間怎麼計算,即RTO如何計算?如果設定過短,則會造成重傳頻繁,加快網路阻塞;設定過長,則會導致效能下降(失序的報文段得不到確認,接收方無法提交給程序)。所以,超時計算的演算法應該能夠反映當前網路的擁塞情況,而每個連線的RTT恰恰能夠反映這一點,所以設計好的RTT估計器是計算 RTO 的第一步。
由於大多數的TCP實現僅僅在某一時刻為一個已傳送但尚未確認的報文段做一次RTT取樣,得到一個SampleRTT,而不是為每一個傳送的報文段都測量RTT,從而用這個SampleRTT來接近(代表)所有RTT。

  • 一個連線中,有且僅有一個測量定時器被使用。也就是說,如果TCP連續發出3組資料,只有一組資料會被測量。
  • TCP決不會為已被重傳的報文段測量SampleRTT,僅僅為傳輸一次的報文段測量SampleRTT。
  • ACK資料報不會被測量,原因很簡單,沒有ACK的ACK迴應可以供結束定時器測量。

由於路由器的擁塞和端系統負載的變化,由於這種波動,用一個報文段所測的SampleRTT來代表同一段時間內的RTT總是非典型的,為了得到一個典型的RTT,TCP規範中使用低通過濾器來更新一個被平滑的RTT估計器。TCP維持一個估計RTT(稱之為EstimatedRTT),一旦獲得一個新SampleRTT時,則根據下式來更新EstimatedRTT:
EstimatedRTT = (1-a)* EstimatedRTT + a * SampleRTT
其中a通常取值為0.125,即:

EstimatedRTT = 0.875 * EstimatedRTT + 0.125 * SampleRTT

每個新的估計值的87.5%來自前一個估計值,而12.5%則取自新的測量。

關於估計器的更新:
在一個報文段被髮送和確認之前阻止更新估計器。

二、RTT的方差跟蹤

在最初的RTO演算法中,RTO等於一個值為2的時延離散因子與RTT估計值的乘積,即:

RTO = 2*EstimatedRTT

但這種做法有個很大的缺陷,就是在RTT變化範圍很大的時候,使用這個方法無法跟上這種變化,從而引起不必要的重傳。怎麼理解呢?由於新測量SampleRTT的權值只佔EstimatedRTT的12.5%,當實際RTT變化很大的時候,即便測量到的SampleRTT變化也很大,但是所佔比重小,最後EstimatedRTT的變化也不大,從而RTO的變化不大,造成RTO過小,容易引起不必要的重傳。因此對RTT的方差跟蹤則顯得很有必要。
在TCP規範中定義了RTT偏差DevRTT,用於估算SampleRTT一般會偏離EstimatedRTT的程度:

DevRTT = (1-B)*DevRTT + B*|SampleRTT - EstimatedRTT|

其中B的推薦值為0.25,當RTT波動很大的時候,DevRTT的就會很大。

三、設定重傳時間間隔RTO

如上面所述得到了EstimatedRTT和DevRTT,很明顯超時時間間隔RTO應該大於等於EstimatedRTT,但要大多少才比較合適呢?所以選擇DevRTT作為餘量,當波動大時餘量大,波動小時,餘量小。則組後超時重傳時間間隔RTO的計算公式為:

RTO = EstimatedRTT + 4 * DevRTT

在[RFC 6298]中,推薦初始超時重傳時間為1秒,當出現超時後,超時重傳時間將以指數退避的方法加倍,以免即將被確認的後繼報文段過早出現超時。不管如何,一旦報文段收到並更新EstimatedRTT 後,超時重傳時間便會按上式計算。具體闡述如下:
超時間隔加倍:
假設當前超時重傳定時器溢位時,與最早的未被確認的報文段相關聯的RTO為0.75s,TCP就會重傳報文段,並版新的RTO設定為1.5s,如果1.5s後又溢位了,則TCP將再次重傳報文段,並把RTO設定為3秒。因此,超時間隔在每次重傳後會呈指數上升,然而每當重傳定時器在另外兩個事件(收到上層應用的資料和收到ACK)中的任意一個啟動時,RTO有最近的EstimatedRTT 和DevRTT重新計算。

四、實際RTT和RTO測量

首先在這裡要區分重傳定時器和TCP連線可供呼叫的時鐘定時器。

  • 重傳定時器:當TCP傳送報文段時,就建立這個特定報文段的重傳定時器,若在定時器超時之前收到對報文段的確認,則撤銷定時器;若在收到對特定報文段的確認之前計時器超時,則重傳該報文,並且進行RTO = 2 * RTO進行退避。
  • 可供呼叫的TCP時鐘定時器:一個TCP連線只有一個這樣的定時器用於測量RTT,一般情況下是500ms定時器,並且只能夠被一個報文段佔用,即在傳送一個報文段時,如果給定連線的定時器已經被使用,則該報文段不被計時(不計算該報文段的RTT,這就解釋了不是所有報文段都能被計算RTT)。(這裡的定時器應該是呼叫系統時鐘)

分組交換和RTT測量
好,回到RTT的測量上來。實際中RTT的測量並不是那麼精確,比如說一個報文段的確認訊號在它傳送550ms後到達,那麼該報文段的往返時間RTT將是500ms或者1000ms(假設使用500ms定時器計時)。為什麼會這樣呢?因為在呼叫500ms定時器的同時會增加一個計數器來輔助計時,計數器的每一個滴答(tick)代表定時器轉好一圈500ms,兩個滴答則表示1000ms。可惜的是定時器和計數器做不到無誤差的同時啟動,往往計數器會在定時器啟動的一段時間內啟動,但間隔很小。
RTT測量和時鐘滴答

從圖上可以看到時間間隔為500ms的時鐘滴答,報文段1在0處發出(同時定時器開始啟動)假設計數器在定時器啟動0.03s後開始計數,報文段1 的確認在1.061s出收到,那麼在傳送報文段1和接收到報文段1的確認訊號之間經歷了3個滴答,所以報文段1的RTT為1500ms。之後的RTT也是這麼計算。所以說得到的實際RTT總是500ms的倍數。

在公式初始化重傳超時公式的時候中,常常使用:

RTO = EstimatedRTT + 2 * DevRTT只有在初始化的時候係數為2,之後的係數仍為4。

EstimatedRTT初始化為0,DevRTT的初始值隨TCP版本實現不同而定。而後每次根據測量的RTT對RTO進行更新。實際上RTO的值也基本上是500ms的倍數,這是由於通常情況下餘量的波動並不會很大。