Linux流量控制指南 (Traffic control HOWTO)
流量控制指南
版本 1.0.2
Martin A. Brown
翻譯 :ziven
pdf 版下載地址:http://download.csdn.net/detail/zgangz/8363599
修訂記錄
修訂號 1.0.2 2006-10-28 修訂者:MAB
增加對HFSC的說明,更改作者的電子郵箱
修訂號 1.0.1 2003-11-17 修訂者:MAB
對引用的Leonardo Balliache的文獻增加連結
修訂號 1.0 2003-09-24 修訂者:MAB
被TLDP審查且批准
修訂號 0.7 2003-9-14 修訂者:MAB
增加修訂號,校對,為新增進TLDP做好準備
修訂號 0.6 2003-09-09 修訂者:MAB
來自Stef Coene的細微修正
修訂號 0.5 2003-09-01 修訂者:MAB
HTP章節基本完成,更多的圖表,LARTC預覽版
修訂號 0.4 2003-08-30 修訂者:MAB
增加圖表
修訂號 0.3 2003-08-29 修訂者:MAB
真正的完成無等級,軟體,規則,要素及元件(classless,software, rules, elements and components)章節
修訂號 0.2 2003-08-23 修訂者:MAB
主要集中在概覽,要素,元件和軟體(overview, elements,components and software)章節
修訂號 0.1 2003-08-15 修訂者:MAB
初始版本(完成大綱)
流量控制包含一組機制和操作,這些機制和操作作用於某個網口上被排隊等待發送/接收的報文。其中操作包括入隊,監管,分類,排程,整流,丟棄。本指南介紹了Linux下流量控制的能力及其運用。
© 2006, Martin A. Brown
本文件允許在自由軟體基金的GNU1.1版或以後釋出的條款下複製,分發和修改。本文件沒有不變的部分,沒有封面文字,沒有封底文字。許可證副本在:
目錄
Linux流量控制介紹
Linux提供了豐富的工具來管理和控制報文的傳送。Linux社群對於在Linux下對報文進行修改、應用防火牆策略(netfiler,以及之前的ipchains)以及大量的可以執行在作業系統上的網路服務工具非常熟悉。但只有小部分Linux社群內和更少的Linux社群外人員瞭解Linux流量控制子系統的強大功能,並且該子系統已經在2.2和2.4核心中變得更為成熟。
本指南試圖介紹流量控制的思想,傳統的流量控制要素,Linux流量控制組件,同時提供了一些參考。這份指南是通過對LARTC指南上的文件以及重要的LARTC郵件列表學習、整理出來的。
本指南的目標讀者是想對流量控制及對Linux下的流量控制工具有所瞭解的網路管理人員或者有一定基礎的家庭使用者
本指南的讀者應該熟悉UNIX操作環境及命令列且具備一定的IP網路知識。如果想要對流量控制進行應用,還需具有對linux核心或軟體進行打補丁,編譯及安裝的能力。對於擁有較新核心版本(2.4.20及以上,參見5.1節)的使用者,只需要會安裝和使用軟體就夠了。
一般來說,本指南應該適合各類使用者。雖然有些讀者可能已經有在Linux下進行流量控制的經驗,但我仍假設所有讀者都沒有相關經驗
本文件是在DocBook中通過vim來編寫的。所有格式由基於DocBook XSL和LDP XSL表格樣式的xsltproc來控制。字型格式和顯示樣式和大多數印刷及電子技術文件相似。
強烈建議讀者先通過tc和tcng來突擊學習下流量控制的規則,在集中學習tcng之前,只需對tc命令列工具有一個大致的瞭解。tcng軟體包定義了一個完整的語言來描述流量控制結構。第一眼看上去,這門語言會讓人生畏,但當你掌握之後,它會使你能很容易使用流量控制,而這是直接使用tc工具不能辦到的。
如果可能的話,我將以一種抽象的方式來描述Linux下流量控制系統的行為,但有些時候我也會借用其他類似的系統來描述這些結構。同一個例子,我不會既用tcng語言又用tc命令列來實現,聰名的讀者會將兩者融會貫通。
本指南仍然缺少些內容。下面的內容會在未來某個時間點新增進本文件。
- 有關GRED, WRR, PRIO 和CBQ的描述及圖表。
- 使用示例
- 對分類器(classifier)進行詳細介紹的小節。
- 對流量測量技術進行討論的小節。
- 對標記有覆蓋的小節。.
- 更多關於tcng的細節.
歡迎將建議,錯誤指正及反饋傳送至<[email protected]>。理論上來說,所有的錯誤和疏忽都是我的錯,雖然我已經盡力確保了當前文件的正確性,但我不能承擔讀者根據此文件進行操作後的任何後果。
2. 流量控制思想概述
本節將會對流量控制進行介紹並且說明為什麼要使用流量控制,然後指出流量控制的一些優缺點,最後介紹在流量控制中涉及的一些關鍵思想。
2.1. 什麼是流量控制?
流量控制是路由器上報文的接收和傳送機制及排隊系統的統稱。這包括在一個輸入介面上決定以何種速率接收何種報文,在一個輸出介面上以何種速率、何種順序輸出何種報文。
在絕大多數情況下,流量控制只包含一個單一佇列,此佇列以硬體所能處理的最大能力接收報文並儘快輸出它們,這種佇列就叫FIFO(first in,first out)。
Linux下的預設排隊規則是pfifo_fast,此規則比FIFO稍複雜。 |
在很多型別的軟體中都有使用佇列的例子。佇列是組織未定任務或資料流的一種方法(參考2.5節)。因為網路鏈路層單純的以序列方式傳送資料流,所以佇列對於管理輸出報文是必要的。
如果一桌面電腦和一臺高效web伺服器共享同一條上行鏈路,它們對頻寬的競爭就可能發生。web伺服器可能會填滿路由器的傳送佇列,當web伺服器傳送資料的速率大於路由器上資料的輸出速率時,路由器就會開始丟包(它的緩衝區滿了)。這個時候,桌面電腦(擁有一個互動使用者)就會面臨丟包及高延時的風險。注意,高延遲有時候會讓使用者抓狂!通過劃分兩個內部佇列給這兩種不同型別的應用使用,這兩種應用就可以較好的分享網路資源。
流量控制是一個工具集,它能夠讓使用者通過它在網路裝置上應用不同的佇列和排隊機制。雖然利用這些工具來重新劃分資料流和報文的功能很強大,並且可以進行復雜的應用,但最好有足夠多的頻寬。
術語服務質量(QoS)通常是流量控制的同義詞。
分組交換網路和電路交換網路的一個重要不同之處是:分組交換網路是無狀態的,而電路交換網路(比如電話網)必須保持其狀態。分組交換網路和IP網路一樣被設計成無狀態的,實際上,無狀態是IP的一個根本優勢。
無狀態的缺陷是不能對不同型別資料流進行區分。但通過流量控制,管理員就能夠基於報文的屬性對其進行排隊和區別。它甚至能夠被用於類比電路交換網路,將無狀態網路模擬成有狀態網路。
有很多實際的理由去考慮使用流量控制,並且流量控制也有很多有意義的應用場景。下面是一些利用流量控制可以解決或改善的問題的例子
下面的列表不是流量控制可以解決的問題的完整列表,此處僅僅介紹了一些能通過流量控制來解決的幾類問題
常用的流量控制解決方案
- 通過TBF和帶子分類的HTB將頻寬限制在一個數值之下
- 通過HTB分類(HTB class)和分類(classifying)並配合filter,來限制指定使用者、服務或客戶端的頻寬。
- 通過提升ACK報文的優先順序,以及使用wondershaper來最大化非對稱線路上的TCP吞吐量。
- 通過帶子分類的HTB和分類(classifying)為某個應用或使用者保留頻寬。
- 通過HTB分類(HTB class)中的(優先順序)PRIO機制來提高延時敏感型應用的效能。
- 通過HTB的租借機制來管理多餘的頻寬。
- 通過HTB的租借機制來實現所有頻寬的公平分配。
- 通過監管器(policer)加上帶丟棄動作的過濾器(filter)來使某種型別的流量被丟棄。
請記住,很多時候,最好去購買更大的頻寬,流量控制並不能解決所有的問題。
2.3. 優點
當正確的使用流量控制時,就能提高網路資源的利用率,並能減少潛在的競爭。正確使用後,網路就會符合流量控制的目標,比如能給大流量的下載分配一個合適的頻寬然後使高優先順序的互動報文也能進行正常的傳送,低優先順序的資料(比如郵件)也能正常的傳輸而不明顯的影響其它資料傳送。
廣義上來說,如果流量控制能符合已和使用者約定好的策略,那麼使用者就能最大限度的使用網路資源。
2.4. 缺點
複雜性是流量控制的主要缺點。而流量控制工具降低了學習流量控制及其機制的難度,雖然有一些方式來熟悉這些流量控制工具,但是從流量控制中找出不正確的配置也是一個挑戰
恰當的使用流量控制可以使網路資源更加公平的被分配,但流量控制很容易被使用不當,如果使用不當就會導致對網路資源的分配更不公,對網路資源的競爭會更大。
為了維護流量控制結構,需要路由器上有足夠的計算資源。幸運的是,它只會消耗較小的計算資源,不過當流量控制規則變得龐大且複雜時它所消耗的資源就不容忽視。
對於個人使用者來說,流量控制幾乎沒什麼成本。但對於公司來說,應用流量控制所帶來的費用可能會比購買更多的頻寬還多,因為培訓一個精通流量控制的人員會比購買更多的頻寬花費多。
儘管分組交換網上的流量控制是一種很寬泛的概念,但你可以認為流量控制提供了一種將電路交換網的有狀態屬性應用到分組交換網的方式。
2.5. 佇列
佇列是流量控制的基礎,而且是排程的實現思想。一個佇列中包含有限個物件,這些物件將在佇列中等待被處理。在網路中,這些物件就是資料包,這些資料包在佇列中等待被硬體傳輸。在最簡單的模式中,資料包按照先進先出的原則進行傳輸,這種佇列在計算機網路(或更廣泛的電腦科學)中被稱為FIFO。
當沒有和其它機制配合使用時,佇列並不能提供流量控制功能。實際上,佇列只有兩種操作:將物件加入到佇列中,即入隊,將物件從佇列中移除,即出隊。
當和其他元件配合時佇列就會具有複雜的功能,比如在多佇列中對報文進行延遲,對報文進行重新排隊,丟棄報文,對報文進行分級。佇列中也可以包含子佇列,以便使用更為複雜的排程方式。
對於高層應用來說,報文就是入隊然後傳送,對於報文是以何種順序、何種方式被髮送的,高層應用並不關心。因此,對於高層應用來說,流量控制表現出來的就是一個單一佇列。只有對應用流量控制的那一層來說,流量控制結構才是可見的。
2.6. 資料流
一條資料流就是兩臺主機之間的連線或會話。兩臺主機之間的任何資料互動報文可以被認為一條資料流。在TCP中,源IP加源埠和目的IP加埠的連線就決定了一條資料流,UDP也類似。
流量管理機制常常會將流量劃分為不同類的資料流,這些流可以被聚合起來然後作為一條聚合流被傳輸(DiffServ,差分服務)。不同的流量控制機制能基於不同的流將頻寬進行均等的劃分。
如果想對頻寬進行均分,然後分配給對頻寬有競爭關係的資料流,那麼對資料流進行處理就很重要。特別是有些應用會產生大量的資料流,這時的流量管理就更為重要。
2.7. 令牌桶
整流的兩個關鍵要素就是令牌桶。
為了控制出隊的速率,一種方式就是直接統計佇列中出隊的報文或位元組數,但是為了保證精確性就需要複雜的計算。在流量控制中廣泛應用的另一種方式就是令牌桶,令牌桶以一定的速率產生令牌,報文或位元組出隊時從令牌桶中取令牌,只有取到令牌後才能出隊。
我們可以打一個比方,一群人正排隊等待乘坐遊樂場的遊覽車。讓我們想象現在有一條固定的道路,遊覽車以固定的速度抵達,每個人都必須等待遊覽車到達後才能乘坐。遊覽車和遊客就可以類比為令牌和報文,這種機制就是速率限制或流量整形,在一個固定的時間段內只有一部分人能乘坐遊覽車。
繼續上面的比方,設想有大量的遊覽車正停在車站等待遊客乘坐,但現在沒有一個遊客。如果現在有一大群遊客同時過來了,那麼他們都可以馬上乘上游覽車。在這裡,我們就可以將車站類比為桶,一個桶中包含一定數量的令牌,桶中的令牌可以一次性被使用完而不管資料包到達的時間。
讓我們來完成這個比方,遊覽車以固定的速率抵達車站,如果沒人乘坐就會停滿車站,即令牌以一定的速率進入桶中,如果令牌一直沒被使用那麼桶就可以被裝滿,而如果令牌不斷的被使用那麼桶就不會滿。令牌桶是處理會產生流量突發應用(比如HTTP)的關鍵思想。
使用令牌桶過濾器的排隊規則(TBF qdisc,Token Bucket Filter)是流量整形的一個經典例子(在TBF小節中有一個圖表,通過該圖表可以形象化的幫助讀者理解令牌桶)。TBF以給定的速度產生令牌,當桶中有令牌時才傳送資料,令牌是整流的基本思想。
在某些情況下,佇列中可能無資料包,因此不會立即需要令牌,這些令牌就會被收集起來直到佇列需要。但無限制的積累令牌可能會失去流量整形的意義,所以令牌積累到一定量就會停止。由於積累了令牌,當有大量的報文或位元組需要出隊時就有足夠的令牌可用。這種虛擬的令牌被儲存在虛擬的桶中,一個桶中能存放多少令牌取決於桶的大小。
這意味著如果桶的大小設計不合理,在任何時刻桶中都可能充滿令牌。小型的令牌桶適合流量較為穩定的網路,大型的令牌桶適合有較大突發流量的網路,除非你的目的就是為了限制資料流的突發傳輸。
總之,令牌以固定的速度產生,桶中可以積滿令牌,這樣就可以處理突發流量,使網路流量更為平滑。
令牌和桶的概念緊密相聯,它們被用於TBF(一種無類qdiscs)和HTB(一種分類qdiscs)中。在tcng語言中,二色和三色標識法就是令牌桶的應用。
2.8. 包和幀
在網路上傳輸的資料該被稱為什麼,其術語取決於其所在的網路層。本文件將不會區分兩者在技術上的差別(不區分是錯的),儘管在這裡列出了這兩個術語。
幀通常是用來描述第2層(資料鏈路層)上傳送給下一接收者的資料。乙太網介面,PPP介面,T1介面都把他們的第2層資料叫作幀。在流量控制中,幀其實就是其處理單位。
包就是對更高層資料單元的稱呼,即第3層(網路層),在本文件中我們更多的會使用包這一術語,雖然這麼用不夠準確。
(譯註:在本譯文中,資料包和報文混用)
整流器通過延遲資料包來使流量保持在一定速率。
整流就是讓包在輸出佇列上被髮送之前進行延時,然後一定的速率傳送,使網路流量保持在一定的速率之下,這是大部分使用者進行流量控制的目的。報文延時作為流量控制的一部分,使得所有整流演算法都是非工作保留模式的,大致解釋就是“必須保持工作來延遲報文”。
非工作保留模式提供了整形的功能,反過來看,工作保留排隊機制(參考PRIO,優先順序排程)就不具備流量整形的功能,因為其不能對報文進行延時。
整流器將流量控制在一個給定速率下(通常以pps,bps,Bps為單位)。當然其也有副作用,那就是整流器平滑了突發流量。對頻寬進行整流的好處是可以控制報文的延時,整流的思想就是利用令牌桶,可以閱讀2.7節獲取更多有關令牌桶的資訊。
(譯註:工作保留就是為較高優先順序的報文保留部分資源,在非工作保留模式下,當有報文可處理時就處理,在工作保留模式下,即使有報文需要處理,就算資源空閒,其也會為高優先順序的報文保留部分資源)
排程器(scheduler)排列或重排輸出報文。
排程就是對佇列中的輸入輸出報文進行排列。最常的排程方法就是FIFO(先進先出),更廣泛的來說,在輸出佇列上的任何流量控制都可以被稱作排程,因為報文被排列以被輸出。
有很多排程演算法被用於不同的網路環境,一種公平排程演算法(參考SFQ)用來阻止某一個客戶端或資料佔用太多網路資源,一種輪循排程演算法(參考WRR)讓每條資料流輪流出隊,還有一些比較複雜的排程演算法用來防止主幹網流量過載(參考GRED)或還有一些用來改進其它排程演算法的演算法(參考ESFQ)。
分類器(classifier)將流量分類、劃分到不同佇列中。
分類就是將流量進行劃分以便區別處理,例如拆分後放到不同的輸出佇列中。在報文的接收、路由、傳送過程中,網路裝置可以用多種方式來分類報文。分類包括對報文進行標記,標記可以在邊際網路中由一個單一的控制單元來完成,也可以在每一跳中都進行標記。
Linux允許報文依次通過一系列分類器,而且還可以通過和監管器(policer)配合來對報文進行分類。
監管器(Policer)計算和限制佇列中的流量。
監管作為流量控制的一部分,就是用於限制流量。監管常用於網路邊際裝置,使某個節點不能使用多於分配給它的頻寬。監管器以特定的速率接收資料包,當流量超過這一速率時就對接收的資料包執行相應的動作。最嚴格的動作就是丟棄資料包,儘管該資料包可以被重新分類。
當流量以一定的速率進入佇列時,監管器只有兩個動作:當資料包以低於給定速率進入佇列時,執行一個動作(允許入隊),當資料包以高於給定速率進入佇列時,執行另一個動作。儘管監管器內部使用了令牌桶,但是它不具備整流器延遲報文的能力。
丟棄就是丟掉整個資料包,整條流或一類流量。
丟棄就是通過某種機制來選擇哪個資料包被丟掉。
標記對資料進行更改。
這裡不是指fwmark,iptables和ipchains的標記都是用來修改資料包的元資料,而不是資料包本身。 |
流量控制在資料包中插入了DSCP部分,在一個可管理網路中,其可被其它路由器利用和識別(通常用於DiffServ,差分服務)。
表1. 流量控制元素和Linux元件之間的聯絡
傳統元素 |
Linux元件 |
整流(shaping) |
class元件提供整流功能。 |
排程(scheduling) |
qdisc是一個排程器。排程器可簡可繁,簡單的如FIFO,複雜的如帶分類的qdisc,其他的如HTB。 |
分類(classifying) |
filter加上classifier提供了分類功能,嚴格來說,Linux的classifier離不開filter。 |
監管(policing) |
在Linux流量控制機制中,policer僅僅作為filter一個功能。 |
丟棄(dropping) |
為了運用丟棄,需要一個filter和一個動作是“drop”的policer相配合。 |
標記(marking) |
qdisc提供標記的功能。 |
簡單來說,qdisc是一個排程器(參見3.2節)。每個輸出介面都有一個排程器,預設的排程器就是FIFO。Linux下可用的排程器會按照排程器的規則對進入佇列的包進行重新排列。
qdisc是Linux流量控制設計的主要部分,也被稱為排隊規則(quenuing discipline)。
分類qdisc(classful qdisc)可以包含多個類別(class),其也提供了可以附加到filter的控制代碼。使用不帶子類的classful qdisc是允許的,儘管這會造成系統資源的浪費。
非分類qdisc是不帶class的,所以其也不能被附加到一個filter,由於非分類qdisc不帶任何子物件,所以不能用來對流量進行分類。這就意味著沒有filter能被附加到一個非分類qdisc。
術語root qdisc和ingress qdisc常使人混淆,其實它們都不是真正的排隊規則,它們只是流量控制可以被實施的地方,即入口(輸入流量)和出口(輸出流量)處。
每個介面既包含root qdisc又包含ingress qidsc。最主要也是最常見的就是入口排隊規則(egress qdisc),即root qdisc。它能包含任何帶分類或分類結構的排隊規則。絕大多數文件都是針對root qdisc和它的子集的,介面上的流量都得通過egress或root qdisc。
對於在介面上接收的流量,會先通過ingress qdisc,由於元件的限制,ingress qdisc不能建立子分類,而且只能和一個filter相關聯。在實際運用中,ingress qdisc僅僅和一個policer相關聯來方便的限制網路介面上接收的資料量。
簡而言之,你可以利用egress實現更為強大的功能,因為它包含一個真正的qdisc並且具有流量控制系統的完整功能。一個ingress qdisc僅僅支援一個policer。本文件的餘下部分除非有特殊說明,將只關心和root qdisc有關的流量控制結構。
4.2. 分類(class)
分類只存在於可分類排隊規則(classful qdisc)(例如,HTB和CBQ)中。分類可以很複雜,它可以包含多個子分類,也可以只包含一個子qdisc。在超級複雜的流量控制應用場景中,一個類中再包含一個可分類qdisc也是可以的。
任何一個分類都可以和任意多個filter相關聯,這樣就可以選擇一個子分類或運用一個filter來重新排列或丟棄進入分類中的資料包。
葉子分類是qdisc中的最後一個分類,它包含一個qdisc(預設是FIFO)並且不包含任意子分類。任何包含子分類的分類都是內部分類而不是子分類。
4.3. 過濾器(filter)
過濾器是流量控制系統中最複雜的部分。過濾器提供了一種方便的機制將流量控制中的幾個關鍵要素集合在了一起。過濾器最簡單且最常見的功能就是分類資料包(參見3.3節)。Linux的過濾器可以允許使用者利用一個或多個過濾器將資料包分類至輸出佇列上。
- 一個過濾器必須包含一個分類器(classifier)。
- 一個過濾器可以包含一個監管器(policer)。
過濾器既可以和可分類的qdisc相關聯,也可以和分類(class)相關聯。已入隊的資料包首先通過root qdisc,當資料包通過了和root qdisc相關聯的過濾器後,資料包可以被送入子分類(subclass)(子分類也可以有自己的過濾器)以進行進一步的分類。
4.4. 分類器(classifier)
分類器(filter)可以通過tc工具來管理,它可以運用不同的分類器,最常用的就是u32分類器,u32分類器可以允許使用者基於資料包的屬性來選擇資料包。
分類器作為filter的一部分,可以用來識別資料包或資料包元資料的特徵。Linux分類器是Linux流量控制中有關分類的直接實現。
4.5. 監管器(policer)
在Linux中,監管器這個關鍵部分只能作為filter的一部分來使用,監管器在速率超過指定速率時執行一個動作,在速率低於指定速率時執行另一個動作。可以巧秒的利用監管器來模擬三色標識法,參考第10節。
當利用監管器來限制頻寬時,儘管監管和整形都是流量控制的基本元素,但它們從不延遲任何流量。基於指定的準則,監管器只能執行一個動作。可參考例5。
4.6. 丟包(drop)
在Linux流量控制中,drop僅能作為policer的一部分。任何和filter相關聯policer都可以有drop動作。
在Linux流量控制系統中,資料包只能在policer中被顯示的丟棄,policer能以指定的數率限制資料包入隊,也能丟棄匹配某種模型的所有資料包。 |
然而,在流量控制系統的某些地方,資料包可能作為一個副作用被丟棄。例如,如果排程器(scheduler)使用和GRED一樣的方式來控制資料流時,資料包就可能會被丟棄。
另外,當流量突發或流量過載的時候,整形器(shaper)或排程器(scheduler)可能會耗盡分配給它的緩衝區而不得不丟棄資料包。
4.7. 控制代碼(handle)
在流量控制結構中,每個分類或可分類qdisc(參見第7節)都需要一個唯一的識別符號。這個唯一識別符號就是我們所說的控制代碼,一個控制代碼由兩組數字組成:一個主編號和一個次編號。這些編號可以由使用者根據下面的規則任意分配。
class和qidsc控制代碼的編號準則
主編號(major)
這個編號對核心來說完全沒有意義。使用者可以使用任意一種方式來編號,但是在流量控制系統中,具有相當父物件的子物件應該使用相同的主控制代碼號。和root qdisc直接關聯的物件,習慣上從1開始給它們編號。
次編號(minor)
如果次編號為0,那麼就明確的表明這個物件是一個qdisc,其他非零值則表示該物件是class。所有擁有同一父class的class必須使用同一個次編號。
ffff:0這個控制代碼號保留給ingress qidsc使用。
在tc的filter中,控制代碼被作為classid和flowid的引數使用。控制代碼是物件的外部識別符號,在使用者側應用中被使用,而在核心中,核心為每個物件都分配了一個對應的內部識別符號。
5. 軟體包和工具集
5.1. 核心版本要求
許多Linux發行版都提供了帶流量控制(QoS)功能的核心,該功能作為一個單獨的模組存在,或直接編譯在核心中。定製化的核心可能不包含流量控制功能,這時就可以按照下面列出的核心選項配置核心。
對於編譯核心沒有或只有一點經驗的使用者,建議參考KernelHOWTO。對於編譯核心有經驗的使用者,在對流量控制有一定了解後,應該知道下面的選項哪一些應該被選擇。
例1. 核心編譯選項
# # QoS 和或公平排隊(fair queueing) # CONFIG_NET_SCHED=y CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_HTB=m CONFIG_NET_SCH_CSZ=m CONFIG_NET_SCH_PRIO=m CONFIG_NET_SCH_RED=m CONFIG_NET_SCH_SFQ=m CONFIG_NET_SCH_TEQL=m CONFIG_NET_SCH_TBF=m CONFIG_NET_SCH_GRED=m CONFIG_NET_SCH_DSMARK=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_QOS=y CONFIG_NET_ESTIMATOR=y CONFIG_NET_CLS=y CONFIG_NET_CLS_TCINDEX=m CONFIG_NET_CLS_ROUTE4=m CONFIG_NET_CLS_ROUTE=y CONFIG_NET_CLS_FW=m CONFIG_NET_CLS_U32=m CONFIG_NET_CLS_RSVP=m CONFIG_NET_CLS_RSVP6=m CONFIG_NET_CLS_POLICE=y |
按上面的選項編譯後的核心將能以模組化的方式提供本文件所討論的任何元件。當需要使用相應功能時,使用者可以使用modprobe來載入對應模組。再說一次,推薦有困惑的使用者去閱讀Kernel HOWTO,通過本文件並不能解決有關使用Linux核心的問題。
iproute2是一組命令列工具元件,用來操作一臺機器上有關IP網路配置的核心結構。有關這些工具的技術文件,參見iproute2 documentation,如果想了解更多,可以參考linux-ip.net 上的文件。在iproute2軟體包的眾多工具中,tc是唯一用來進行流量控制的工具,本指南將忽略其它工具。
由於tc直接作用於核心來建立、刪除、修改流量控制結構,所以在編譯tc時需要提前安裝你想使用的所有qdisc。特別的,HTB qdisc還末在上游iproute2軟體包中被支援,更多資訊請參見7.1小節。
例2. 使用tc命令
[[email protected]]# tc Usage: tc [ OPTIONS ] OBJECT { COMMAND | help } where OBJECT := { qdisc | class | filter } OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] } |
每個物件都有更多且不同的選項,本文件不會完整涉及到所有選項,下面的例子將盡可能展現tc命令的使用。可以訪問LARTC HOWTO來獲取更多的例子,如果想更好的理解tc,可以參考核心和iproute2的程式碼。
例3. tc qidsc
[[email protected]]# tc qdisc add \ > dev eth0 \ > root \ > handle 1:0 \ > htb |
新增一個排隊規則,也可以使用del來刪除。
指定將和新排隊規則相關聯的裝置。
對tc來說,root就是指 “egress”,但是這裡必需使用單詞“root”。對於另一個有功能限制的qdisc:ingress qdisc,其可以被關聯到同一裝置上。
handle 是使用者指定的一個編號,其格式是主編號:次編號。對任何排隊規則控制代碼來說,次編號必需是0。排隊規則(qidsc)控制代碼的一種可用簡寫形式是“1:”,當沒有指定次編號時就預設為0。
需要使用的排隊規則,本例中是HTB。排隊規則需要的一些引數可以跟在後面,本例中,我們沒有其他引數。
上例是使用tc工具給一個裝置新增排隊規則的簡單例子,下面是使用tc給一個存在的父class新增子class的例子。
例4. tc class
[[email protected]]# tc class add \ > dev eth0 \ > parent 1:1 \ > classid 1:6 \ > htb \ > rate 256kbit \ > ceil 512kbit |
新增一個class,也可以用del刪除。
指定我們將要關聯新class的裝置。
指定我們將要關聯新class的父class控制代碼。
標識此class的唯一控制代碼(主編號:次編號)。次編號必需為非零值。
帶分類的qdisc需要所有的子class都和其是相同的型別,因此,HTBqdisc將包含HTB classes。
class的引數,檢視7.1節來獲取關於這些引數的更多詳細資訊。
例5. tc filter
[[email protected]]# tc filter add \ > dev eth0 \ > parent 1:0 \ > protocol ip \ > prio 5 \ > u32 \ > match ip port 22 0xffff \ > match ip tos 0x10 0xff \ > flowid 1:6 \ > police \ > rate 32000bps \ (11) > burst 10240 \ (12) > mpu 0 \ (13) > action drop/continue (14) |
新增一個filter,也可以使用del來刪除。
指定新的filter將要關聯的裝置。
指定新的filter將要關聯的父控制代碼。
這個引數是必要的,它應該被顯示的使用,儘管我不知道它還有什麼其他功能。
prio引數能使一個filter在另一個之前被使用,pref是prio的同義詞。
這是一個分類器(classifer),所有tc filter命令都需包含該選項。
這些是分類器的引數。在本例中,帶有服務標識且埠號是22的資料包將會被選擇。
flowid指定了一個目標class(或qdisc)控制代碼,filter所選擇的資料包將發往這個控制代碼所指向的class(或qdisc)。
這是一個監管器(policer),在tc fitler命令中,這是一個可選選項。
(11) 當超過這個速率時,監管器將執行一個動作,低於這個速率時,監管器將執行另一個動作。
(12) burst相當於HTB中的burst(burst採用的是桶(bucket)原理)。
(13) 被監管的最小資料單位。為了統計所有流量,使用mpu 0。
(14) action指定了當流量大於給politer所配置的 rate時應採取的動作。第一個詞指明瞭當流量超過rate時所要執行的操作,第二個詞指明瞭其他情況下應該採取的操作。
正如你在上面所看到的,tc命令列工具語法晦澀且複雜,即使是一個簡單的操作都要進行復雜的配置。當然你不必感到吃驚,因為在Linux下,我們有更容易的方式來配置流量控制結構。參見下一小節5.3。
5.3. tcng, 下一代流量控制(Traffic Control Next Generation)
下一代流量控制(也就是這裡的tcng)將會以一種非常簡單的方式提供Linux下流量控制所有的功能。
此節有待補充;對於IMQ的探討是必須的。可以參考Patrick McHardy網站上有關IMQ的內容。
6. 無分類排隊規則 (qdiscs)
下面的任一無類排隊規則都可以作為一個網路介面的主要排隊規則,或者作為分類排隊規則的葉子分類(leaf class)。下面的這些排隊規則都是在Linux下使用的基本規則。
6.1. FIFO, 先進先出 (pfifo and bfifo)
FIFO不是Linux網路介面上使用的預設排隊規則(qdisc),有關預設排隊規則(pfifo_fast)的完整資訊請參考6.2節。 |
FIFO演算法是所有Linux網路介面預設排隊規則的基本組成形式。FIFO既不能對流量進行整形也不能對資料包進行重新排列,當收到資料包後它只能儘快的傳輸它們。FIFO也是所有新建立的class內部使用的排隊規則,直到被其他排隊規則或class替換。
實際使用的FIFO都有一個緩衝區來防止溢位,當FIFO不能及時將它所收到的資料包出隊時就使用緩衝區將資料包暫時快取起來。Linux運用了兩種型別的FIFO,一種基於位元組,一種基於報文。不管是哪種型別的FIFO,佇列的大小都由引數limit來定義。基於報文的fifo(pfifo)其單位就是報文,基於位元組的fifo(bfifo)其單位就是位元組。
例6. 為基於報文或位元組的FIFO設定一個大小
[[email protected]]# cat bfifo.tcc /* *在eth0上建立一個大小為10k位元組的FIFO佇列 * */ dev eth0 { egress { fifo (limit 10kB ); } } [[email protected]]# tcc < bfifo.tcc tc qdisc add dev eth0 handle 1:0 root dsmark indices 1 default_index 0 tc qdisc add dev eth0 handle 2:0 parent 1:0 bfifo limit 10240 [[email protected]]# cat pfifo.tcc /* *在eth0上建立一個可容納30個數據包的FIFO佇列 * */ dev eth0 { egress { fifo (limit 30p ); } } [[email protected]]# tcc < pfifo.tcc # ======================Device eth0 ============================ tc qdisc add dev eth0 handle 1:0 root dsmark indices 1 default_index 0 tc qdisc add dev eth0 handle 2:0 parent 1:0 pfifo limit 30 |
pfifo_fast是Linux上所有介面的預設排隊規則(qdisc)。pfifo_fast基於傳統的FIFO排隊規則,但它支援優先順序,它為分離的流量提供了三種不同等級的通道(三條獨立的FIFO)。最高等級的流量(互動資料流)被放入0號通道且被優先處理,通道1中的資料包優先於通道2中的資料包被處理。
pfifo_fast對使用者來說沒有什麼需要配置的。有關priomap和Tos使用的更詳細資訊請參考pfifo-fast section of the LARTC HOWTO。
SFQ 試圖讓任意數量的資料流都有平等的機會來向網路傳輸資料。它通過一個雜湊函式將資料流分配到不同的FIFO佇列中,然後以輪循的方式依次出隊這些佇列中的資料。由於所選擇的雜湊函式可能會產生明顯的不公平性,雜湊函式會被定期的更換,引數perturb用來設定雜湊函式的更換週期。
例7. 建立一個SFQ
|
不幸的是,一些自作聰明的軟體(例如Kazaa,eMule等等)破壞了公平排隊的好處,它們持續不斷的建立儘可能多的TCP會話。在許多網路中,如果應用能遵守規範,SFQ能很好的將網路資源分給對資源有競爭的資料流,但當某些討厭的應用產生大量的資料流時就必需採用其它措施了。
參考6.4節,瞭解一種可供使用者使用的,擁有更多引數的SFQ排隊規則。
從概念上來講,ESFQ除了擁有更多的可用引數外,和它的同輩SFQ沒有什麼不同。ESFQ只是為了克服上節所述的SFQ的缺點而被提出。它允許使用者選擇雜湊演算法來分配網路頻寬,使頻寬的分配更公平。
例8. ESFQ的使用
Usage: ... esfq [ perturb SECS ] [ quantum BYTES ] [ depth FLOWS ] [ divisor HASHBITS ] [ limit PKTS ] [ hash HASHTYPE] Where: HASHTYPE := { classic | src | dst } |
待補充,需要補充實際例子和解釋。
待補充,我從沒有使用過GRED,需要實用例子和解釋。
RED演算法的原理表明,它在骨幹網和核網上非常有用,在末級使用者處幾乎無用。檢視資料流這一節來簡單瞭解下TCP
TBF是建立在令牌桶之上,它對介面上的流量進行整形。為了限制某一特定介面上報文的出隊速率,TBF排隊規則將是一個不錯的選擇,它能將報文的傳送速率降到指定值。
如果有足夠的令牌,資料包就被傳輸,否則,資料包會被延遲。通過這種方式延遲報文將會給報文的往返造成人為的延時。
例9.建立一個速率為256kbit/s的TBF
[[email protected]]# cat tbf.tcc /* * 在eth0上建立一個速率為256kbit/s的TBF * */ dev eth0 { egress { tbf( rate 256 kbps, burst 20 kB, limit 20 kB, mtu 1514 B ); } } [[email protected]]# tcc < tbf.tcc # ======================== Device eth0 =============================== tc qdisc add dev eth0 handle 1:0 root dsmark indices 1 default_index 0 tc qdisc add dev eth0 handle 2:0 parent 1:0 tbf burst 20480 limit 20480 mtu 1514 rate 32000bps |
7. 分類排隊規則(qdiscs)
通過分類排隊規則可以使流量控制更易操作、更靈活。記住,分類排隊規則可以和filter相關聯,這樣就可以讓資料包被送往特定的分類或子佇列。
有幾個常見的術語來描述和root qdisc以及末梢分類直接相關聯的分類(class)。和root qdisc相關聯的分類,通常被稱為根分類(root class),或者更通用的被稱為內部分類(inner class)。在特定排隊規則中的末梢分類(terminal class)通常被稱為葉子分類(leaf class),就好比一棵樹的葉子一樣。在本文中,除了將這種結構比喻成一棵樹外,還會運用家庭成員關係來描述。
HTB利用令牌和桶的概念,並基於分類和filter實現了一個複雜且精細的流量控制方法。通過複雜的租借機制(borrowingmodel),HTB能實現複雜且多樣的流量控制機制。HTB最簡單、最快速的應用就是整形(shaping)。
如果理解了令牌和桶,或者瞭解TBF的機制,那麼學習HTB就輕而易舉。HTB允許使用者自己定義令牌和桶的屬性,然後按照需求對這些桶分類。當和分類機制(classifying scheme)配合使用時,就能將流量控制得更為精細。
下面是tc工具在命令列上輸出的HTB用法,儘管tcng有它自己的語法,但對於HTB的使用都是相同的。
例10. tc的HTB用法
Usage: ... qdisc add ... htb [default N] [r2q N] default minor id of class to which unclassified packets are sent {0} r2q DRR quantums are computed as rate in Bps/r2q {10} debug string of 16 numbers each 0-3 {0} ... class add ... htb rate R1 burst B1 [prio P] [slot S] [pslot PS] [ceil R2] [cburst B2] [mtu MTU] [quantum Q] rate rate allocated to this class (class can still borrow) burst max bytes burst which can be accumulated during idle period {computed} ceil definite upper class rate (no borrows) {rate} cburst burst but for ceil {computed} mtu max packet size we create rate map for {1600} prio priority of leaf; lower are served first {0} quantum how much bytes to serve from leaf at once {use r2q} TC HTB version 3.3 |
不像這裡討論的其它規則,HTB是一個比較新的排隊規則,你所使用的Linux發行版可能沒有相應的操作工具或者沒有HTB的功能。要使用HTB,就必需使用支援HTB的核心,核心主幹版本2.4.20及其以上版本支援HTB,較低版本的核心需要打相應的補丁。為了在應用中使用HTB,參見HTB中有關tc的iproute2補丁資訊。
HTB最常用的用法包含將網路流量限制在一個指定速率之下。
所有的整形都發生在葉子分類中(leaf class),在根(root)或內部(inner)分類(class)中不會進行整形,根分類僅僅決定租借機制如何分發可用令牌。
HTB排隊規的一個基本組成部分就是租借機制。當子分類的流量超過了rate之後,就可以向父分類借用令牌。一個子分類會一直嘗試向父分類借用令牌,直到該子分類的流量達到ceil,這個時候子分類就會將資料包入隊,以等待有更多的可用令牌。HTB只建立兩種基本型別的分類,下面的圖表列出了在租借機制影響下,兩種分類在各種可能狀態可能會產生的相產動作。
表2. HTB分類在不同狀態下可能會採取的動作
分類 型別 |
類狀態 |
HTB 內部狀態 |
動作 |
葉子(leaf) |
< rate |
HTB_CAN_SEND |
只要有可用令牌就傳送資料包 (不超過burst 個數據包)。 |
> rate, < ceil |
HTB_MAY_BORROW |
葉子分類會嘗試向父分類借用令牌(token或ctoken),如有父分類有足夠的令牌,葉子分類會以quantum的整數倍借用令牌傳送資料,但傳送的資料包總數不能超過cburst位元組。 |
|
葉子(leaf) |
> ceil |
HTB_CANT_SEND |
將不會發送任何資料包,為了將速率限制在rate之下,會對資料包造成延時。 |
inner, root |
< rate |
HTB_CAN_SEND |
內部分類向子分類借出令牌。 |
inner, root |
> rate, < ceil |
HTB_MAY_BORROW |
內部分類會嘗試向父分類借用令牌(token或ctoken),然後以quantum的整數倍將借用的令牌再租借給它的子分類。 |
inner, root |
> ceil |
HTB_CANT_SEND |
內部分類既不會向父分類借用令牌,也不會向它的子分類借出令牌。 |
下圖描繪了借用令牌時令牌的流向,以及向父分類歸還令牌的方法。為了使租借模型能正常工作,必須明確的指定每個分類及其該分類所有子類的可用令牌數量。每個子分類都向它的父分類歸還令牌,這樣一級級歸還,直到根分類。
任何想要借用令牌的子分類都向它的父分類借用,如果父分類由於超過了它的rate而沒有令牌,父分類就會向它的父分類借用,這樣一級級直到借到令牌或到達根分類為止。因此,借用令牌時,令牌從根向葉子的方向流動;歸還令牌時,令牌從葉子向根的方向流動。
注意,該圖中有多個根分類,每個根分類都可以模擬成一條虛擬線路。
default
這是HTB排隊規則的一個可選引數,預設值為0, 當值為0時意味著會繞過所有和rootqdisc相關聯的分類,然後以最大的速度出隊任何未分類的流量。
rate
這個引數用來設定流量傳送的最小期望速率。這個速率可以被當作承諾資訊速率(CIR), 或者給某個葉子分類的保證頻寬。
ceil
這個引數用來設定流量傳送的最大期望速率。租借機制將會決定這個引數的實際用處。 這個速率可以被稱作“突發速率”。
burst
這個引數是rate桶的大小(參見令牌桶這一節)。HTB將會在更多令牌到達之前將burst個位元組的資料包出隊。
cburst
這個引數是ceil桶的大小(參見令牌桶這一節)。HTB將會更多令牌(ctoken)到達之前將cburst個位元組的資料包出隊。
quantum
這個是HTB控制租借機制的關鍵引數。正常情況下,HTB自己會計算合適的quantum值,而不是由使用者來設定。對這個值的輕微調整都會對租借和整形造成巨大的影響,因為HTB不僅會根據這個值向各個子分類分發流量(速率應高於rate,小於ceil),還會根據此值輸出各個子分類中的資料。
r2q
通常,quantum 的值由HTB自己計算,使用者可以通過此引數設定一個值來幫助HTB為某個分類計算一個最優的quantum值。
mtu
prio
下面是一些從http://docum.org/ 和LARTC mailing list上挑選出來的使用HTB的一般性提示。這些只是針對初學者的提示,以便初學者能最大化的掌握HTB,如果你有HTB的實際使用經驗,就沒必要看這些建議了。
· 整形只會發生在HTB的葉子分類中,參見第7.1.2小節。
· 由於只會在HTB的葉子分類中進行整形,所以所有葉子分類的速率(rate)之和應該不大於父分類速率的最大值(ceil)。在理想情況下,葉子分類的總速率應該和父分類的速率相同,這樣父分類總是會有剩餘的頻寬分配給子分類。
這是HTB的一個關鍵點,我們一再重複。只有葉子分類能對流量進行整形,資料包也只會在葉子分類中被延時,所有的內部分類(從葉子分類開始一直到根分類的所有分類)只是決定如何進行租借。
· quantum只會在某個分類的速率大於rate小於ceil時起作用。
· quantum應該被設定成MTU或更大。即使quantum的值被設定得過小,HTB只要有機會也會出隊一個數據包,不過這樣就不能準確的計算真實的頻寬消耗了。
· 父分類向子分類租出的令牌以quantum的倍數增加,所以為了最大粒度、最為迅速的公平分發頻寬,quantum的值應該儘可能的小,但不能小於MTU。
· token和ctoken只有在葉子分類中才有區別,因為非葉子分類只是向子分類租借令牌。
· HTB的租借模型應該更為準備的被稱為“使用”。
7.2. HFSC, 分層公平服務曲線
本節將會在稍後完善。
PRIO分類排隊規則有一個非常簡單的準則,當它準備傳送資料包時,它會檢查第一個分類中有沒有資料包,如果有就傳送資料包,如果沒有就檢查下一個分類,直到佇列中的最後一個分類。
本節將會在稍後完善。
CBQ是流量控制系統的典型排隊演算法,本節稍後會完善。
8. 流量控制的常見規則和方法
下面的一些規則可以使流量控制的學習更簡單,不管是使用tcng來配置或tc來配置,Linux下的流量控制結構都是相同的。
- 應當只有在路由器出現瓶頸時才去實施流量整形,而且流量整形值應該比最大頻寬稍低,這樣就能防止從其它路由器過來的大量資料流阻塞路由器,同時也能保證路由器的最大處理能力。
- 只能對裝置傳送的流量進行整形,當流量被入口接收後,就不能對其進行整形了。該問題的傳統解決方案是利用ingress policer。
- 每個介面都有一個預設排隊規則,當介面上沒有顯示指明使用哪一種qdisc時就會使用預設qdisc。
- 給介面配置一個沒有子class的分類qdisc是毫無用處的,僅僅消耗了CPU資源。
- 每個新建立的class內部預設都是使用的FIFO排隊規則,可以用其它排隊規則來代替FIFO,如果有一個子class和這個新建的class相關聯,那麼FIFO排隊規則將會被刪除。
- 可以將分類(class)和根排隊規則(root qdisc)直接關聯起來,用來模擬一個虛擬線路。
- filter可以和分類(class)或者一個可分類排隊規則(classful qdisc)關聯起來。
8.2. 在已知頻寬的線路上實施流量控制
在已知頻寬的線路上實施流量控制,HTB是一個完美的選擇。最內部(最頂端)的分類可以配置成允許最大頻寬的流量進入,然後資料流可以被劃分到各個子分類(children class)中,我們可以為某些子類保留一定頻寬,或者讓某些特殊的流量優先傳送。
8.3. 在可變(或未知)頻寬的線路上實施流量控制
理論上來說,PRIO排程器(scheduler)是在可變頻寬上實施流量控制的完美方案,因為它是一個工作保留型的排隊規則(這也意味著PRIO沒有整形功能)。在一個頻寬未知或有波動的網路中,PRIO排程器簡單的先將最高優先順序通道中的資料包出隊,然後再將次優先順序佇列中的資料包出隊。
8.4. 基於流來分享、劃分頻寬
對網路頻寬的競爭有多種形式,SFQ是解決競