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