網絡擁塞是基於IP協議的數據報交換網絡中常見的一種網絡傳輸問題,它對網絡傳輸的質量有嚴重的影響,網絡擁塞是致使網絡吞吐下降,網絡丟包等的主要緣由之一,這些問題使得上層應用沒法有效的利用網絡帶寬得到高質量的網絡傳輸效果。特別是在通訊領域,網絡擁塞致使的丟包,延遲,抖動等問題,嚴重的影響了通訊質量,若是不能很好的解決這些問題,一個通訊產品就沒法在現實環境中正常使用。在這方面WebRTC中的網絡擁塞控制算法給咱們提供了一個可供參考的實現,本篇文章會盡可能詳細的介紹WebRTC中的擁塞控制算法---GCC的實現方式。html
相關閱讀推薦web
WebRTC簡介算法
WebRTC是一個Web端的實時通訊解決方案,它能夠作到在不借助外部插件的狀況下,在瀏覽器中實現點對點的實時通訊。WebRTC已經由W3C和IETF標準化,最先推出和支持這項技術的瀏覽器是Chrome, 其餘主流瀏覽器也正在陸續支持。Chrome中集成的WebRTC代碼已所有開源,同時Chrome提供了一套LibWebRTC的代碼庫,使得這套RTC架構能夠移植到其餘APP當中,提供實時通訊功能。瀏覽器
GCC算法概述服務器
本文主要介紹的是WebRTC的擁塞控制算法,WebRTC的傳輸層是基於UDP協議,在此之上,使用的是標準的RTP/RTCP協議封裝媒體流。RTP/RTCP自己提供不少機制來保證傳輸的可靠性,好比RR/SR, NACK,PLI,FIR, FEC,REMB等,同時WebRTC還擴展了RTP/RTCP協議,來提供一些額外的保障,好比Transport-CCFeedback, RTP Transport-wide-cc extension,RTP abs-sendtime extension等,其中一些後文會詳細介紹。網絡
GCC算法主要分紅兩個部分,一個是基於丟包的擁塞控制,一個是基於延遲的擁塞控制。在早期的實現當中,這兩個擁塞控制算法分別是在發送端和接收端實現的,接收端的擁塞控制算法所計算出的估計帶寬,會經過RTCP的remb反饋到發送端,發送端綜合兩個控制算法的結果獲得一個最終的發送碼率,並以此碼率發送數據包。下圖即是展示的該種實現方式:session
從圖中能夠看到,Loss-Based Controller在發送端負責基於丟包的擁塞控制,它的輸入比較簡單,只須要根據從接收端反饋的丟包率,就能夠作帶寬估算;上圖右側比較複雜,作的是基於延遲的帶寬估計,這也是本文後面主要介紹的部分。在最近的WebRTC實現中,GCC把它的兩種擁塞控制算法都移到了發送端來實現,可是兩種算法自己並無改變,只是在發送端須要計算延遲,於是須要一些額外的feedback信息,爲此WebRTC擴展了RTCP協議,其中最主要的是增長了Transport-CC Feedback,該包攜帶了接收端接收到的每一個媒體包的到達時間。架構
基於延遲的擁塞控制比較複雜,WebRTC使用延遲梯度來判斷網絡的擁塞程度,延遲梯段的概念後文會詳細介紹;ide
其算法分爲幾個部分:測試
l 到達時間濾波器
l 過載檢測器
l 速率控制器
在得到兩個擁塞控制算法分別結算到的發送碼率以後,GCC最終的發送碼率取的是兩種算法的最小值。下面咱們詳細介紹WebRTC的擁塞控制算法GCC。
(一)基於丟包的帶寬估計
基於丟包的擁塞控制比較簡單,其基本思想是根據丟包的多少來判斷網絡的擁塞程度,丟包越多則認爲網絡越擁塞,那麼咱們就要下降發送速率來緩解網絡擁塞;若是沒有丟包,這說明網絡情況很好,這時候就能夠提升發送碼率,向上探測是否有更多的帶寬可用。實現該算法有兩點:一是得到接收端的丟包率,一是肯定下降碼率和提高碼率的閾值。
WebRTC經過RTCP協議的Receive Report反饋包來獲取接收端的丟包率。Receive Report包中有一個lost fraction字段,包含了接收端的丟包率,以下圖所示。
另外,WebRTC經過如下公式來估算髮送碼率,式中 As(tk) 即爲 tk 時刻的帶寬估計值,fl(tk)即爲 tk 時刻的丟包率:
------ (1)
簡單來講,當丟包率大於10%時則認爲網絡有擁塞,此時根據丟包率下降帶寬,丟包率越高帶寬降的越多;當丟包率小於2%時,則認爲網絡情況很好,此時向上提升5%的帶寬以探測是否有更多帶寬可用;2%到10%之間的丟包率,則會保持當前碼率不變,這樣能夠避免一些網絡固有的丟包被錯判爲網絡擁塞而致使下降碼率,而這部分的丟包則須要經過其餘的如NACK或FEC等手段來恢復。
(二)基於延遲梯度的帶寬估計
WebRTC實現的基於延遲梯度的帶寬估計有兩種版本:
l 最先一種是在接受端實現,評估的帶寬結果經過RTCP REMB消息反饋到發送端。在此種實現中,爲了準確計算延遲梯度,WebRTC添加了一種RTP擴展頭部abs-send-time, 用來表示每一個RTP包的精確發送時間,從而避免發送端延遲給網絡傳播延遲的估計帶來偏差。這種模式也是RFC和google的paper中描述的模式。
l 在新近的WebRTC的實現中,全部的帶寬估計都放在了發送端,也就說發送端除了作基於丟包的帶寬估計,同時也作基於延遲梯度的帶寬估計。爲了可以在接受端作基於延遲梯度的帶寬估計,WebRTC擴展了RTP/RTCP協議,其一是增長了RTP擴展頭部,添加了一個session級別的sequence number, 目的是基於一個session作反饋信息的統計,而不牢牢是一條音頻流或視頻流;其二是增長了一個RTCP反饋信息transport-cc-feedback,該消息負責反饋接受端收到的全部媒體包的到達時間。接收端根據包間的接受延遲和發送間隔能夠計算出延遲梯度,從而估計帶寬。
關於如何根據延遲梯度推斷當前網絡情況, 後面會分幾點詳細展開講, 整體來講分爲如下幾個步驟:
l 到達時間濾波器
l 過載檢測器
l 速率控制器
其過程就是,到達時間濾波器根據包間的到達時延和發送間隔,計算出延遲變化,這裏會用到卡爾曼濾波對延遲變化作平滑以消除網絡噪音帶來的偏差;延遲變化會做爲過載檢測器的輸入,由過載檢測器判斷當前網絡的狀態,有三種網絡狀態返回overuse/underuse/normal,檢測的依據是比較延遲變化和一個閾值,其中該閾值很是關鍵且是動態調整的。最後根據網絡狀態的變化,速率控制器根據一個帶寬估計公式計算帶寬估計值。
(三)到達時間濾波器
前面屢次提到WebRTC使用延遲梯度來判斷網絡擁塞情況,那什麼是延遲梯度,爲何延遲梯度能夠做爲判斷網絡擁塞的依據,咱們在這裏詳細介紹,首先來看如下,延遲梯度是怎樣計算出來的:
1. 延遲梯度的計算
如上圖所示,用兩個數據包的到達時間間隔減去他們的發送時間間隔,就能夠獲得一個延遲的變化,這裏咱們稱這個延遲的變化爲單向延遲梯度(one way delay gradient),其公式可記爲:
(2)
那麼爲何延遲梯度能夠用來判斷網絡擁塞的呢,以下面兩圖所示:
左邊這幅圖的場景是理想情況下的網絡傳輸,沒有任何擁塞,按咱們上面提到的公式(2)來計算,這種場景下,所計算到的延遲梯度應該爲0。而右邊這幅圖的場景則是發送擁塞時的情況,當包在t2時刻到達時,該報在網絡中經歷過一次因擁塞致使的排隊,這致使他的到達時間比本來要完,此時計算出的延遲梯度就爲一個較大的值,經過這個值,咱們就能判斷當前網絡正處在擁塞狀態。
在WebRTC的具體實現中,還有一些細節來保證延遲梯度計算的準確性,總結以下:
l 因爲延遲梯度的測量精度很小,爲了不網絡噪音帶來的偏差,利用了卡爾曼濾波來平滑延遲梯度的測量結果。
l WebRTC的實現中,並非單純的測量單個數據包彼此之間的延遲梯度,而是將數據包按發送時間間隔和到達時間間隔分組,計算組間的總體延遲梯度。分組規則是:
1) 發送時間間隔小於5ms的數據包被歸爲一組,這是因爲WebRTC的發送端實現了一個平滑發送模塊,該模塊的發送間隔是5ms發送一批數據包。
2) 到達時間間隔小於5ms的數據包被歸爲一組,這是因爲在wifi網絡下,某些wifi設備的轉發模式是,在某個固定時間片內纔有機會轉發數據包,這個時間片的間隔可能長達100ms,形成的結果是100ms的數據包堆積,並在發送時造成burst,這個busrt內的全部數據包就會被視爲一組。
l 爲了計算延遲梯度,除了接收端要反饋每一個媒體包的接受狀態,同時發送端也要記錄每一個媒體包的發送狀態,記錄其發送的時間值。在這個狀況下abs-send-time擴展再也不須要。
2. transport-cc-feedback消息
l 該消息是對RTCP的一個擴展,專門用於在GCC中反饋數據包的接受狀況。這裏有兩點須要注意:
l 該消息的發送速率如何肯定,按RFC[2]中的說明,能夠是收到每一個frame發送一次,另外也指出能夠是一個RTT的時間發送一次,實際WebRTC的實現中大約估計了一個發送帶寬的5%這樣一個發送速率。
l 若是這個數據包丟失怎麼辦,RFC[2]和WebRTC實現中都是直接忽略,這裏涉及的問題是,忽略該包對計算延遲梯度影響不大,只是至關於數據包的分組跨度更大了,丟失的包對計算沒有太大影響,但另外一個問題是,發送端須要計算接受端的接受速率,當feedback丟失時,會認爲相應的數據包都丟失了,這會影響接受速率的計算,這個值在後續計算估計帶寬中會用到,從而致使必定偏差。
具體消息格式以下:
如上圖所示,紅框以前的字段是RTCP包的通用字段,紅框中的字段爲transport-cc的具體內容,其中前四個字段分別表示:
l base sequence number:當前包攜帶的媒體包的接受信息是從哪一個包開始的
l packet status count:當前包攜帶了幾個媒體包的接受信息
l reference time:一個基準時間,計算該包中每一個媒體包的到達時間都要基於這個基準時間計算
l fb pkt. count:第幾個transport-cc包
在此以後,是兩類信息:多個packet chunk字段和多個recv delta字段。其中pcaket chunk具體含義以下:
以下兩圖所示, 表示媒體包到達狀態的結構有兩種編碼方式, 其中 T 表示chunk type;0表示RunLength Chunk, 1表示Status Vector Chunk.
1)Run LengthChunk
這種表示方式是用於,當咱們連續收到多個數據包,他們都有相同的到達狀態,就能夠用這種編碼方式。其中S表示的是到達狀態,Run Length表示有多少個連續的包屬於這一到達狀態。
到達狀態有三種:
00 Packet not received
01 Packet received, small delta (所謂small detal是指能用一個字節表示的數值)
10 Packet received, large ornegative delta (large便是能用兩個字節表示的數值)
2) Status Vector Chunk
這種表示方式用於每一個數據包都須要本身的狀態表示碼,固然仍是上面提到的那三種狀態。可是這裏的S就不是上面的意思,這裏的S指的是symbol list的編碼方式,s = 0時,表示symbollist的每個bit能表示一個數據包的到達狀態,s = 1時表示每兩個bit表示一個數據包的狀態。
s = 0 時
0 Packet not received
1 Packet received , small detal
s = 1 時
同 Run Length Chunk
最後,對於每個狀態爲Packet received 的數據包的延遲依次填入|recv delta|字段,到達狀態爲1的,recv delta佔用一個字節,到達狀態爲2的,recv delta佔用兩個字節能夠看出以上編碼的目的是爲了儘可能減小該數據包的大小,由於每一個媒體包都須要反饋他的接受狀態。
(四)過載檢測器
到達時間濾波器計算出每組數據包的延遲梯度以後,就要據此判斷當前的網絡擁塞狀態,經過和某個閾值的比較,高過某個閾值就認爲時網絡擁塞,低於某個閾值就認爲網路狀態良好,所以如何肯定閾值就相當重要。這就是過載檢測器的主要工做,它主要有兩部分,一部分是肯定閾值的大小,另外一部分就是依據延遲梯度和閾值的判斷,估計出當前的網絡狀態,一共有三種網絡狀態: overuse underuse normal,咱們先看網絡狀態的判斷。
1. 網絡狀態判斷
判斷依據入下圖所示:
其中表示的是計算出的延遲梯,表示的是一個判斷閾值,這個閾值是自適應的, 後面還會介紹他是怎麼動態調整的,這裏先只看如何根據這兩個值判斷當前網絡狀態。
從上圖能夠看出,這裏的判斷方法是:
這樣計算的依據是,網絡發生擁塞時,數據包會在中間網絡設備中排隊等待轉發,這會形成延遲梯度的增加,當網絡流量回落時,網絡設備快速消耗(轉發)其發送隊列中的數據包,然後續的包排隊時間更短,這時延遲梯度減少或爲負值。
這裏了須要說明的是:
l 在實際WebRTC的實現中,雖然每一個數據包組(前面提到了如何分組)的到達都會觸發這個探測過程,可是使用的m(ti)這個值並非直接使用每組數據到來時的計算值,而是將這個值放大了60倍。這麼作的目的多是m(ti)這個值一般狀況下很小,理想網絡下基本爲0,放大該值可使該算法不會應爲太靈敏而波動太大。
l 在判斷是否overuse時,不會一旦超過閾值就改變當前狀態,而是要知足延遲梯度大於閾值至少持續100ms,纔會將當前網絡狀態判斷爲overuse。
2. 自適應閾值
上節提到的閾值值,它是判斷當前網絡情況的依據,因此如何肯定它的值也就很是重要了。雖然理想情況下,網絡的延遲梯度是0,可是實際的網絡中,不一樣轉發路徑其延遲梯度仍是有波動的,波動的大小也是不同的,這就致使若是設置固定的 太大可能沒法探測到擁塞,過小又太敏感,致使速率了變化很大。同時,另一個問題是,實驗中顯示固定的值會致使在和TCP連接的競爭中,本身被餓死的現象(TCP是基於丟包的擁塞控制),所以WebRTC使用了一種自適應的閾值調節算法,具體以下:
(1) 自適應算法
------(3)
上面的公式就是GCC提出的閾值自適應算法,其中:,每組數據包會觸發一次探測,同時更新一次閾值,這裏的意義就是距上次更新閾值時的時間間隔。
是一個變化率,或者叫增加率,固然也有多是負增加,增加的基值是:當前的延遲梯度和上一個閾值的差值---。其具體的取值以下:
------(4)
其中:ku = 0.01; kd = 0.00018
從這個式子中能夠看出,當延遲梯度減少時,閾值會以一個更慢的速率減少; 延遲梯度增長時,閾值也會以一個更慢的速度增長;不過相對而言,閾值的減少速度要小於增長速度。
(五)速率控制器
速率控制器主要實現了一個狀態機的變遷,並根據當前狀態來計算當前的可用碼率,狀態機以下圖所示:
速率控制器根據過載探測器輸出的信號(overuse underusenormal)驅動速率控制狀態機, 從而估算出當前的網絡速率。從上圖能夠看出,當網絡擁塞時,會收到overuse信號,狀態機進入「decrease」狀態,發送速率下降;當網絡中排隊的數據包被快速釋放時,會受到underuse信號,狀態機進入「hold」狀態。網絡平穩時,收到normal信號,狀態機進入「increase」狀態,開始探測是否能夠增長髮送速率。
在Google的paper[3]中,計算帶寬的公式以下:
------(5)
其中 = 1.05, =0.85。從該式中能夠看到,當須要Increase時,之前一次的估算碼率乘以1.05做爲當前碼率;當須要Decrease時,以當前估算的接受端碼率(Rr(ti))乘以0.85做爲當前碼率;Hold狀態不改變碼率。
最後,將基於丟包的碼率估計值和基於延遲的碼率估計值做比較,其中最小的碼率估價值將做爲最終的發送碼率。
以上即是WebRTC中的擁塞控制算法的主要內容,其算法也一直還在演進當中,每一個版本都有會有一些改進加入。其餘還有一些主題這裏沒有覆蓋到,好比平滑發送,能夠避免突發流量; padding包等用來探測帶寬的策略。應該說WebRTC的這套機制能覆蓋大部分的網絡場景,可是從咱們測試來看有一些特殊場景,好比抖動或者丟包比較高的狀況下,其帶寬利用率仍是不夠理想,但整體來講效果仍是很不錯的。
另外,想要獲取更多產品乾貨、技術乾貨,記得關注網易雲信博客。
Reference
[1] https://tools.ietf.org/html/draft-ietf-rmcat-gcc-02
[2] https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01
[3] Analysis and Design of the Google CongestionControl for Web Real-time Communication