Overview of Concepts
本章將介紹流量控制,研究出現流量控制的原因及其優缺點,並介紹流量控制的關鍵概念。
瞭解Linux的流量控制的目的:一是為了更好地理解底層對報文的處理邏輯,二是在流量控制中使用了很多很好的流量處理方法,可以學習一下這些方法和思想,翻譯自:https://tldp.org/en/Traffic-Control-HOWTO/index.html。
2.1. 什麼是流量控制
流量控制是指在路由器上接收和傳輸資料包的佇列系統和機制的統稱。包括決定(如果和)輸入介面上以哪種速率接收哪個包,以及決定在輸出介面上以哪種順序傳輸那些包。
在最簡單的模型中,流量控制包含簡單的佇列,該佇列收集了所有的報文,並在硬體(或底層裝置)可以接收報文時儘快讓這些報文出佇列。這種佇列即FIFO。它就像一個進入高速公路的收費站,每輛車必須停下並繳納過路費,而此時其他汽車也必須等待。
注:Linux下預設的qdisc為
pfifo_fast
,它比FIFO更加複雜。
在各種軟體中都有佇列的影子。佇列是一種組織掛起的任務或資料(參見Section 2.5, “Queues”)的方式。由於網路連結通常會以序列化的方式攜帶資料,因此需要一個佇列來管理出站的資料包。
在桌上型電腦和一臺高效的網路伺服器共享(到因特網的)同一上行鏈路的情況下,可能會對頻寬資源產生競爭。例如,伺服器填充路由器上的輸出佇列的速度可能比通過鏈路傳輸資料的速度還要快,此時路由器開始丟包(緩衝已經滿了),這樣桌上型電腦(可能是互動應用的使用者)可能會面臨丟包和高延遲。通過劃分內部佇列來服務這兩種不同的應用,就可以在兩個應用間更好地共享網路。
流量控制是一組允許管理員對這些佇列進行精細控制的工具和網路裝置的排隊機制的統稱。雖然這些工具重新分配流量和包的能力是強大的,同時也可能會很複雜,但最好留有足夠的頻寬。
術語Quality of Service (QoS)通常作為ip層的流量控制的代名詞。
2.2. 為什麼使用流量控制
流量控制工具允許實現者對傳輸到網路中的資料包或網路流應用首選項、組織或業務策略,進而管理網路資源,如吞吐量或延遲。
從根本上說,由於網路中的分組交換,流量控制變得非常必要。
為了簡要說明資料包交換的新穎性和巧妙性,考慮一下在整個20世紀構建起來的電路交換電話網路。為了發起一個呼叫,網路裝置需要了解建立呼叫的規則。當一個呼叫者嘗試發起連線時,網路會使用這些規則來為整個呼叫或連線期間保留一個電路。當有一個使用該資源的通話佔線時,其他呼叫或呼叫者都不能使用該資源,意味著由於資源不可用,許多裝置可能會因為單個部件而阻塞通話的建立。
回到分組交換網路,這是20世紀中期的一項發明,後來被廣泛使用,並且在21世紀幾乎無處不在。分組交換網路與基於電路的網路有一個非常重要的區別,即網路裝置處理的資料單位不再是電路,而是一小塊的資料,稱為資料包。分組交換網路只需要處理一小部分的工作:讀取目的地標識,並傳輸該資料包。
分組交換網路有時會被認為為無狀態的,這是因為它不需要跟蹤網路上所有的活動的流。因此,缺乏對特定資料包或網路流重要性的區分是這種分組交換網路的一個弱點。網路可能會因資料包的相互競爭而超載。
簡單來說,流量控制工具允許根據資料包的屬性,通過不同的方式將資料包放入網路。不同的工具用於解決不同的問題,可以組合多個工具來實現複雜的規則,滿足偏好或業務目標。
下面是一些常見問題的例子,可以用於解決或改善這些工具。
下面並沒有給出流量控制的所有解決方案,僅給出了可以使用流量控制工具解決的常見問題,用於最大化利用網路。
常用的流量控制方案
- 將總頻寬限制為某個值:TBF,和帶子類的HTB。
- 限制特定使用者、服務或客戶的頻寬:HTB 類和帶filter的分類
- 最大化非對稱鏈路上的TCP吞吐量;提升傳輸的ACK包的優先順序:wondershaper。
- 為特定應用或使用者預留頻寬:帶子類的HTB和分類。
- 偏好延遲敏感的流量:HTB類中的PRIO。
- 管理超額的頻寬:HTB租借
- 允許公平分配未預留的頻寬:HTB租借
- 確保丟棄特定型別的流量:給filter新增policer,使用drop動作。
需要注意的是,有時候最好訂購更多的頻寬,流量控制並不能解決所有的問題。
2.3 優點
正確引入流量控制可以更加可靠地對網路資源地利用進行預測,並可以減少對這些資源的不穩定競爭,這樣就可以實現流量控制配置的目標。即使在為更高優先順序的互動式流量提供服務同時,也可以為批量下載分配合理的頻寬;即使低優先順序的資料傳輸(如郵件),也可以分配到一定的頻寬,而不會對其他型別的流量造成巨大的影響。
如果流量控制中的配置代表了使用者的策略,那麼該使用者(或應用)就應該知道後續會網路的影響。
2.4 缺點
使用流量控制的最大缺點之一是其複雜性。實踐中,有一些方法可以用來熟悉流量控制工具,簡化關於流量控制及其機制的學習曲線,但如何確定一個流量控制的錯誤配置仍然是一個相當大的挑戰。
當正確配置流量控制時,可以公平地分配網路資源。但不合理的使用可能導致對資源的分裂性爭奪。
路由器上支援流量控制方案所需的計算資源必須能夠處理維護流量控制結構的成本的增加。幸運的是,它的成本增量很小,但隨著配置和複雜度的增加,其成本可能顯著增加。
對於個人來說,不需要考慮引入量流量控制帶來的培訓成本,但對於一個公司來說,相比引入流量控制,採購更多的頻寬可能是一個更簡單的解決方案(員工的培訓成本可能要遠高於採購頻寬的成本)。
2.5 佇列
所有的流量控制都會用到佇列,它是排程演算法不可或缺的一部分。一個佇列是一個位置(或緩衝),包含有限數目的元素,等待相應的動作或服務。在網路中,一個佇列是報文(單位)等待被硬體(服務)傳輸的地方。在最簡單的模型中,報文根據先進先出的方式進行傳輸。在計算機網路(和更普遍的電腦科學)的學科中,這種佇列被稱為FIFO。
如果沒有其他機制,佇列是不會為流量控制提供任何優化。此時一個佇列只有兩個需要關注的動作:任何到達佇列的報文(或單位)都會在佇列中排隊;為了從佇列中移除一個元素,則需要對其執行出佇列操作。
當結合其他機制時,佇列可以提供更加豐富的功能,如延遲包容,重新排列,丟棄,以及優先處理多個佇列中的資料包。一個佇列可能會使用子佇列,用來處理更加複雜的排程行為。
從上層的軟體的角度來看,當一個報文入佇列後,該佇列對待傳輸報文的處理行為和處理順序對上層軟體來說是無關緊要的。因此,對上層來說,整個流量控制佇列系統可能只是一個單一的佇列,只有對使用了流量控制的那一層來說,流量控制結構才是可見的。
下圖展示了一個高度簡化的Linux網路棧的傳輸路徑上的佇列圖:
2.6 流
一條流指兩個主機之間的特定連線或會話。兩個主機之間的任何(唯一的)報文集都可以看作是一條流。TCP使用源IP和埠,目的IP和埠來表示一條流,UDP流也是類似的。
流量控制機制經常會將流量劃分為不同的類,並以聚合流的方式(如DiffServ)對這些流進行聚合和傳輸。類似的,可能會基於單個流來平均分配頻寬。
當嘗試在一組競爭流中平均分配頻寬時,對流的處理就變得很重要,尤其是在某些應用故意構建大量流時。
2.7 令牌和桶
整流機制的兩個關鍵概念是令牌和桶。
為了控制出佇列的速率,實現中可以在每個元素出佇列時計算出列的報文數或位元組數(雖然這樣會使用複雜的定時器和工具進行精確限制)。除了計算當前使用量和時間,還有一種方法廣泛用到流量控制中,即以一定速率生成令牌,只有存在可用的令牌是才允許報文或位元組出佇列。
考慮一個遊樂園遊樂設施,人們排隊等候體驗遊樂設施。讓我們將該設施想象成一個軌道,在這個軌道上,推車會通過一個固定的軌道。這些推車以固定的速率排在隊伍的前頭。為了享受乘坐的樂趣,每個人必須等待一輛可用的推車,每個推車類似於一個令牌,人類似於一個報文。這種機制就是限流或整流機制。 在特定時期內,只有一定數量的人可以體驗騎行。
為了擴充套件這個類比,想象遊樂園裡有一條空的線路,而軌道上有大量的推車準備載客,如果大量的人一起進入佇列,很多(也許全部)人可以體驗乘坐,因為此時有一定數量的可用的推車。推車的數量是一個類似於桶的概念。一個桶包含很多令牌,可以使用桶中現有的令牌,而無需等待。
為了完成這個類比,遊樂園裡的推車(我們的令牌)的到達的速率是固定的,且可用的推車不超過桶大小。因此,令牌會以固定速率填充到桶,如果沒有使用令牌,則桶可以被填滿。如果使用了令牌,則桶不會被填滿。桶是支援突發流量(如HTTP)的一個關鍵概念。
TBF qdisc是一個典型的整流器(關於TBF包括一個圖表,它可以幫助以視覺化的方式展示令牌和桶的概念)。TBF會生成速率令牌,只有當令牌可用時才能傳輸報文。令牌是一個通用的整流概念。
當佇列不需要令牌時,這些令牌會被收集起來,並在後續需要時使用。無限制地收集令牌會抵消整流帶來的好處,因此需要限制收集的令牌的數量。佇列中的令牌可用於需要出佇列的報文或位元組。 這些無形的令牌儲存在無形的桶中,可以儲存的令牌數量取決於桶的大小。
這也意味著,在任意時刻都可能存在一個滿token的桶,可預測的流量可以使用小的桶,突發流量可以使用大的桶(除非目標是為了降低流的突發)。
總之,令牌使用一定速率來生成,最大可用的令牌數由桶的大小來決定。通過這種方式可以處理突發流量,使得傳輸的流量變得平滑。
令牌和桶是息息相關的,用於 TBF (classless qdiscs的一種) 和HTB (classful qdiscs的一種)。在tcng語言中,二色和三色標識法就是令牌桶的應用。
2.8 報文和幀
網路上傳輸的資料的術語取決於其所在的網路層。儘管在此處給出了報文和幀的技術上的區別,但本文並不作區分。
幀通常用於描述二層網路上轉發的資料單位。以太介面,PPP介面和T1介面都將二層資料單位稱為幀。幀是流量控制的實際單位。
從另一方面將,報文時上層協議的概念,表示三層資料單位。本文件的使用了報文。
2.9 NIC,網路介面控制器
一個網路介面控制器是一個計算機硬體元件,與前面的軟體元件不同,它將一個計算機連線到一個計算機網路。網路控制器使用特定的資料鏈路層和物理層標準實現了通訊所需的電子電路,如 Ethernet, Fibre Channel, Wi-Fi or Token Ring。流量控制必須處理NIC介面的物理限制和特徵。
2.9.1 網路棧的巨包
大多數NICs都有一個固定的傳輸單位(MTU),即物理媒介可以傳輸的最大幀。對於乙太網來說,預設為1500位元組,但對於支援巨型幀的乙太網來說,其MTU可以達到9000位元組。在IP網路棧中,MTU作為傳送或傳輸報文時的大小限制。例如,如果一個應用向TCP socket寫入了2000位元組的資料,那麼IP棧需要建立兩個IP報文來保證報文小於或等於1500位元組的MTU。當需要傳輸大於MTU的資料時,會導致建立大量的小報文,並傳輸到 驅動佇列。
為了避免在傳輸路徑上對大報文處理產生的開銷,Linux核心實現了幾類優化:TCP分段解除安裝(TSO),UDP分片解除安裝(USO)以及通用的分段解除安裝 (GSO)。所有這些優化都允許IP棧建立的報文大於傳出的NIC上的MTU。對於IPv4,建立並放到驅動佇列中的報文可以達到65536位元組。在TSO和UFO場景下,NIC硬體負責將單個大報文切分為可以在物理介面上傳輸的小報文。對於沒有硬體支援的NIC,GSO會在報文進入驅動佇列之前對其進行相同的操作。
回顧一下,驅動佇列包含一個固定數目的描述符,每個描述符指向大小不同的報文,由於TSO, UFO 和GSO 允許更大長度的報文,因此這些優化會大大增加驅動佇列中儲存的位元組數(即驅動中的描述符可能指向一個大於MTU的報文,後續會在NIC中進行報文切割)。
2.10 飢餓和延遲
IP棧和硬體(參見4.2章節的驅動佇列,和5.5章節對啟動佇列的管理)之間的佇列引入了兩個問題:飢餓和延遲。
NIC驅動程式從佇列中取出資料包進行傳輸,但佇列是空的,此時硬體會錯失一次傳輸的機會,進而導致系統吞吐量下降,這種情況稱為飢餓。注意,當系統不需要傳輸任何資料時,佇列也是空的,這是正常情況,並不歸類為飢餓。與避免飢餓相關的複雜情況是,正在填充佇列的IP棧和消耗佇列的硬體驅動程式是非同步執行的,更糟糕的是,填充和獲取事件的間隔會隨著系統的負載和外部狀況(如網口的物理媒介)而變化。例如,在一個繁忙的系統上,IP棧向緩衝區新增報文的機會將變少,這會導致硬體在更多資料包入佇列之前耗盡緩衝區。基於這種原因,使用比較大的緩衝可以降低飢餓的概率,並保證高吞吐量。
當使用一個大的佇列來為一個繁忙的系統保持高吞吐量時,同時也會引入大量延遲。
上圖展示了一個驅動佇列,其中幾乎填滿了高頻寬,大流量(藍色)下的TCP段。佇列的最後一個報文來自一個VoIP或遊戲流(黃色)。像VoIP或遊戲這樣的互動式應用通常會以固定間隔的時間傳送小的報文,它們是延遲敏感型的。而高頻寬資料傳輸會產生更高的報文速率和更大的報文,更高的報文速率會填滿互動式報文之間的緩衝,導致互動式報文的傳輸被推遲。為了描述這種行為,考慮下面這種場景:
- 網口上允許傳輸的速率為5 Mbit/sec 或 5,000,000 bits/sec。
- 大流量上的每個報文是 1,500 bytes 或12,000 bits。
- 互動式流量上的每個報文是500 bytes。
- 佇列的深度為128個描述符。
- 此時佇列中有127個大流量報文和1個互動式報文。
鑑於上述假設,耗盡127個大流量報文並給互動式報文創造傳輸機會的時間為(127 * 12,000) / 5,000,000 = 0.304 seconds (對於根據ping來衡量的延遲結果為304毫秒),這樣的延遲對互動式應用來說是不可接受的,且不代表完整的往返時間(僅僅是互動式報文在佇列中等待傳輸前的時間)。如前面所述,當啟用TSO, UFO 或 GSO時,驅動佇列中的報文大小可以大於1500位元組,這將導致延遲更加嚴重。
為驅動佇列選擇一個合適的大小可以看作是一個Goldilocks 問題,為了保證吞吐量而不能大小,為了保證延遲而不能太大。
2.11 吞吐量和延遲之間的關係
在所有流量控制系統中,吞吐量和延遲都存在一定的關係。網路鏈路上傳輸的的最大資訊速率稱為頻寬,但是對於網路上使用者來說,實際獲得的頻寬還有一個專用術語,吞吐量。
延遲
-
傳送者傳輸和接收者解碼或接收資料之間的延遲,總是非負或非0的值。
-
原則上,延遲是單向的,但幾乎整個Internet網路社群都在談論雙向延遲--傳送方傳送資料和通過某種方式確認收到資料之間的時間延遲,如ping
-
以毫秒計算延遲;在乙太網上,延遲通常是0.3到1ms之間,在廣域網上,延遲為5到300ms之間。
吞吐量
-
衡量傳送者和接收者之間成功傳輸的資料總量
-
以bit/sec為單位進行衡量;
注:延遲和吞吐量是常用的計算術語。例如,應用程式開發人員在嘗試構建響應工具時會提到了使用者感知的延遲。資料庫和檔案系統人員會提到磁碟吞吐量。在網路層上,在DNS中查詢網站名稱的延遲是感知一個網站效能的重要指標。
為了最大化下載吞吐量,裝置供應商和供應商通常會調整他們的裝置來容納大量資料包。當網路準備接收另外一個報文時,網路裝置的佇列中如果有一個報文,則簡單地傳送該報文即可。通過這種方式可以保證使用者的下載吞吐量。
該技術以延遲的代價來最大化吞吐量。想象一下,當高優先順序的報文位於大佇列的末尾時,該報文在這個網路上的理論上的延遲可能是100ms,但必須在佇列中等待傳輸。
雖然最大化吞吐量的決定非常成功,但對延遲的影響也是顯著的。
斯圖爾特·柴郡(Stuart Cheshire)在1990年代中期發出了一個名為愚蠢的延遲的警告,它採用了術語bufferbloat
,大約15年後由吉姆·蓋蒂(Jim Getty)在他的部落格的ACM佇列文章bufferbloat:網際網路中的黑暗緩衝和 Bufferbloat FAQ中重點介紹了最大化吞吐量的選擇。
在學術、網路和Linux開發社群中,分組交換網路存在的延遲和吞吐量之間的關係是眾所周知的。 Linux流量控制核心資料結構可以追溯到1990年代,並且一直在不斷開發和擴充套件,並增加了新的排程器和功能。