擁塞控制算法主要能夠分爲兩個部分:在端系統使用的的源算法和在網絡設備上使用的鏈路算法。其中端到端的網絡擁塞控制算法一般根據接受到的ACK(Acknowledge character)確認包中包含的信息來調整擁塞控制窗口的大小,進而控制TCP鏈接的發送速率,譬如:TCP Tahoe, TCP Reno, TCP Vegas, TCP NewReno, TCP BIC, TCP CBIC, BBR等算法;在網絡中間設備上(路由器、防火牆、交換機等)的擁塞控制算法(AQM-Active Queue Management-主動隊列管理)一般根據設備中的緩存隊列長度信息對網絡擁塞控制程度進行判斷,並將擁塞控制信息顯示或隱式地告知端點,端點根據得到的擁塞控制信息對自身發送速率進行調整,譬如:FIFO, RED(Random Early Detection), ECN(Explicit Congestion Notification), FQ(Fair Queuing)等算法。html
本文主要針對端對端的TCP擁塞控制算法進行分析。算法
網絡產生擁塞的根本緣由在於用戶(或稱端系統)提供給網絡的負載大於網絡資源容量和處理能力,即「需求」大於"供應".通常表現爲數據時延增長、丟包機率增大、上層應用系統性能降低。以下圖顯示了擁塞發生的狀況.緩存
擁塞老是發生在網絡資源中資源「相對」短缺的位置。擁塞發生位置的不均衡反映了\(Internet\)不均衡性。網絡
1.首先是資源分佈的不均衡性。下圖中的帶寬分佈是不均衡的,當以 \(1Mb/s\) 的速率從S向D發送數據時,在網關R會發生擁塞。dom
2.其次是流量分佈的不均衡。下圖中帶寬分佈是均衡的,當 \(A\) 和 \(B\) 都以 \(1Mb/s\) 的速率向 \(C\) 發送數據時,在網關 \(R\) 也會發生擁塞。tcp
擁塞產生的直接緣由有以下3點:函數
TCP 擁塞控制通常包含以下四個控制過程:慢啓動 (slow start)、擁塞避免 (congestion avoidance)、快速重傳 (fast retransmit) 和快速恢復 (fast recovery)。如圖2.1 和圖 2.2所示性能
早期的TCP在創建鏈接後,發送方將向網絡發送多個數據包直到達到接受方聲明的最大窗口爲止。當兩臺主機在同一個局域網時,這種方式徹底可行。但若是發送方和接收方之間存在路由器和低速鏈路時,這種方式就會產生一些問題。一些路由器可能須要排列數據包於是產生緩存容量不足的問題,從而引發數據包丟失,致使傳輸超時,下降網絡的吞吐量(throughput)。ui
用來避免上述狀況的算法稱爲慢啓動算法:當創建新的TCP鏈接時,擁塞窗口(\(cwnd-congestion \ window\))初始化爲一個數據包大小。發送方首先發送1個數據包,而後等待反饋回來的該數據包的 \(ACK\) 確認包,當接受到相應的 \(ACK\) 後,擁塞窗口的值從1增長到2,此時,發送方一次就能發送2個數據包。當這個兩個數據包的 \(ACK\) 都到達後,擁塞窗口的值就增長至4.依次類推,每通過一個 \(RTT\)(\(round-trip \ time\)) 的時間,cwnd的值將增長一倍。這種方式使得擁塞窗口的增加將隨着 \(RTT\) 呈指數級 (\(exponential\)) 增加。發送方向網絡中發送的數據量將急劇增長。spa
擁塞避免算法的做用是經過減緩 \(cwnd\) 值的增長速率推遲網絡擁塞控制的發生,這樣可以使得發送端在較長的一段時間內保持較高的數據傳輸率。該算法假設基於損壞而丟失包的比例很小(遠小於\(1\%\))。所以,當出現丟包時,就代表源端和接收端之間的網絡的某個地方可能出現了擁塞。包的丟失有兩種暗示:定時器超時和接收到重複 \(ACK\)。
若是在慢啓動階段中,\(cwnd\) 增長至大於閾值 \(ssthresh\)(\(slow \ start \ threshold\)) 時,進入擁塞避免階段,在每一個 \(RTT\) 時間內,若發送方收到對當前 \(cwnd\) 對應數據的應答後,\(cwnd\) 就比原來增長一個最大\(TCP\)數據包所對應的字節數,即 \(cwnd\) 線性增加。
不管是慢啓動仍是擁塞避免,\(cwnd\) 老是增加,使得負載逐漸增大最終致使網絡擁塞。一旦數據包丟失,發送方只能在定時器超時以後才啓動數據重發過程,這樣可能會致使網絡資源的浪費或閒置。所以快速重傳的機制是,當發生丟包事件時,接收方將返回多個對相同數據的重複應答,若發送方連續收到三個以上的 \(ACK\) ,則代表極可能一個數據包丟失了。此時,發送方沒必要等重傳定時器超時就從新傳送那個可能丟失的數據包。TCP發送方利用快速重傳算法檢測和恢復數據包丟失。
在快速重傳可能丟失的數據包以後,\(TCP\) 就執行擁塞避免算法(而不是慢啓動算法),這就是快速恢復算法。此後,快速恢復算法將控制新數據的傳送,直到收到一個非重複的 \(ACK\) 爲止,之後開始執行擁塞避免而不是慢啓動。快速恢復實際上是基於 "管道" 模型的 "報文守恆"(\(packet \ conservation\)) 的原則,控制的目標是使得網絡中報文的個數保持恆定,只有當 "舊" 報文離開網絡後,才能發送 "新" 報文進入網絡。
快速恢復可以使大窗口下發生中度擁塞時依舊具備較高的吞吐量。對於沒有執行慢啓動的緣由是:收到重複的 \(ACK\) 意味着數據包已經丟失,而因爲接收方收到另外一個數據包時纔會產生重複的 \(ACK\) ,說明有另外的數據包已經到達了接收方的緩存區裏。也就是說,在這兩個端點之間還存在數據發送,\(TCP\) 不想進入慢啓動而形成流量的忽然下降。
![]()
\(TCP-Tahoe\) 網絡擁塞控制算法是最先的端到端的擁塞控制算法。算法僅做用於端點,嵌入在 TCP 協議中,由 \(Jacobson\) 在 1988 提出,此算法極大的提升了網絡控制擁塞的能力,併成爲 \(Internet\) 標準之一。
\(TCP-Tahoe\) 算法經過改變擁塞窗口的大小來調節 \(TCP\) 鏈接中端點的數據發送速率,使得端點具備了主動控制數據發送速率,避免網絡擁塞的能力。該算法中對擁塞窗口的調節主要包括了慢啓動、快速重傳和擁塞避免三種策略。
流程:首先使用慢啓動策略,將擁塞控制窗口大小設爲1個 \(MSS\)(\(Maximum \ Segment \ size\), 最大報文長度),隨後每收到一個ACK確認包,擁塞窗口大小便增長1個 \(MSS\)。當端點收到3個連續的 \(ACK\) 確認包或發生重傳超時 (\(Retransmission \ Timeout, RTO\)) 時,則認爲傳輸過程當中出現了數據包丟失,當即使用快速重傳策略以從新傳輸丟失的數據包,重傳結束後,將慢啓動閾值 \(ssthresh\) 設置爲當前擁塞窗口大小的一半,隨後從新使用慢啓動策略控制擁塞窗口大小,將其重置爲1個 \(MSS\) 大小,當擁塞窗口大小增長至大於 \(ssthresh\) 時,則切換爲擁塞避免策略。擁塞避免策略使擁塞窗口大小在 \(RTT\) 內增長一個 \(MSS\),直至再次檢測到數據包丟失後從新使用慢啓動策略, 算法依照數據包丟失狀況來判斷鏈路是否出現擁塞,並據此對擁塞窗口大小進行調節。
優勢:\(TCP-Tahoe\) 算法在慢啓動階段發送速率較低時可以以指數形式快速增加,快速佔用可用帶寬,在發送速率接近鏈路帶寬上限時在擁塞避免階段以線性形式平穩增加,保持相對穩定。一方面能夠探測出所處鏈路的最大帶寬,另外一方面可以使得鏈路上存在的其餘 \(TCP\) 鏈接出現擁塞,使其下降自身數據發送速率,讓出一部分網絡資源提供給新創建的 \(TCP\) 鏈接使用。同時 \(TCP-Tahoe\) 的快速重傳策略也解決了 \(TCP\) 鏈接超時重傳致使的大量網絡帶寬的浪費。
缺點: 在 \(TCP-Tahoe\) 中,一旦檢測到數據包丟失,擁塞窗口大小即被重置爲1個 \(MSS\) ,這樣 \(TCP\) 鏈接在數據包傳輸恢復正常以前沒法傳輸新的數據,形成了鏈路帶寬的大量浪費。
![]()
基於 \(TCP-Tahoe\) 算法中的缺陷,Jacobson 提出了 \(TCP-Reno\) 擁塞控 制算法,在 $TCP -Tahoe $原有的窗口調節策略中新增了快速恢復策略,這樣 \(TCP\) 發送端能更準確地計算鏈路中的包數目。\(Reno\) 避免了網絡擁塞不夠嚴重時採用慢啓動形成的過分減少發送窗口的現象。
流程:當發送方收到 3 個連續的重複 \(ACK\) 確認包時,並使用快速恢復策略來代替慢啓動策略,將 \(ssthresh\) 設置爲當前擁塞窗口大小的一半(但要大於或等於2個 \(MSS\)),隨後將擁塞窗口大小調節爲 \(ssthresh+3\times MSS\)(當收到3個重複 \(ACK\) 時,依舊採起擁塞避免階段每次加 1 個 \(MSS\) ,因此變爲 3倍 \(MSS\)),重傳丟失的數據包,此後每收到1個依舊重複 \(ACK\) 確認包時,也發送一個新的數據包,直到收到非重複 \(ACK\) 確認包後,將擁塞窗口大小設置爲 \(ssthresh\) 並使用擁塞避免策略調節擁塞窗口。
優勢:\(TCP-Reno\) 算法更加靈活的利用了 「數據包守恆」 的思想,在其新增的快速恢復策略中,每收到一個 \(ACK\) 確認包即認爲鏈路中出現了 1 個數據包大小空缺,則發送一個新的數據包,使得 \(TCP\) 鏈接在恢復正常傳輸以前也能夠傳輸適量的數據,下降了超時重傳發生的概率,加快了 \(TCP\) 鏈接從網絡擁塞中恢復的速度。
缺點:\(TCP-Reno\) 的快速恢復策略是針對一個窗口僅丟失一個數據包的狀況來設計的,其快速恢復策略僅對首個丟失的數據包進行從新傳輸,在收到非重複的 ACK 確認包 後,即認爲 \(TCP\) 鏈接數據傳輸已經恢復正常,若出現一個窗口連續多個數據包丟失,在連續收到多個重複確認時,擁塞窗口大小會被屢次減半,下降了 \(TCP\) 鏈接的鏈路帶寬利用率。
\(TCP-NewReno\) 對 \(Reno\) 中的 "快速恢復" 算法進行了補充。它考慮了一個發送窗口多個數據包丟失的狀況。當發送方收到3個連續的重複 \(ACK\) 確認包時,將最大的已經發送的數據包的序號記爲 \(recover\) ,在收到序號大於 \(recover\) 的 \(ACK\) 確認包後才切換爲擁塞避免策略。
優勢:\(TCP-NewReno\) 保證了 \(TCP\) 鏈接可以從網絡擁塞中正確恢復,進一步的提升了算法的性能。
帶選擇性重傳策略的 \(SACK\)(\(select \ Acknowledgment\)) 機制一樣也能夠克服 \(Reno\) 算法中一個窗口丟失多個數據包時,\(TCP\) 的性能可能變得不好的問題。\(SACK\) 選項域包含一些 \(SACK\) 塊,每一個 \(SACK\) 塊報告已經收到或正在排隊的非連續數據域。\(TCP\) 的接收端將 \(SACK\) 包傳回給發送端通知它所收到的數據,這樣發送端可選擇僅重傳丟失的數據。
優勢:\(SACK\) 避免了沒必要要的重傳,減小了時延,提升了網絡吞吐量。
缺點:在中等規模或大規模的 \(BDP\) (\(bandwidth-delay \ product\)) 網絡,此時的 \(SACK\) 就像 \(DOS\) 攻擊同樣,每次遍歷都要消耗大量的 \(CPU\),時間複雜度爲O(n^2),n爲 \(packets \ in \ flight\) 的數量。\(SACK\) 算法最大的缺點仍是在於修改協議 \(TCP\) 協議。
不管是 \(TCP-Tahoe、TCP-Reno\) 仍是 \(TCP-NewReno\) , 均爲根據數據包的丟失狀況推斷網絡擁塞程度的算法,這就致使 \(TCP\) 鏈接僅僅會在所處鏈路緩衝區沒法容納更多的數據包時纔對自身發送速率進行控制,增長了網絡的排隊時延以及數據包丟失率。
\(TCP-Vegas\) 擁塞控制算法是根據最短 \(RTT\) 預測 \(TCP\) 鏈接的預期吞吐量 \(Excepted\) ,根據當前的 \(RTT\) 計算 \(TCP\) 的真實吞吐量 \(Actual\) ,並計算二者的差值,記爲 \(diff\) ,若 \(diff\) 小於閾值 $\alpha $ ,則認爲網絡未發送擁塞,線性增長擁塞窗口大小;若 \(diff\) 超出閾值 $\beta $ ,則線性減少擁塞窗口大小;若 \(diff\) 處於二者之間,則擁塞窗口大小不變。
\[\text{指望吞吐量:}Expected=cwnd/BaseRTT \]\[\text{實際吞吐量:}Actual=cwnd/RTT \]\[\text{計算差值:}diff=\left( Expect-Actual \right) \times BaseRTT \]優勢:因爲 \(TCP-Vegas\) 並不徹底依賴於數據包丟失狀況來檢測網絡擁塞,而是主要採用 \(RTT\) 的改變來判斷網絡的可用帶寬,於是對網絡擁塞程度的判斷較爲靈敏,有效的下降了數據包丟失率,在必定程度上提升了網絡吞吐量。
缺點:\(TCP-Vegas\) 存在較大的 \(TCP\) 公平性問題,在與其它算法共存的狀況下,基於丟包的擁塞控制算法會嘗試填滿網絡中的緩衝區,致使Vegas計算的 \(RTT\) 增大,進而下降擁塞窗口的大小,使得傳輸速度愈來愈慢,所以一直未被普遍採用。
上述 \(TCP-Tahoe、TCP-Reno\) 和 \(TCP-NewReno\) 算法,使用了加性增長乘性減少 (\(Additive \ Increase \ Multiplicative \ Decrease, AIMD\)) 的擁塞窗口大小調整機制,即每一個 \(RTT\) 時間內擁塞窗口大小增加 \(\alpha\) (\(\alpha\) 的默認值爲1),每當檢測到數據包丟失時將擁塞窗口大小減少爲 \(\beta\) 倍 (\(\beta < 1\) ,\(\beta\) 的值默認爲0.5),會致使擁塞窗口大小須要經歷不少個 \(RTT\) 才能使 \(TCP\) 鏈接的數據發送速度到達高帶寬時延鏈路的承載上限,而一旦遇到數據包丟失則將擁塞窗口大小減半甚至重置爲1個 \(MSS\) ,這使得擁塞控制窗口大小增加十分緩慢但減低過於迅速,浪費了大量的可用帶寬。
咱們能夠粗略估計一下 \(reno\) 算法在高速TCP環境下的處理,在一個 \(RTT\) 爲\(100ms\),帶寬爲\(10Gbps\),包大小爲\(1500bytes\)的網絡中,若是滿速率發送 \(cwnd\ge \left( 10\times 1000\times 1000\times 1000 \right) bit/s\times 0.1s/\left( 8\times 1500 \right) bit=83333\)。假設 \(cwnd=83333\) ,若是快速重傳 \(cwnd\) 減半後從新進入擁塞避免狀態,那麼大約須要 $83333/2\times 100=4166666ms=4166ms=69\min $ 經過簡單計算咱們能夠發現,這種場景下大約須要69分鐘,\(reno\) 的擁塞避免過程才能讓 \(cwnd\) 足夠大以充分利用 \(10Gbps\) 的帶寬,顯然69分鐘的擁塞避免過程時間太長了,並且極可能會形成帶寬浪費。實際上受限於丟包率,\(reno\) 的一個典型問題就是還沒等 \(cwnd\) 增加到足夠利用 \(10Gbps\) 的值就已經發生丟包並削減 \(cwnd\)了。
基於解決這一問題,\(Floyd\) 提出了 \(HSTCP\) 擁塞控制算法,其將擁塞窗口大小的函數 \(\alpha(cwnd)\) 和 \(\beta(cwnd)\) 做爲 \(AIMD\) 機制中的參數 \(\alpha\) 和 \(\beta\) ,當擁塞窗口大小不超過預先設定的參數值 \(Low\_window\) 時,\(HSTCP\) 認爲當前所處鏈路的時延帶寬積較低,令 \(\alpha(cwnd)=1\) ,\(\beta(cwnd)=0.5\),與原有的擁塞控制窗口調節機制保持一致。(\(\alpha=a,\beta=b\))
![]()
當擁塞窗口大小大於 \(Low\_window\) 時,就會依據下列公式採起新的 \(a\) 和 \(b\) 來到達高時延帶寬積的要求:
\[a\left( w \right) =w^2\times p\left( w \right) \times 2\times b\left( w \right) /\left( 2-b\left( w \right) \right) ,\ \text{其中}p\left( w \right) \text{時窗口爲}w\text{時的丟包率} \]\[b\left( w \right) =\left( High\_Decrease-0.5 \right) \left( \log \left( w \right) -\log \left( W \right) \right) /\left( \log \left( W\_1 \right) -\log \left( W \right) \right) +0.5 \]\(High\_Decrease\) 是最大的乘性減少因子,標準TCP取值爲0.5,\(HSTCP\) 取爲0.1,\(W\) 爲低窗口的臨界值,也就是38,\(W\_1\)是窗口最大值,設爲\(83000\)(爲何是\(83000\)?Floyd是經過10Gbps,100ms的網絡下計算出來的窗口值,精確值是\(83333\))。關於 \(a\) 和 \(b\) 在不一樣擁塞窗口大小的取值,真正使用的時候能夠經過查表的方式直接得出來。
\(HSTCP\) 同時也對慢啓動策略指數增大擁塞窗口得方式進行了改進,在高\(BDP\) 網絡上,原有的慢啓動策略會以指數形式增長,越到後面擁塞窗口能夠到達很大的值,從而致使 \(TCP\) 鏈接的傳輸速度增加至遠超鏈路的緩衝區承載上限,形成大量數據包丟失。\(HSTCP\) 在擁塞窗口大小的指數增加過程當中設置了一個閾值 \(max\_ssthresh\) ,當窗口大小小於 \(max\_ssthresh\) 時,仍以指數形式增加,一旦超過 \(max\_ssthresh\) 後,令其在 \(RTT\) 時間內的增加不得超過 \(max\_ssthresh/2\) ,修改後的機制被稱做限制慢啓動 (\(Limited \ Slow \ Start\))。
優勢:\(HSTCP\) 算法可以在高速網絡中,不管是在高丟包率或低丟包率的環境下,都能達到很高的吞吐量。
缺點:與傳統 \(TCP\) 擁塞控制算法共存時會存在公平性的問題。當 \(TCP-Reno\) 和 \(HSTCP\) 共享鏈路時(高速網絡中且數據包丟失率較小的狀況下) 在擁塞發生後,\(TCP-Reno\) 使用的擁塞窗口增加速率遠遠慢於 \(HSTCP\) 的增加速率,所以,通過若干次擁塞控制事件後,\(HSTCP\) 會不斷地侵佔傳統 \(TCP\) 的可用帶寬。
關於 \(TCP-BIC\) 和 \(TCP-CUBIC\) 算法的詳細內容,能夠參考個人另一篇博客,這裏再也不詳述。
其中關於 \(TCP-BIC\) 算法公平性問題,以下圖所示,因爲 \(TCP-BIC\) 是在收到 \(ACK\) 確認包時對擁塞窗口進行調節的,這樣在 \(RTT\) 不一樣的兩個 \(TCP\) 鏈接競爭同一瓶頸鍊路時,\(RTT\) 較大的 \(TCP\) 鏈接因爲收到的數據包頻率始終小於 \(RTT\) 較小的 \(TCP\) 鏈接,其擁塞窗口 調節頻率較低,增加較慢,致使 \(TCP-BIC\) 存在很嚴重的 RTT 公平性問題 。
![]()