不管哪類場景,都是要保證可靠性,也就是質(zhì)量,那么在UDP之上怎么實現(xiàn)可靠呢?答案就是重傳。
重傳模式
IP協(xié)議在設(shè)計的時候就不是為了數(shù)據(jù)可靠到達而設(shè)計的,所以UDP要保證可靠,就依賴于重傳,這也就是我們通常意義上的RUDP行為,在描述RUDP重傳之前先來了解下RUDP基本框架,如圖:
圖2
RUDP在分為發(fā)送端和接收端,每一種RUDP在設(shè)計的時候會做不一樣的選擇和精簡,概括起來就是圖中的單元。RUDP的重傳是發(fā)送端通過接收端ACK的丟包信息反饋來進行數(shù)據(jù)重傳,發(fā)送端會根據(jù)場景來設(shè)計自己的重傳方式,重傳方式分為三類:定時重傳,請求重傳和FEC選擇重傳。
定時重傳
定時重傳很好理解,就是發(fā)送端如果在發(fā)出數(shù)據(jù)包(T1)時刻一個RTO之后還未收到這個數(shù)據(jù)包的ACK消息,那么發(fā)送就重傳這個數(shù)據(jù)包。這種方式依賴于接收端的ACK和RTO,容易產(chǎn)生誤判,主要有兩種情況:
對方收到了數(shù)據(jù)包,但是ACK發(fā)送途中丟失。
ACK在途中,但是發(fā)送端的時間已經(jīng)超過了一個RTO。
所以超時重傳的方式主要集中在RTO的計算上,如果你的場景是一個對延遲敏感但對流量成本要求不高的場景,就可以將RTO的計算設(shè)計比較小,這樣能盡最大可能保證你的延時足夠小。例如:實時操作類網(wǎng)游、教育領(lǐng)域的書寫同步,是典型的用expense換latency和Quality的場景,適合用于小帶寬低延遲傳輸。如果是大帶寬實時傳輸,定時重傳對帶寬的消耗是很大的,極端情況會用20%的重復(fù)重傳率,所以在大帶寬模式下一般會采用請求重傳模式。
請求重傳
請求重傳就是接收端在發(fā)送ACK的時候攜帶自己丟失報文的信息反饋,發(fā)送端接收到ACK信息時根據(jù)丟包反饋進行報文重傳。如下圖:
圖3
這個反饋過程最關(guān)鍵的步驟就是回送ACK的時候應(yīng)該攜帶哪些丟失報文的信息,因為UDP在網(wǎng)絡(luò)傳輸過程中會亂序會抖動,接收端在通信的過程中要評估網(wǎng)絡(luò)的jitter time,也就是rtt_var(RTT方差值),當發(fā)現(xiàn)丟包的時候記錄一個時刻t1,當t1 + rtt_var < curr_t(當前時刻),我們就認為它丟失了,這個時候后續(xù)的ACK就需要攜帶這個丟包信息并更新丟包時刻t2,后續(xù)持續(xù)掃描丟包隊列,如果他t2 + RTO <curr_t,再次在ACK攜帶這個丟包信息,以此類推,直到收到報文為止。這種方式是由丟包請求引起的重發(fā),如果網(wǎng)絡(luò)很不好,接收端會不斷發(fā)起重傳請求,造成發(fā)送端不停的重傳,引起網(wǎng)絡(luò)風(fēng)暴,通信質(zhì)量會下降,所以我們在發(fā)送端設(shè)計一個擁塞控制模塊來限流,這個后面我們重點分析。除了網(wǎng)絡(luò)風(fēng)暴以外,整個請求重傳機制也依賴于jitter time和RTO這個兩個時間參數(shù),評估和調(diào)整這兩個參數(shù)和對應(yīng)的傳輸場景也息息相關(guān)。請求重傳這種方式比定時重傳方式的延遲會大,一般適合于帶寬較大的傳輸場景,例如:視頻、文件傳輸、數(shù)據(jù)同步等。
FEC選擇重傳
除了定時重傳和請求重傳模式以外,還有一種方式就是以FEC分組方式選擇重傳,F(xiàn)EC(Forward Error Correction)是一種前向糾錯技術(shù),一般是通過XOR類似的算法來實現(xiàn),也有多層的EC算法和raptor涌泉碼技術(shù),其實是一個解方程的過程。應(yīng)用到RUDP上示意圖如下:
圖4
在發(fā)送方發(fā)送報文的時候,會根據(jù)FEC方式把幾個報文進行FEC分組,通過XOR的方式得到若干個冗余包,然后一起發(fā)往接收端,如果接收端發(fā)現(xiàn)丟包但能通過FEC分組算法還原,就不向發(fā)送端請求重傳,如果分組內(nèi)包是不能進行FEC恢復(fù)的,就請求想發(fā)送端請求原始的數(shù)據(jù)包。FEC分組方式適合解決要求延時敏感且隨機丟包的傳輸場景,在一個帶寬不是很充裕的傳輸條件下,F(xiàn)EC會增加多余的冗余包,可能會使得網(wǎng)絡(luò)更加不好。FEC方式不僅可以配合請求重傳模式,也可以配合定時重傳模式。