從上一篇示例中我們可以看到在TCP中有一個重要的過程就是決定何時進行超時重傳,也就是RTO的計算更新。由于網絡狀況可能會受到路由變化、網絡負載等因素的影響,因此RTO也必須跟隨網絡狀況動態更新。如果TCP過早重傳,則可能會向網絡中注入很多重復報文,如果過晚重傳,則在丟包時候則會影響滑窗前行可能會降低網絡利用率。因為TCP在接收到數據后會發送累計的ACK number,因此TCP發送某個系列號的報文后,在接收到覆蓋此系列號的ACK報文的時候,測量發送和接收之間的時間,這個測量就叫做RTT采樣(RTT sample)。TCP對于每個連接都會根據RTT采樣來維護跟新RTO,同時還會維護一個RTO超時的定時器。注意是對每個連接維護一個超時定時器,而不是對每個發出去的TCP報文。當TCP發出數據報文(或者SYN、FIN報文)的時候,如果之前沒有等待ACK的報文則會設置這個連接的RTO定時器,如果之前有等待ACK的報文,則并不會重啟RTO定時器。當TCP同時有多個報文發出且沒有等到ACK的時候,則會先重傳第一個報文,第一個報文重傳成功收到ACK后,再設置RTO定時器然后重傳第二個報文。
本篇先來介紹一下協議中更新計算RTO的方法。協議中主要有兩種方法來計算RTO一種是RFC793的經典方法(classic method),另一種是RFC6298的標準方法(standard method)。
一、經典方法
在原始的RFC793中關于RTO更新的介紹只有半頁文字的樣子,它首先讓TCP使用下面的公式更新一個平滑RTT估計(smoothed RTT estimator、簡稱SRTT):
SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)
其中RTT是之前介紹的一個RTT采樣值,ALPHA則是一個平滑因子(smoothing factor),協議給出的示例范圍是0.8--0.9之間。這個過程也叫做指數加權移動平均(exponentially weighted moving average、簡稱EWMA)。可以看到這個計算過程只需要保留一個RTT采樣值就行了,而不需要保留過多的歷史RTT采樣。
接著在按照下面公式計算出RTO:
RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]]
其中BETA是一個延遲因子,協議給出的示例范圍是1.3--2.0。UBOUND是一個RTO上限,LBOUND是一個RTO下限,UBOUND和LBOUND協議給出的示例范圍分別是1分鐘和1秒,顯然這兩個值對于現代TCP網絡可能并不合適。
二、標準方法
RFC1122指出上面介紹的計算RTT的經典方法中存在兩個問題,一個是在發生TCP重傳的時候,RTT采樣的精確測量非常困難,第二個問題是經典方法認為RTT是比較平穩的狀態,變化比較小,因此SRTT的計算是不合適的。實際上比如在低速網絡中,TCP的數據包的不同大小會導致不同的傳輸耗時,進而可能就會導致RTT采樣值差距比較大。對于上面兩個問題第一個問題由karn算法解決,karn算法我們后續進行介紹。第二個問題由Jacobson算法解決,該算法在RTO估計中添加了一個用于反映RTT波動的RTTVAR變量。而RFC6298就是一個基于Jacobson算法的RTO計算文檔,我們把這種RTO計算方法稱為標準方法。
1、RTO計算及更新
為了計算當前的RTO,TCP發送端維護兩個狀態變量一個是SRTT(smoothed round-trip time)一個是RTTVAR (round-trip ? time variation),另外還有一個TCP時鐘粒度G。
1)、在沒有測量到有效的RTT采樣之前,設置RTO=1s;
2)、在第一個有效的RTT采樣測量出來后,假設采樣值為R,則進行如下初始化過程
SRTT = R
RTTVAR = R/2
RTO = SRTT + max(G,K*RTTVAR)
其中K = 4;
3)、當隨后的RTT采樣R’測量到以后,按照如下更新:
RTTVAR = (1 - beta) * RTTVAR + beta * |SRTT - R'|
SRTT = (1 - alpha) * SRTT + alpha * R'
注意用于計算RTTVAR的公式中的SRTT是本次更新前的值,也就是說這兩個公式的計算順序不能顛倒。其中alpha=1/8、 beta=1/4,alpha和beta的選值允許計算機通過移位做除法的快速運算。
計算出SRTT和RTTVAR后,RTO仍舊按照如下更新:
RTO = SRTT + max (G, K*RTTVAR)
4)、當RTO計算出來后,如果RTO小于1s,RTO則應該設置為1s。雖然給出的是1s的下限,但是協議允許使用更低的下限。
5)、也可以對RTO設置一個上限,協議建議上限至少為60s。
關于上面的RTT采樣,協議要求使用karn算法進行采樣,同時要求至少在一個RTT里面采樣一次(除非因為karn算法導致不可能在一個RTT里面采樣一次)。協議指出對于每個TCP報文進行RTT采樣測量不一定會得到更好的RTT估計值。
2、RTO定時器的管理
協議對于RTO定時器的建議管理方法如下:
1)、每次一個包含數據的TCP報文發送出去的時候(包括重傳),如果RTO定時器沒有運行,則重啟RTO定時器,并設置定時時間為RTO。
2)、當所有發出的數據報文都被ACK后,關閉這個RTO定時器。
3)、當一個新的ack number到達的時候(新的ack number是指ack了新數據),如果還有未被ACK的數據,則重啟RTO定時器,并設置定時時間為當前RTO。
當RTO定時器觸發的時候(即所設置的定時時間到達的時候)
4)、在還沒有ACK的報文里面重傳最早發出去的報文。
5)、設置RTO = RTO * 2,這也就是我們經常說的指數回退。也可以和上面RTO更新過程一樣添加一個同樣的上限來限制RTO大小。
6)、重啟RTO定時器,設置定時時間為RTO(這里的RTO是已經回退過的RTO)。
7)、如果RTO定時器是因為等待SYN報文的ACK而超時,如果實現上使用的RTO值小于3s,這個RTO定時器必須被重新初始化為3s。
在重傳完成后,新的RTT采樣可能會將RTO設置為與原來比較接近的值,從而消除指數回退對于RTO的影響。另外在多次指數回退過程中,TCP實現可能會清空SRTT和RTTVAR的值,一旦這兩個被清空,則需要使用上面RTO計算及更新中的第2)步來初始化SRTT和RTTVAR。
三、RTO定時器管理示例
下面的測試示例關閉了TLP功能,相關介紹見后面文章
1、RTO超時重傳成功恢復后發送的新數據又RTO超時。對于這種場景我們從下圖可以看到新發送的數據在RTO超時后,超時時間大約為1.5s,也就是說RTO定時器在之前指數回退后現在已經恢復。
2、RTO超時重傳collapse后,只回復部分ACK確認包。如下圖所示,在數據包No6超時重傳的時候,把No7數據包collapse在一起了,也就是說No8重傳包同時包含了No6和No7數據包的內容,從圖中的len字段也可以看出來,如果這時候client只是ACK確認了No6報文的內容(No12確認包Ack=1740381487正好是No7數據包的Seq),No11重傳包只有收到Ack>=1740381493時候才會取消RTO定時器,這時候部分ACK并不能取消server在發送No11時候的定時器,最終RTO超時超時重傳No13數據包,重傳的時候被部分ACK確認的數據不會在重傳,因為No13只是重傳了No7數據包。(關于重傳collapse的內容我們后面內容在進行介紹)。
3、RTO超時重傳成功后還有待重傳數據。如下圖所示,server端發出了No6和No7兩個數據包,RTO超時后重傳No6報文,No6重傳成功后server端發現還有一個No7報文等待重傳,接著在收到No11確認包后立即進行了一個快速重傳。(嚴格的說應該叫做慢啟動重傳SlowStartRetrans,但是實際上走的是快速重傳的流程,快速重傳請參考后面的內容)。快速重傳的同時會初始化一個RTO定時器,如果快速重傳失敗,接著進行RTO超時重傳(No13-No17)。這里可以看到server端在發出No12報文時候初始化的RTO定時器定時時間為1.5s。也就是之前RTO指數回退的作用已經消除了,可以看到這里與協議是存在一些差異的。
4、SACK reneging下RTO超時重傳的示例請參考后面SACK和FACK相關的內容。
TCP系列15—重傳—5、Linux中RTO的計算
之前我們介紹的都是協議中給出的RTO計算方法,下面我們看一下linux實現中RTO的計算方法.在linux中維護了srtt.mdev.mdev_max.rttvar.rtt_seq幾個狀態變量用來計算 ...
TCP系列25—重傳—15、DSACK虛假重傳探測
一.DSACK介紹 RFC2883通過指定使用SACK來指示接收端的重復包(duplicate packet)擴展了RFC2018對SACK選項的定義(SACK選項的介紹和示例參考前面內容).RFC2 ...
TCP系列11—重傳—1、TCP重傳概述
在最開始介紹TCP的時候,我們就介紹了TCP的三個特點,分別是面向連接.可靠.字節流式.前面內容我們已經介紹過了TCP的連接管理,接下來的這部分內容將會介紹與TCP可靠性強關聯的TCP重傳. 很多網絡 ...
TCP系列24—重傳—14、F-RTO虛假重傳探測
一.虛假重傳 在一些情況下,TCP可能會在沒有數據丟失的情況下初始化一個重傳,這種重傳就叫做虛假重傳(Spurious retransmission).發生虛假重傳的原因可能是包傳輸中重排序.傳輸中發 ...
TCP系列16—重傳—6、基礎快速重傳(Fast Retransmit)
一.快速重傳介紹 按照TCP協議,RTO超時重傳是一個非常重要的事件,當RTO超時的時候,TCP會同時通過兩種方式非常謹慎的降低發送數據包的速率,一種是基于擁塞控制削減發送窗口的大小,另外一個是通過指 ...
TCP系列14—重傳—4、Karn算法和TSOPT的RTTM
一.Karn算法 在RTT采樣測量過程中,如果一個數據包初傳后,RTO超時重傳,接著收到這個數據包的ACK報文,那么這個ACK報文是對應初傳TCP報文還是對應重傳TCP報文呢?這個問題就是retran ...
TCP系列21—重傳—11、TLP
一.介紹 Tail Loss Probe (TLP)是同樣是一個發送端算法,主要目的是使用快速重傳取代RTO超時重傳來處理尾包丟失場景.在一些WEB業務中,如果TCP尾包丟失,如果依靠RTO超時進行重 ...
TCP系列01—概述及協議頭格式
一.TCP簡單介紹 我們經常聽人說TCP是一個面向連接的(connection-oriented).可靠的(reliable).字節流式(byte?stream)傳輸協議, ?TCP的這三個特性該怎么 ...
TCP系列12—重傳—2、Linux超時重傳引入示例
在前面我們概述了TCP的超時重傳之后我們簡單的看一下tcp超時重傳的示例.首先簡單的描述一下測試過程 1.設置/proc/sys/net/ipv4/tcp_early_retrans為2,關掉TLP功 ...
隨機推薦
國內可用maven repository 配置
國內可用maven repository 配置 發表于2016/1/4 23:08:04 ?10235人閱讀 分類:?maven 鑒于一些原因,從maven中央倉庫download依賴包時,被各種折磨 ...
浮出層的css寫法,完美兼容IE6~10
利用元素間的絕對定位差一像素,使用不同顏色做出浮出層小三角的效果,完美兼容各瀏覽器! html部分:
搭建Android環境
1.相關文件下載: 1.1.Java jdk下載: JDK下載地址 http://www.oracle.com/technetwork/java/javase/downloads/jre7-downl ...
關于Oracle數據庫字符集的選擇
如果數據庫只在中國地區使用,數據庫字符集選擇ZHS16GBK或者常用中文字符集,如果不確定,就推薦使用AL32UTF8 國家字符集就選擇: AL16UTF16 字符集一旦設定,不允許修改,修改可能出現 ...
Spring Framework AOP具體解釋
此前對于AOP的使用僅限于聲明式事務,除此之外在實際開發中也沒有遇到過與之相關的問題.近期項目中遇到了下面幾點需求,細致思考之后,認為採用AOP來解決.一方面是為了以更加靈活的方式來解決這個問題,還有 ...
css居中問題
學習過程中遇到css居中問題 , 也查閱了資料,每個人的方法都不盡相同,而且當時看懂了,過后就記混淆了;so作為一個前端小白,也來寫一下俗話說好腦子不如爛筆頭,畢竟自己知道的也不多,其實是抱著學習和交 ...
Java開發知識之Java的異常處理
Java開發知識之Java的異常處理 一丶異常概述 在講解異常之前,我們要搞清楚.什么是異常. 通俗理解就是我們編寫的程序出問題了.進行處理的一種手段. 比如我們的QQ.有的時候就崩潰了.比如出現xx ...
C# - 操作符
操作符(Operator) C#的操作符是一種告訴編譯器執行計算.邏輯判斷的符號. default(x) 獲取類型的默認值,x是類型.雖然可以為任意類型使用此操作符,但此操作符主要用于泛型,在不確定泛 ...
Python學習(三十九)—— Django之Form組件
一.構建一個表單 假設你想在你的網站上創建一個簡單的表單,以獲得用戶的名字.你需要類似這樣的模板:
Python flask+react+antd實現登陸demo
這兩天在研究flask和antd,想把這倆個東西結合來使用,單獨學antd的時候用的是dva來配置,但是發現這樣與flask結合的話需要啟動兩個服務,作為flask只是作為數據的接口,并沒用用到其強大 ...