##使用過程中查了很多資料,特整理如下,方便隨時查看##
##介紹##
報文分組從輸入網(wǎng)卡(入口)接收進(jìn)來,經(jīng)過路由的查找,以確定是發(fā)給本機(jī)的,還是需要轉(zhuǎn)發(fā)的。如果是發(fā)給本機(jī)的,就直接向上遞交給上層的協(xié)議,比如TCP,如果是轉(zhuǎn)發(fā)的,則會從輸出網(wǎng)卡(出口)發(fā)出。網(wǎng)絡(luò)流量的控制通常發(fā)生在輸出網(wǎng)卡處,Linux內(nèi)核中由TC(Traffic Control)實(shí)現(xiàn)。TC是利用隊列規(guī)定建立處理數(shù)據(jù)包的隊列,并定義隊列中的數(shù)據(jù)包被發(fā)送的方式,從而實(shí)現(xiàn)流量控制?;驹恚?br>

接收包從輸入接口(Input Interface)進(jìn)來后,經(jīng)過流量限制(Ingress Policing)丟棄不符合規(guī)定的數(shù)據(jù)包,由輸入多路分配器(Input De-Multiplexing)進(jìn)行判斷選擇。如果接收包的目的地是本主機(jī),那么將該包送給上層處理,否則需要進(jìn)行轉(zhuǎn)發(fā),將接收包交到轉(zhuǎn)發(fā)塊(Forwarding Block)處理。轉(zhuǎn)發(fā)塊同時也接收本主機(jī)上層(TCP、UDP等)產(chǎn)生的包。轉(zhuǎn)發(fā)塊通過查看路由表,決定所處理包的下一跳。然后,對包進(jìn)行排列以便將它們傳送到輸出接口(Output Interface)。一般我們只能限制網(wǎng)卡發(fā)送的數(shù)據(jù)包,不能限制網(wǎng)卡接收的數(shù)據(jù)包,所以我們可以通過改變發(fā)送次序來控制傳輸速率。
##流量控制對象:QDISC(排隊規(guī)則)? CLASS(類別)? FILTER(過濾器)##
流量控制的一個基本概念是隊列(Qdisc),每個網(wǎng)卡都與一個隊列(Qdisc)相聯(lián)系。每當(dāng)內(nèi)核需要將報文分組從網(wǎng)卡發(fā)送出去,都會首先將該報文分組添加到該網(wǎng)卡所配置的隊列中,由該隊列決定報文分組的發(fā)送順序。因此可以說,所有的流量控制都發(fā)生在隊列中。有些隊列的功能是非常簡單的,它們對報文分組實(shí)行先來先走的策略。有些隊列則功能復(fù)雜,會將不同的報文分組進(jìn)行排隊、分類,并根據(jù)不同的原則,以不同的順序發(fā)送隊列中的報文分組。為實(shí)現(xiàn)這樣的功能,這些復(fù)雜的隊列需要使用不同的過濾器(Filter)來把報文分組分成不同的類別(Class)。這里把這些復(fù)雜的隊列稱為可分類(Classiful)的隊列。通常,要實(shí)現(xiàn)功能強(qiáng)大的流量控制,可分類的隊列是必不可少的。因此,類別(Class)和過濾器(Filter)也是流量控制的另外兩個重要的基本概念。類別(Class)和過濾器(Filter)是隊列的內(nèi)部結(jié)構(gòu),并且可分類的隊列可以包含多個類別,同時,一個類別又可以進(jìn)一步包含有子隊列,或者子類別。所有進(jìn)入該類別的報文分組可以依據(jù)不同的原則放入不同的子隊列 或子類別中,以此類推。而過濾器(Filter)是隊列用來對數(shù)據(jù)報文進(jìn)行分類的工具,它決定一個數(shù)據(jù)報文將被分配到哪個類別中。
在Linux中,可以配置很多類型的隊列,比如CBQ、HTB等,其中CBQ 比較復(fù)雜,不容易理解。HTB(Hierarchical Token Bucket)是一個可分類的隊列, 與其他復(fù)雜的隊列類型相比,HTB具有功能強(qiáng)大、配置簡單及容易上手等優(yōu)點(diǎn)。
在TC中,使用"major:minor"這樣的句柄來標(biāo)識隊列和類別,其中major和minor都是數(shù)字。對于隊列來說,minor總是為0,即"major:0"這樣的形式,也可以簡寫為"major: "。比如,隊列1:0可以簡寫為1:。需要注意的是,major在一個網(wǎng)卡的所有隊列中必須是惟一的。對于類別來說,其major必須和它的父類別或父隊列的major相同,而minor在一個隊列內(nèi)部則必須是惟一的(因為類別肯定是包含在某個隊列中的)。舉個例子,如果隊列2:包含兩個類別,則這兩個類別的句柄必須是2:x這樣的形式,并且它們的x不能相同,比如2:1和2:2。
##使用基本步驟##
Linux流量控制主要分為建立隊列、建立分類和建立過濾器三個方面。
1) 針對網(wǎng)絡(luò)物理設(shè)備(如以太網(wǎng)卡eth0)綁定一個隊列qdisc;
2) 在該隊列上建立分類class;
3) 為每一分類建立一個基于路由的過濾器filter;
4) 最后與過濾器相配合,建立特定的路由表。
##相關(guān)單位##
tc命令所有的參數(shù)都可以使用浮點(diǎn)數(shù),可能會涉及到以下計數(shù)單位。
帶寬或流速單位:
kbps ?千字節(jié)/s ? ? ? ? ? ? ? mbps 兆字節(jié)/s ? ? (bps或者一個無單位數(shù)字,表示字節(jié)數(shù)/s)
kbit ?KBits/s ? ? ? ? ? ? ? ? ? mbit ?MBits/s
數(shù)據(jù)的數(shù)量單位
kb或k ?千字節(jié) ? ? ? ? ? ? ? ? mb或m 兆字節(jié) ?(b或者一個無單位數(shù)字,字節(jié))
kbit ? ? 千bit ? ? ? ? ? ? ? ? ? ?mbit 兆bit ??
時間的計量單位
s, sec或secs ? 秒 ? ? ? ? ? ?ms, msec或mescs ?毫秒
us, use, usecs或一個無單位數(shù)字 ?微s
##舉例##
『創(chuàng)建根隊列--》創(chuàng)建類別class--》為類別創(chuàng)建對應(yīng)過濾器,對應(yīng)網(wǎng)卡接收的數(shù)據(jù)包會一層一層下發(fā)到過濾器進(jìn)行過濾或相關(guān)處理』
1)為網(wǎng)卡創(chuàng)建根隊列或htb隊列或cbq隊列
有關(guān)隊列的TC命令的一般形式為:
# tc?qdisc?[add?|?change?|?replace?|?link]?dev?DEV?[parent?qdisk-id?|root]?[handle?qdisc-id]?qdisc?[qdisc?specific?parameters]
==》sar -n DEV 1 2 命令查看當(dāng)前機(jī)器所使用的以太網(wǎng)卡是哪個
==》tc qdisc add dev eth1 root handle 1: prio
? ? ? ?為網(wǎng)卡eth1建議一個隊列,名字為root,句柄為1
?==》tc qdisc add dev eth1 root handle 1:htb default 11
? ? ? ? 為網(wǎng)卡eth1添加root根隊列,"handle 1:"表示隊列的句柄為1: ,"htb"表示要添加的隊列為HTB隊列,命令最后的"default 11"是htb特有的隊列參數(shù),意思是所有未分類的流量都將分配給類別1:11。
==》tc qdisc add dev xgbe0 root handle 1:0 cbq bandwidth 100Mbit avpkt 1000 cell 8;為網(wǎng)卡xbge0創(chuàng)建一個cbq隊列,限制網(wǎng)卡總帶寬為100Mbit/s,avpkt表示平均包大小,單位字節(jié),avpkt 1000表示平均包大小為1000B,cell表示一個數(shù)據(jù)包被發(fā)送出去的平均時間,通常設(shè)置為8,必須是2的整數(shù)次冪
2)為根隊列創(chuàng)建相應(yīng)的類別,對于句柄編號一般根隊列為一位數(shù),子類別為兩位數(shù)
有關(guān)類別的TC 命令的一般形式為:
# tc?class?[add?|?change?|?replace]?dev?DEV?parent?qdisc-id?[classid?class-id]?qdisc?[qdisc?specific?parameters]
可以利用下面這三個命令為根隊列1創(chuàng)建三個類別,分別是1:11、1:12和1:13,它們分別占用40、40和20mbit的帶寬。
? tc?class?add?dev?eth1 parent?1:?classid?1:11 htb?rate?40mbit?ceil?40mbit
? tc?class?add?dev?eth1 parent?1:?classid?1:12?htb?rate?40mbit?ceil?40mbit
? tc?class?add?dev?eth1 parent?1:?cllassid?1:13?htb?rate?20mbit?ceil?20mbit
命令中,"parent?1:"表示類別的父親為根隊列1:?。"classid1:11"表示創(chuàng)建一個標(biāo)識為1:11的類別,"rate?40mbit"表示系統(tǒng)將為該類別確保帶寬40mbit,"ceil?40mbit",表示該類別的最高可占用帶寬為40mbit。
3)為各個類別設(shè)置過濾器
有關(guān)過濾器的TC?命令的一般形式為:
# tc?filter?[add?|?change?|?replace]?dev?DEV?[parent?qdisc-id | root] protocol?protocol?prio?priority?filtertype?[filtertype?specific?parameters]?flowid?flow-id
比如,需要將WWW、E-mail、Telnet三種流量分配到三個類別,即上述1:11、1:12和1:13,因此,需要創(chuàng)建三個過濾器,如下面的三個命令:
# tc filter add dev eth0? parent 1:0 protocol ip prio 1 u32 match ip dport 80 0xffff flowid 1:11?
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip dport 25 0xffff flowid 1:12?
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip dport 23 oxffff flowid 1:13
這里,"protocol?ip"表示該過濾器應(yīng)該檢查報文分組的協(xié)議字段。"prio?1"表示它們對報文處理的優(yōu)先級是相同的。對于不同優(yōu)先級的過濾器,系統(tǒng)將按照從小到大的優(yōu)先級順序來執(zhí)行過濾器,對于相同的優(yōu)先級,系統(tǒng)將按照命令的先后順序執(zhí)行。這幾個過濾器還用到了u32選擇器(命令中u32后面的部分)來匹配不同的數(shù)據(jù)流。以第一個命令為例,判斷的是dport字段,如果該字段與0xffff進(jìn)行與操作的結(jié)果是80,則"flowid?1:11"表示將把該數(shù)據(jù)流分配給類別1:11。更加詳細(xì)的有關(guān)TC的用法可以參考TC的手冊頁。
4)查看當(dāng)前網(wǎng)卡上配過的流量控制規(guī)則
? ? #?tc[-s | -d ] qdisc show [ dev DEV ] ? ? ? ? ? ? ? tc -s qdisc show dev eth1
? ? # tc[-s | -d ] class show dev DEV ?
? ? # tc?filter show dev DEV
? ? # tc -s -d qdisc ls
5)刪除已配置的規(guī)則
? ? # tc qdisc del dev eth1 root
##實(shí)際項目使用場景篇##
1)配合netem模塊對特定ip或port模擬超時(netem 是 Linux2.6?及以上內(nèi)核版本提供的一個網(wǎng)絡(luò)模擬功能模塊。該功能模塊可以用來在性能良好的局域網(wǎng)中,模擬出復(fù)雜的互聯(lián)網(wǎng)傳輸性能,諸如低帶寬、傳輸延遲、丟包等等情況。tc?可以用來控制?netem?的工作模式,也就是說,如果想使用?netem?,需要至少兩個條件,一個是內(nèi)核中的?netem?功能被包含,另一個是要有?tc?。)##親測有效##
# tc qdisc add dev xgbe0 root netem delay 100ms ?##這個是對整個網(wǎng)卡xgbe0的數(shù)據(jù)包延遲100ms發(fā)送。如果要對發(fā)送到特定ip或從特定端口發(fā)送的數(shù)據(jù)包延遲100ms,再加下面的命令設(shè)置class和filter。
# tc class add dev xgbe0 parent 1: classid 1:11
# tc filter add dev xgbe0 parent 1:0 protocol ip? prio 1 u32 match ip dst 10.10.10.91 flowid 1:1 ##到特定ip
# tc filter add dev xgbe0 parent 1:0 protocol ip? prio 1 u32 match ip dport 9988 flowid 1:1 ##從特定port發(fā)出的
2)模擬丟包
# tc? qdisc? add? dev? eth0? root? netem? loss? 1%?
該命令將eth0網(wǎng)卡的傳輸設(shè)置為隨機(jī)丟掉1%的數(shù)據(jù)包,也是對整個網(wǎng)卡有效,如果也是要特定ip或port試著按上述進(jìn)行配置class和filter
也可以設(shè)置丟包的成功率:
# tc ?qdisc? add? dev ?eth0 ?root? netem??loss??1%? 30%
該命令將eth0網(wǎng)卡的傳輸設(shè)置為隨機(jī)丟掉1%的數(shù)據(jù)包,成功率為30%。
3)模擬包損壞 ##沒試過##
# tc ?qdisc? add? dev ?eth0 ?root? netem??corrupt??0.2%
該命令將eth0網(wǎng)卡的傳輸設(shè)置為隨機(jī)產(chǎn)生0.2%的損壞的數(shù)據(jù)包 。 (內(nèi)核版本需在2.6.16以上)
4)模擬包亂序
# tc? qdisc? change? dev? eth0? root ?netem? delay? 10ms?? reorder? 25%? 50%
該命令將eth0網(wǎng)卡的傳輸設(shè)置為:有25%的數(shù)據(jù)包(50%相關(guān))會被立即發(fā)送,其他的延遲10ms。
新版本中,如下命令也會在一定程度上打亂發(fā)包的次序:
# tc ?qdisc? add? dev ?eth0 ?root? netem ?delay ?100ms? 10ms
5)模擬包重復(fù)
# tc ?qdisc? add? dev ?eth0 ?root? netem??duplicate?1%
該命令將eth0網(wǎng)卡的傳輸設(shè)置為隨機(jī)產(chǎn)生1%的重復(fù)數(shù)據(jù)包 。
6)模擬網(wǎng)絡(luò)抖動
可以寫個腳本進(jìn)行l(wèi)oop:先tc命令設(shè)置好延時——》隔隨機(jī)時間后,將tc規(guī)則刪除-->再隔隨機(jī)時間后,tc命令加入延時如此往復(fù)
腳本運(yùn)行期間就可以看服務(wù)在網(wǎng)絡(luò)抖動時整體時延或資源消耗是否符合預(yù)期或是否出現(xiàn)服務(wù)異常warning日志等。
##使用之中遇到的幾個問題##
1)tc執(zhí)行必須root賬號;只針對出口流量有效
2)如果機(jī)器是64位,執(zhí)行tc之前先創(chuàng)建一個軟鏈,不然在用netem庫時會出現(xiàn)錯誤『[Netem] Unknown qdisc "netem"』:ln -s /usr/lib64/tc/ /usr/lib/tc
參考:
1.?linux下流量控制工具TC詳細(xì)說明及應(yīng)用實(shí)例? ?寫得很贊的一篇博文