五分鐘技術(shù)趣談 | 淺談網(wǎng)絡(luò)傳輸中的錯誤恢復(fù)機(jī)制
在網(wǎng)絡(luò)傳輸中,隨機(jī)丟包是一種常見且不可避免的現(xiàn)象,常見的隨機(jī)丟包原因有:
1??網(wǎng)絡(luò)擁塞:當(dāng)網(wǎng)絡(luò)擁塞時,網(wǎng)絡(luò)設(shè)備(如路由器、交換機(jī)等)會出現(xiàn)緩存溢出、隊列滿等情況,導(dǎo)致數(shù)據(jù)包無法及時處理,從而出現(xiàn)丟包現(xiàn)象。
2??傳輸錯誤:數(shù)據(jù)包可能會因為傳輸介質(zhì)的問題或者傳輸過程中的干擾等原因?qū)е聰?shù)據(jù)包損壞,無法通過網(wǎng)絡(luò)數(shù)據(jù)正確性校驗,數(shù)據(jù)包被丟棄導(dǎo)致丟包現(xiàn)象。
此外,數(shù)據(jù)包的亂序也是網(wǎng)絡(luò)傳輸中的常見現(xiàn)象,當(dāng)網(wǎng)絡(luò)擁塞時,不同數(shù)據(jù)包在傳輸過程中可能會經(jīng)過不同路徑,而不同路徑的帶寬和延遲不同導(dǎo)致數(shù)據(jù)包亂序到達(dá)。
為解決隨機(jī)丟包與亂序的問題,各個傳輸控制協(xié)議分別引入了各自的錯誤恢復(fù)機(jī)制,比較典型的是:TCP引入了ACK,UDP引入了NACK,下面我們對ACK和NACK進(jìn)行分析比較。
Part 01
ACK實現(xiàn)原理
ACK是一種正向反饋,接收方收到數(shù)據(jù)后回復(fù)消息告知發(fā)送方數(shù)據(jù)包已收到。ACK要求TCP包頭中包含一個唯一ID(SeqNum),接收端收到數(shù)據(jù)包后發(fā)送“確認(rèn)當(dāng)前SeqNum已收到”的數(shù)據(jù)包給發(fā)送端,發(fā)送端收到確認(rèn)包即認(rèn)為數(shù)據(jù)發(fā)送成功。
常見的ACK實現(xiàn)如下??
1.1 停等協(xié)議
發(fā)送方A發(fā)送數(shù)據(jù), 每發(fā)送一個數(shù)據(jù)包就停止發(fā)送,開啟定時器并等待接收方B發(fā)送確認(rèn), 收到確認(rèn)后A關(guān)閉定時器,發(fā)送下一個數(shù)據(jù)包。若超過定時器設(shè)置的超時時間,則數(shù)據(jù)包發(fā)送失敗,重新發(fā)送數(shù)據(jù)包并重啟定時器。
圖1 停等協(xié)議數(shù)據(jù)交互示意圖
停等協(xié)議一次只能發(fā)送一個數(shù)據(jù)包,保證了準(zhǔn)確性但犧牲了效率,對帶寬的利用率也不高。
1.2 快速重傳&滑窗協(xié)議
使用 ACK 機(jī)制的傳輸協(xié)議,通常在發(fā)送端等到某個數(shù)據(jù)包的 ACK 超時后,才會重傳數(shù)據(jù)包,不夠及時。快速重傳的實現(xiàn)是如果接收端接收到了序號跳躍的數(shù)據(jù)包,則立即給發(fā)送方發(fā)送最后一個連續(xù)的數(shù)據(jù)包的 ACK(重復(fù)確認(rèn)) 。如果發(fā)送端收到連續(xù) 3 個重復(fù)確認(rèn),則認(rèn)為該 ACK 的下一個數(shù)據(jù)包丟失了,并立即重傳該丟失的數(shù)據(jù)包。
圖2 快速重傳&滑窗協(xié)議數(shù)據(jù)交互示意圖
觸發(fā)快速重傳之后,重傳的方案有以下兩種,具體采取哪種方案依賴于具體實現(xiàn):
a.僅重傳包M1,在較少丟包的時候該方案比較適用,但是如果是連續(xù)丟包場景,會不斷的觸發(fā)快速重傳,性能反而較差。
b.從M1開始重傳所有包,適用于連續(xù)丟包場景,但是較少丟包或亂序時,M1之后已被接收的包也會被重發(fā),浪費網(wǎng)絡(luò)資源。
快速重傳協(xié)議保留了超時時間機(jī)制,超時后數(shù)據(jù)包重發(fā),引入快速重傳機(jī)制可以更快的發(fā)現(xiàn)數(shù)據(jù)包丟失,在未到達(dá)超時時間時便可提前重發(fā)數(shù)據(jù)并重啟定時器。
1.3 連續(xù)ARQ協(xié)議&滑窗協(xié)議
發(fā)送方維持著一個一定大小的發(fā)送窗口,位于發(fā)送窗口內(nèi)的所有包可以連續(xù)發(fā)送出去,中途不需要依次等待對方的ACK確認(rèn)。
接收方通常采用積累確認(rèn)模式,即不必對每一個包逐個發(fā)送ACK,而是在連續(xù)收到N個包后,對順序到達(dá)的最后一個包序號發(fā)送ACK,表示這個包及之前的所有包都已正確收到了,其中N會根據(jù)網(wǎng)絡(luò)狀況和協(xié)議設(shè)計而有所不同。
圖3 連續(xù)ARQ協(xié)議&滑窗協(xié)議數(shù)據(jù)交互示意圖
連續(xù)ARQ協(xié)議保留了超時時間機(jī)制,超時后數(shù)據(jù)包重發(fā)。
連續(xù)ARQ協(xié)議中,在收到確認(rèn)包(M4)后,之前的所有包(M1、M2、M3)也被確認(rèn)。
與快速重傳協(xié)議相比,連續(xù)ARQ協(xié)議減少了確認(rèn)包的數(shù)目,節(jié)省了帶寬。但連續(xù)ARQ協(xié)議在確認(rèn)到丟包(M7)之后,處于丟包(M7)之后已被接收的包(M8)也會被重發(fā),浪費網(wǎng)絡(luò)資源,降低網(wǎng)絡(luò)響應(yīng)速度。
1.4 SACK協(xié)議&滑窗協(xié)議
SACK協(xié)議是在連續(xù)ARQ協(xié)議上的優(yōu)化,通過在確認(rèn)包頭中增加已經(jīng)接收到并緩存的不連續(xù)的報文段,避免丟包之后已被接收的包(圖3中M8)也會被重發(fā),從而節(jié)省帶寬,加快網(wǎng)絡(luò)響應(yīng)速度。
圖4 SACK協(xié)議&滑窗協(xié)議數(shù)據(jù)交互示意圖
需要注意的是,SACK并不是TCP的默認(rèn)項,需要通信雙方均開啟SACK功能支持。
對于以上四個方案,整體性能評價為SACK協(xié)議>ARQ協(xié)議≈快速重傳協(xié)議>停等協(xié)議。特別是針對亂序場景:
(1)SACK可以避免重發(fā)接收端已經(jīng)接受的包;
(2)快速重傳策略a也可避免重發(fā)接收端已經(jīng)接受的包,但是卻引入了連續(xù)丟包場景不斷觸發(fā)快速重傳的問題;
(3)快速重傳策略b、ARQ協(xié)議無法避免重發(fā)接收端已經(jīng)接受的包。
快速重傳和連續(xù)ARQ相比,各有其適用的場景,快速重傳適用于數(shù)據(jù)傳輸延遲要求較高的場景,如實時視頻傳輸;而連續(xù)ARQ適用于數(shù)據(jù)傳輸可靠性要求較高的場景,如文件傳輸。
Part 02
NACK實現(xiàn)原理
NACK是一種負(fù)向反饋,接收方只有在沒有收到數(shù)據(jù)的時候才通知發(fā)送方。NACK要求UDP包頭中包含一個唯一ID(SeqNum),接收端收到數(shù)據(jù)包后,檢查SeqNum是否連續(xù),記錄缺失的SeqNum,等待定時發(fā)送NACK請求,要求發(fā)送端重發(fā)。
圖5 NACK協(xié)議數(shù)據(jù)交互示意圖
定時發(fā)送NACK的時間由用戶自定義,一般為20ms,在一個定時發(fā)送周期內(nèi)到達(dá)的亂序包不會請求重發(fā),但不在一個定時發(fā)送周期內(nèi)到達(dá)的亂序包會冗余重發(fā)。
Part 03
ACK與NACK性能對比
由于SACK性能在ACK中最佳,因此我們只比較NACK與SACK。
- SACK的確認(rèn)包丟失可能會導(dǎo)致數(shù)據(jù)包發(fā)送超時,重發(fā)接收端已接收的數(shù)據(jù)包;NACK反饋包丟失,下一個反饋包會攜帶上一個反饋包的信息。NACK避免了已接收數(shù)據(jù)包的重發(fā),但因為缺少超時機(jī)制,發(fā)送端丟包重發(fā)完全依賴于NACK反饋包,重傳靈敏度略低于SACK。
- 受限于TCP滑動窗口的大小(100-200個),SACK必須等待滑動窗口中的數(shù)據(jù)全部發(fā)送才能向后繼續(xù)發(fā)送新的數(shù)據(jù)包,這會引入部分時延;NACK歷史數(shù)據(jù)隊列完全由用戶控制,無此限制(一般為1000個或2s內(nèi)數(shù)據(jù))。
- 受限于TCP頭的大小,SACK一個確認(rèn)包中只能攜帶3組提前收到確認(rèn)數(shù)據(jù),在強(qiáng)丟包場景下性能退化嚴(yán)重,很容易導(dǎo)致冗余重發(fā);NACK在強(qiáng)丟包場景下性能略微退化,會導(dǎo)致部分冗余重發(fā),但優(yōu)于SACK。
綜上,在網(wǎng)絡(luò)數(shù)據(jù)較好時,NACK與SACK各有優(yōu)劣;在強(qiáng)丟包環(huán)境中,NACK性能強(qiáng)于SACK。但個人認(rèn)為在強(qiáng)丟包環(huán)境中,SACK策略與NACK策略仍是各有優(yōu)劣,但SACK受限于TCP的框架,導(dǎo)致性能不如NACK。
總的來說,基于TCP的SACK適用于效率要求較低、但準(zhǔn)確性要求較高的場景,例如文件傳輸、接收郵件、遠(yuǎn)程登錄;基于UDP的NACK適用于效率要求較高,但準(zhǔn)確性要求不高的場景,例如實時音視頻、快直播、家庭教育、在線視頻觀看等類直播場景。