BBR, the new kid on the TCP block | APNIC Blog 這篇文章挺好的,下面不少內容也基於這篇文章而來。html
擁塞避免用於避免由於發送者發送數據過快致使鏈路上由於擁塞而出現丟包。算法
TCP 鏈接創建後先通過 Slow Start 階段,每收到一個 ACK,CWND 翻倍,數據發送率以指數形式增加,等出現丟包,或達到 ssthresh,或到達接收方 RWND 限制後進入 Congestion Avoidance 階段。下面這個圖挺好的,描述了好幾個過程,找不到出處了,只是列一下圖吧。微信
一些基礎東西能夠看:TCP congestion control - Wikipedia網絡
BDP 是 Bandwidth and Delay Product. 就是帶寬 (單位 bps) 和延遲 (單位 s) 的乘積,單位是 bit,也是 Source 和 Destination 之間容許處在 Flying 狀態的最大數據量。Flying 也叫 Inflights,就是發送了但還未收到的 Ack 的數據。tcp
來自[3]。ide
實際發送速率乘以延遲獲得的值越接近 BDP 說明算法的效率越高。函數
Reno 這種叫作 ACK-Pacing
,基於 Ack 來確認網絡情況。若是能持續收到 ACK,表示網絡能正常承載當前發送速率。性能
Reno maintains an estimate of the time to send a packet and receive the corresponding ACK (the 「round trip time,」 or RTT), and while the ACK stream is showing that no packets are being lost in transit, then Reno will increase the sending rate by one additional segment each RTT interval.
Reno 下,每收到一個 ACK,CWND 加一,等出現丟包以後發送者將發送速率減半。理想情況下,Reno 能走出以下曲線:大數據
來自[1]優化
Reno 有以下假設:
從上面假設能看出,Reno 下受鏈路上 Buffer 大小影響很大。當 Buffer 較小的時候,鏈路上實際處在發送狀態的數據量還未達到 BDP (Bandwidth delay product) 時候可能就會出現丟包,致使 Reno 馬上減半發送速率,從而沒法高效的利用網絡帶寬。若是 Buffer 很大,超過 BDP,可能會進入 「Buffer Bloat」 狀態,即延遲畸高,由於即便 Reno 速度降爲一半依然不能保證使鏈路 Buffer 清空,或者說可能大部分時間鏈路上 Buffer 都處在非空狀態,且每次 Reno 由於丟包而降速時,會作數據重傳,致使以前發送的可能還依舊在鏈路上排隊的數據空佔資源沒起到做用最終白白丟掉,因而讓整條鏈路上持續存在固有延遲。
Reno 的問題:
BIC 叫 Binary Increase Congestion Control,是在 Reno 基礎上作改進,將 CWND 擴大過程分紅三個階段,第一階段是在遇到丟包後將 CWND 降爲 β × Wmax
,(通常 β 是 0.5,Wmax 是丟包時 CWND)但記住以前 Wmax 最大值,以後以一個較快速度增長 CWND,在接近 Wmax 後 CWND 增長量是一個 Wmax 和 CWND 之間的二次函數,稱爲 Binary Increase,逐步去接近 Wmax,到達 Wmax 後又轉換爲二次曲線去探測下一個極限。具體內容能夠看 Wiki,在這裏:BIC TCP - Wikipedia
大概是這麼個圖,好處就是丟包後能快速恢復,並在穩按期盡力保持更長時間,並還能支持探測更高帶寬值。
來自[3]
Cubic 在 BIC 的基礎上,一個是經過三次函數去平滑 CWND 增加曲線,讓它在接近上一個 CWND 最大值時保持的時間更長一些,再有就是讓 CWND 的增加和 RTT 長短無關,即不是每次 ACK 後就去增大 CWND,而是讓 CWND 增加的三次函數跟時間相關,無論 RTT 多大,必定時間後 CWND 必定增加到某個值,從而讓網絡更公平,RTT 小的鏈接不能擠佔 RTT 大的鏈接的資源。
平滑後的 CWND 和時間組成的曲線以下,能夠看到三次曲線保留了 BIC 的優勢,即在丟包後初期,CWND 能快速增加,減少丟包帶來的影響;而且在接近上一個 CWND 最大值時 CWND 增加速度又會很是慢,要經歷很長時間才能超越 Wmax,從而能盡力保持穩定,穩定在 Wmax 上;最後在超越 Wmax 後初期也是增加的很是慢,直到後來才快速的指數形式增加,用於探測下一個 Wmax。
來自[3]
Cubic 最終出來的曲線以下。黃色是 CWND,藍色線是網絡上隊列擁塞包數。藍色箭頭表示 queue fill,綠色箭頭表示 queue drain。看到有兩個淺綠色的線,高的是開始丟包,低的是隊列開始排隊。由於這裏畫的是說網絡上 bandwidth 是固定的,buffer 也是固定的,因此 Cubic 下沒有超越 Last Wmax 繼續探測下一個 Wmax 的曲線,都是還未到達第一次的 Wmax 時候就由於丟包而被迫下降了 CWND。第一次個黃色尖峯能那麼高是由於當時網絡上 buffer 是空的,後來每次丟包後 Buffer 還沒來得及徹底清空 CWND 又漲上來致使數據排隊了,因此後來的黃色尖峯都沒有第一個高。
來自[3]
Cubic 的優點:
Cubic 缺點:
綜合來看 Cubic 適合 BDP 大的高性能網絡,性能意思是帶寬或者說發送速率,發送速率足夠大 Cubic 把 Buffer 佔滿後才能快速清空,纔能有較低的延遲。
一個挺好的講 Cubic 的 PPT:Cubic,還有論文。Linux 2.6 時候用的 CUBIC。
Bufferbloat 在 Bufferbloat - Wikipedia 講的挺好了。簡單說就是隨着內存愈來愈便宜,鏈路上有些設備的 Buffer 傾向於配置的特別大,而流行的 TCP Congestion Avoidance 算法又是基於丟包的。數據在隊列排隊說明鏈路已經出現擁塞,原本應該當即反饋給發送端讓發送端減少發送速度的,但由於 Buffer 很大,數據都在排隊,發送端根本不知道本身發出去的數據已經開始排隊,還在以某個速度 (Reno)甚至更高速度(Cubic,到時間就增長 CWND) 發送。等真的出現丟包時候,發送端依然不知道出現了丟包,還會快速發消息,直到丟的這個包被接收端感知到,回覆 ACK 後發送端才終於知道要下降發送速度。而重傳的包放在鏈路上還得等以前的數據包都送達接收端後才能被處理。若是接收端的 Buffer 不足夠大,不少數據送達接收端後都會丟棄,得等重傳的包到達(Head Of Line 問題)後才能送給上游,大大增長延遲。
Bufferbloat 一方面是會致使網絡上超長的延遲,再有就是致使網絡傳輸不穩定,有時候延遲很小,有的時候延遲又很大等。
能夠參考:Bufferbloat: Dark Buffers in the Internet - ACM Queue
在 CUBIC 之上又有個優化,叫作 Proportional Rate Reduction (PRR),用以讓 CUBIC 這種算法在遇到丟包時候能更快的恢復到當前 CWND 正常值,而不過度的下降到太低的水平。
參考:draft-mathis-tcpm-proportional-rate-reduction-01 - Proportional Rate Reduction for TCP。不進一步記錄了。Linux 3.X 的某個版本引入的,配合 CUBIC 一塊兒工做。
爲了進一步優化 Cubic,能夠先看看鏈路上隊列的模型。
來自[1]
最優狀態是 State 1 和 State 2 之間,即沒有出現排隊致使延遲升高,又能徹底佔滿鏈路帶寬發送數據,又高效延遲又低。
而基於丟包的 Congestion Avoidance 策略都是保持在 State 2 的狀態。而 Cubic 是讓 CWND 儘量保持在上一個 Wmax 的狀態,也即 State 2 末尾和即將切換到 State 3 的狀態。因此 Cubic 至關於儘量去佔用鏈路資源,使勁發數據把下游鏈路佔滿但犧牲了延遲。
因而能夠看到,爲了保持在 State 1 和 State 2 狀態,咱們能夠監控每一個數據包的 RTT,先盡力增大 CWND 提升發送率若是發現發送速率提升後 RTT 沒有升高則能夠繼續提升發送速率,直到對 RTT 有影響時就減速,說明從 State 1 切換到了 State 2。
咱們但願讓 CWND 盡力保持在下面圖中標記爲 optimum operating point
的點上,即 RTT 又小,鏈路上帶寬又被佔滿。在這個圖上,RTprop 叫作 round-trip propagation time
,BtlBw 叫作 bottleneck bandwidth
。橫軸是 inflights 數據量,縱軸有兩個一個是 RTT 一個是送達速度。看到圖中間有個很淡很淡的黃色的線把圖分紅了上下兩部分,上半部分是 Inflights 數據量和 Round trip time 的關係。下半部分是 Inflights 和 Delivery Rate 的關係。
這裏有四個東西須要說一下 CWND、發送速度、inflights,發送者帶寬。inflights 就是發送者發到鏈路中還未收到 ACK 的數據量,發送速度是發送者發送數據的速度,發送者帶寬是發送者能達到的最大發送速度,CWND 是根據擁塞算法獲得的當前容許的 inflights 最大數據量,它也影響着發送速度。好比即便有足夠大的帶寬,甚至有足夠多的數據要發,但 CWND 不夠,因而只能下降發送速度。這麼幾個東西會糾纏在一塊兒,有不少文章在描述擁塞算法的時候爲了方即可能會將這幾個東西中的某幾個混淆在一塊兒描述,看的時候須要盡力內心有數。
回到圖藍色的線表示 CWND 受制於 RTprop,綠色的線表示受制於 BltBw。灰色區域表示不可能出現的區域,至少會受到這兩個限制中的一個影響。白色區域正常來講也不會出現,只是說理論上有可能出現,好比在鏈路上還有其它發送者一塊兒在發送數據相互干擾等。灰色區域是不管如何不會出現。
先看上半部分,Inflights 和 Round-Trip Time 的關係,一開始 Inflights 數據量小,RTT 受制於鏈路固有的 RTprop 時間影響,即便鏈路上 Buffer 是空的 RTT 也至少是 RTprop。後來隨着 Inflights 增大到達 BDP 以後,RTT 開始逐步增大,斜率是 1/BtlBw
,由於 BDP 點右側藍色虛線就是 Buffer 大小,每一個藍點對應的縱軸點就是消耗完這麼大 Buffer 須要的時間。消耗 Buffer 的時間 / Buffer 大小
就是 1/BltBw
,由於消耗 Buffer 的時間乘以 BltBw 就是 Buffer 大小。感受很差描述,反正就這麼理解一下吧。主要是看到不可能到灰色部分,由於發送速率不可能比 BltBw 大。等到 Inflights 把 Buffer 佔滿後到達紅色區域開始丟包。
下半部分,Inflights 比較小,隨着 Inflights 增大 Delivery Rate 越大,由於此時還未達到帶寬上限,發的數據越多到達率也就越高。等 Inflights 超過 BDP 後,Delivery Rate 受制於 BtlBw 大小不會繼續增大,到達速度達到上限,Buffer 開始積累。當 Buffer 達到最大限度後,進入紅色區域開始丟包。
以前基於丟包的擁塞算法實際上就是和鏈路 Buffer 一塊兒配合控制 Inflights 數據量在 BDP 那條線後面與 BDP 線的距離。之前內存很貴,可能只比 BDP 大一點,基於丟包的算法延遲就不會很高,可能比最優 RTT 高一點。但後來 Buffer 愈來愈便宜,鏈路上 Buffer 就傾向於作的很大,此時基於丟包的擁塞算法就容易致使實際佔用的 Buffer 很大,就容易出現 BufferBloat。
爲了達到最優勢,發送速率必須達到 BltBw,從而佔滿鏈路帶寬,最高效的利用帶寬;再有須要控制 Inflight 數據量不能超過鏈路的 BDP = BtlBw * RTprop
,從而有最優的延遲。發送速率能夠超過 BltBw,能夠有隊列暫時產生,但數據發送總量不能超 BDP,從而讓平均下來延遲仍是能在最優勢附近。
來自[4]
Vegas 就如上面說的理想中算法同樣,它會監控 RTT,在嘗試增長髮送速率時若是發現丟包或者 RTT 增長就下降發送速率,認爲網絡中出現擁塞。但它有這些問題:
參考文獻在下一篇統一提供。
更多內容歡迎關注 LeanCloud 官方微信號:「LeanCloud 通信」