1. 程式人生 > >Linux核心TC工具鏈路頻寬設計--無類佇列規定

Linux核心TC工具鏈路頻寬設計--無類佇列規定

      Linux 核心的 TC(traffic control)工具可以用來對網路頻寬做一定的設計和管理,這裡將對這一工具的使用做一定的介紹,在正式開始介紹TC 之前,先對一些基本的單位做一個說明。為了避免概念混亂,TC 採用如下規定來描述頻寬:

mbps = 1024 kpbs = 1024 * 1024 bps => byte/s
mbit = 1024 kbit => kilo bit/s
mb = 1024 kb = 1024 * 1024 b => byte
mbit = 1024 kbit => kilo bit
內定:數字以 bps 和 b 方式儲存,但當 tc 輸出速率時,使用如下表示:
1Mbit 
= 1024 Kbit = 1024 * 1024 bps => byte/s

 

1.1 解釋佇列和佇列規定

      利用佇列,我們決定了資料被髮送的方式。必須認識到,我們只能對傳送資料進行整形。

      根據Internet 的工作方式,我們無法直接控制別人向我們傳送什麼資料。就像我們家裡的信報箱,你不可能控制全世界,聯絡每一個人,修改別人對你傳送郵件的數量。然而,Internet 主要依靠TCP/IP,它的一些特性很有用。因為TCP/IP 沒辦法知道兩個主機之間的網路容量,所以它會試圖越來越快地傳送資料(所謂的“慢起技術”) ,當因為網路容量不夠而開始丟失資料時,再放慢速度。

      如果你有一個路由器,並且希望能夠防止某些主機下載速度太快,你需要在你路由器的內網絡卡——也就是向你的網內主機發送資料包的網絡卡——上進行流量整形。還要保證正在控制的是瓶頸環節。如果有一個100M 乙太網卡,而路由器的鏈路速度是 256k,則必須保證傳送的資料量沒有超過路由器的處理能力。否則,就是路由器在控制鏈路和對頻寬進行整形,而不是你。可以說,我們需要擁有的佇列必須是一系列鏈路中最慢的環節。

 

1.2 簡單的無類佇列規定

      如前所述,利用佇列,我們決定了資料被髮送的方式。無類佇列規定就是那樣,能夠接受資料和重新編排、延遲或丟棄資料包。這可以用作對於整個網絡卡的流量進行整形,而不細分各種情況。最廣泛應用的規定是pfifo_fast 佇列規定,因為它是預設配置。

 

1.2.1 pfifo_fast

      這個佇列的特點是先進先出(FIFO),也就是說沒有任何資料包被特殊對待。這個佇列有 3 個“頻道”。FIFO 規則應用於每一個頻道。並且如果在 0 頻道有資料包等待發送,1 頻道的包就不會被處理,1 頻道和 2 頻道之間的關係也是如此。核心遵照資料包的 TOS(Type Of Service)標記,把帶有“最小延遲”標記的包放進 0 頻道。

      不要把這個無類的簡單佇列規定與分類的 PRIO 相混淆。雖然它們的行為有些類似,但對於無類的 pfifo_fast 而言,不能使用 tc 命令向其中新增其它的佇列規定。

 

1.2.1 引數與使用

      pfifo_fast 佇列規定作為硬性的預設設定,不能對它進行配置。它預設是這樣配置的: 

priomap: 

      核心規定,根據資料包的優先權情況,對應相應的頻道。這個對應是根據資料包的 TOS 位元組進行的。TOS 看上去是這樣的: 

      TOS 欄位的 4 個 bit 是如下定義的: 

二進位制 十進位制 意義

-----------------------------------------

1000     8    最小延遲(md)

0100     4    最大throughput(mt)

0010     2    最大可靠性(mr)

0001     1    最小成本(mmc)

0000     0    正常服務

-----------------------------------------

      佇列的長度來自網絡卡的配置,可以用 ifconfig 和 ip 命令修改。如設定佇列長度為 10,執行:ifconfig eth0 txqueuelen 10。不能用 tc 命令來設定它。

 

1.2.2 令牌桶過濾器(TBF) 

      令牌桶過濾器(TBF)是一個簡單的佇列規定:只允許以不超過事先設定速率到來的資料包通過,但可能允許短暫突發流量超過設定值。

      TBF 的實現在於一個緩衝器(桶),不斷地被一些叫做“令牌”的虛擬資料以特定速率填充著。桶最重要的引數就是它的大小,也就是它能夠儲存令牌的數量。每個到來的令牌從資料佇列中收集一個數據包,然後從桶中被刪除。這個演算法關聯到兩個流——令牌流和資料流,於是我們得到3 種情景:

      (1)資料流以等於令牌流的速率到達 TBF。這種情況下,每個到來的資料包都能對應一個令牌,然後無延遲地通過佇列。

      (2)資料流以小於令牌流的速度到達 TBF。通過佇列的資料包只消耗了一部分令牌,剩下的令牌會在桶裡面積累下來,直到桶被裝滿。剩下的令牌可以在需要以高於令牌流速率傳送資料包的時候被消耗掉,這種情況下會發生突發傳輸。

      (3)資料流以大於令牌流的速率到達 TBF。這意味著桶裡的令牌很快就會被耗盡。導致 TBF 中斷一段時間,稱為“越限”。如果資料包持續到來,將會發生丟包。

      最後一種情況非常重要,因為它可以用來對資料通過過濾器的速率進行整形。令牌的積累可以導致越限的資料包進行短時間的突發傳輸而不必丟包,但是持續越限會導致傳輸延遲直至丟包。需要注意的是,實際的實現是針對資料的位元組數進行的,而不是針對資料包進行。

 

1.2.2.1 引數與使用

      TBF 提供了一些可調控的引數,第一個引數永遠可用:

limit/latency

      limit 確定最多有多少資料(位元組數)在佇列中等待可用令牌,也可以通過設定latency 引數來指定這個引數。latency 引數確定了一個包在TBF 中等待傳輸的最長等待時間。後者計算決定桶的大小、速率和峰值速率。

burst/buffer/maxburst

      桶的大小,以位元組計。這個引數指定了最多可以有多少個令牌能夠即刻被使用。通常情況下,管理的頻寬越大,需要的緩衝器就越大。如果緩衝區太小,就會導致到達的令牌沒有地方放(桶滿了),這會導致潛在的丟包。

mpu

      一個零長度的包並不是不耗費頻寬。比如乙太網,資料幀不會小於64 位元組。mpu(Minimum Packet Unit,最小分組單位)決定了令牌的最低消耗。

rate

      速度操縱桿。

      如果桶存在令牌而且執行沒有令牌,這相當於不限制速率。如果不希望這樣,可以調整以下引數:

peakrate

      峰值速率可以用來指定令牌以多快的速度被刪除。用書面語言來說,就是:釋放一個數據包,然後等待足夠的時間後再釋放下一個。通過計算等待時間來控制峰值速率。然而,由於UNIX 定時器的解析度是10 毫秒,如果平均包長為10kbit,峰值速率則被限制在1Mbps。

mtu/minburst 

      如果常規速率比較高,1Mbps 的峰值速率就沒有什麼價值。要實現更高的峰值速率,可以在一個時鐘週期內傳送多個數據包。最有效的辦法就是再建立一個令牌桶。這第二個令牌桶預設情況下為一個單個的資料包,並非一個真正的桶。要計算峰值速率,用mtu 乘以100 就行了。

 

1.2.2.2 配置範例

      這是一個非常簡單而實用的例子:

# sudo tc qdisc add dev enp0s5 root tbf rate 220kbit latency 50ms burst 1540 

      為什麼它很實用呢?如果你有一個佇列較長的網路裝置,比如DSL modem 或者cable modem 什麼的,並通過一個快速裝置(如乙太網卡)與之相連,你會發現上載資料絕對會破壞互動性。這是因為上載資料會充滿modem 的佇列,而這個佇列為了改善上載資料的吞吐量而設定的特別大。但這並不是你所需要的,你可能為了提高互動性而需要一個不太大的佇列。也就是說你希望在傳送資料的時候乾點別的事情。

      上面的一行命令並非直接影響了modem 中的佇列,而是通過控制Linux 中的佇列而放慢了傳送資料的速度。把220kbit 修改為你實際的上載速度再減去幾個百分點。如果你的modem 確實很快,就把“burst”值提高一點。

 

1.2.3 隨機公平佇列(SFQ)

      SFQ(Stochastic Fairness Queueing,隨機公平佇列)是公平佇列演算法家族中的一個簡單實現。它的精確性不如其它的方法,但是它在實現高度公平的同時,需要的計算量卻很少。

      SFQ 的關鍵詞是“會話”(或稱作“流”) ,主要針對一個TCP 會話或者UDP 流。流量被分成相當多數量的FIFO 佇列中,每個佇列對應一個會話。資料按照簡單輪轉的方式傳送, 每個會話都按順序得到傳送機會。這種方式非常公平,保證了每一個會話都不會被其它會話所淹沒。SFQ 之所以被稱為“隨機”,是因為它並不是真的為每一個會話建立一個佇列,而是使用一個雜湊演算法,把所有的會話對映到有限的幾個佇列中去。

      因為使用了雜湊,所以可能多個會話分配在同一個佇列裡,從而需要共享發包的機會,也就是共享頻寬。為了不讓這種效應太明顯,SFQ 會頻繁地改變雜湊演算法,以便把這種效應控制在幾秒鐘之內。

      有很重要的一點需要宣告:只有當你的出口網絡卡確實已經擠滿了的時候,SFQ 才會起作用。否則在你的Linux 機器中根本就不會有佇列,SFQ 也就不會起作用。特別地,在你使用DSL modem 或者cable modem 的乙太網卡上設定SFQ 是沒有意義的,無需進一步整形。

 

1.2.3.1 引數與使用

      SFQ 基本上不需要手工調整:

perturb 

      多少秒後重新配置一次雜湊演算法。如果取消設定,雜湊演算法將永遠不會重新配置(不建議這樣做)。10 秒應該是一個合適的值。

quantum 

      一個流至少要傳輸多少位元組後才切換到下一個佇列。預設設定為一個最大包的長度(MTU 的大小)。不要設定這個數值低於MTU。

 

1.2.3.2 配置範例

      如果有一塊網絡卡,它的鏈路速度與實際可用速率一致,如下配置可以提高公平性:

# sudo tc qdisc add dev enp0s5 root sfq perturb 10


# sudo tc -s -d qdisc ls
 dev enp0s5

qdisc sfq 8001: root refcnt 2 limit 127p quantum 1514b depth 127 flows 128/1024 divisor 1024 perturb 10sec 

 Sent 1863 bytes 22 pkt (dropped 0, overlimits 0 requeues 0) 

 backlog 0b 0p requeues 0

      “8001:”這個號碼是系統自動分配的一個控制代碼號,“limit”意思是這個佇列中可以有127 個數據包排隊等待。一共可以有1024 個雜湊目標可以用於速率審計, 而其中128 個可以同時啟用。每隔10 秒雜湊演算法更換一次。