參考:https://juejin.cn/post/6844903673760350221
在某些情況下,我們需要模擬網(wǎng)絡(luò)很差的狀態(tài)來測試軟件能夠正常工作辞居,比如網(wǎng)絡(luò)延遲楷怒、丟包、亂序瓦灶、重復(fù)等鸠删。Linux 系統(tǒng)下強(qiáng)大的流量控制工具 TC 能很輕松地完成這個需求,TC 命令行工具是 IProute2 軟件包中的軟件贼陶,可以根據(jù)系統(tǒng)版本自行安裝刃泡。
這篇文章介紹的功能主要是通過 Netem 這個內(nèi)核模塊來實現(xiàn)的。Netem 是 Network Emulator 的縮寫每界,關(guān)于更多功能以及參數(shù)的詳細(xì)解釋可以參閱 TC-Netem 的 Man Page捅僵。
Netem 與 TC 簡要說明
Netem 是 Linux 2.6 及以上內(nèi)核版本提供的一個網(wǎng)絡(luò)模擬功能模塊。該功能模塊可以用來在性能良好的局域網(wǎng)中眨层,模擬出復(fù)雜的互聯(lián)網(wǎng)傳輸性能庙楚。例如:低帶寬、傳輸延遲趴樱、丟包等等情況馒闷。使用 Linux 2.6 (或以上) 版本內(nèi)核的很多 Linux 發(fā)行版都默認(rèn)開啟了該內(nèi)核模塊,比如:Fedora叁征、Ubuntu纳账、Redhat、OpenSuse捺疼、CentOS疏虫、Debian 等等。
TC 是 Linux 系統(tǒng)中的一個用戶態(tài)工具,全名為 Traffic Control (流量控制)卧秘。TC 可以用來控制 Netem 模塊的工作模式呢袱,也就是說如果想使用 Netem 需要至少兩個條件,一是內(nèi)核中的 Netem 模塊被啟用翅敌,另一個是要有對應(yīng)的用戶態(tài)工具 TC 羞福。
TC 能做的事情很多,除了本文介紹的還有帶寬控制蚯涮、優(yōu)先級控制等等治专。這些功能是通過類似 Netem 的內(nèi)核模塊實現(xiàn)的。
網(wǎng)絡(luò)狀況模擬
網(wǎng)絡(luò)狀況欠佳從用戶角度來說就是下載東西慢(網(wǎng)頁一直加載遭顶、視頻卡頓张峰、圖片加載很久等),從網(wǎng)絡(luò)報文角度來看卻有很多情況:比如:延遲(某個機(jī)器發(fā)送報文很慢)液肌、丟包(發(fā)送的報文在網(wǎng)絡(luò)中丟失需要一直重傳)挟炬、亂序(報文順序錯亂鸥滨,需要大量計算時間來重新排序)嗦哆、重復(fù)(報文有大量重復(fù),導(dǎo)致網(wǎng)絡(luò)擁堵)婿滓、錯誤(接收到的報文有誤只能丟棄重傳)等老速。
對于這些情況,都可以用 Netem 來模擬凸主。需要注意的是橘券,Netem 是直接作用于指定網(wǎng)卡上的,也就是說所有從該網(wǎng)卡發(fā)送出去的包都會收到配置參數(shù)的影響卿吐,所以最好搭建臨時的虛擬機(jī)進(jìn)行測試旁舰。
在下面的例子中 add 表示為指定網(wǎng)卡添加 Netem 配置,change 表示修改已經(jīng)存在的 Netem 配置到新的值嗡官,replace 表示替換已經(jīng)存在的 Netem 配置的值箭窜。如果要刪除網(wǎng)卡上的 Netem 配置可以使用 del。
$ tc qdisc del dev enp0s5 root復(fù)制代碼
1. 模擬延遲傳輸
最簡單的例子是所有的報文延遲 100ms 發(fā)送:
$ tc qdisc add dev enp0s5 root netem delay 100ms復(fù)制代碼
如果你想在一個局域網(wǎng)里模擬遠(yuǎn)距離傳輸?shù)难舆t可以用這個方法衍腥,比如實際用戶訪問網(wǎng)站延遲為 101 ms磺樱,而你測試環(huán)境網(wǎng)絡(luò)交互只需要 1ms,那么只要添加 100ms 額外延遲就行婆咸。
$ tc qdisc replace dev enp0s5 root netem delay 100ms
$ ping dev-node-02
PING dev-node-02 (192.168.100.212) 56(84) bytes of data.
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=1 ttl=64 time=102 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=2 ttl=64 time=100 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=3 ttl=64 time=100 ms
^C
--- dev-node-02 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 100.293/101.053/102.795/1.061 ms復(fù)制代碼
如果在網(wǎng)絡(luò)中看到非常穩(wěn)定的時延,很可能是某個地方加了定時器,因為網(wǎng)絡(luò)線路很復(fù)雜第岖,傳輸過程一定會有變化毙死。因此實際情況網(wǎng)絡(luò)延遲一定會有變化的,Netem 也考慮到這一點(diǎn),提供了額外的參數(shù)來控制延遲的時間分布憨闰。完整的參數(shù)列表為:
DELAY := delay TIME [ JITTER [ CORRELATION ]]]
[ distribution { uniform | normal | pareto | paretonormal } ]復(fù)制代碼
除了延遲時間 TIME 之外询兴,還有三個可選參數(shù):
JITTER:抖動,增加一個隨機(jī)時間長度起趾,讓延遲時間出現(xiàn)在某個范圍诗舰。
CORRELATION:相關(guān),下一個報文延遲時間和上一個報文的相關(guān)系數(shù)训裆。
distribution:分布眶根,延遲的分布模式”吡穑可以選擇的值有 uniform属百、 normal、pareto 和 paretonormal变姨。
先說說 JITTER族扰,如果設(shè)置為 20ms,那么報文延遲的時間在 100ms ± 20ms 之間定欧,具體值隨機(jī)選擇:
$ tc qdisc replace dev enp0s5 root netem delay 100ms 20ms
tc qdisc replace dev enp0s5 root netem delay 100ms 20ms 50%
tc qdisc replace dev enp0s5 root netem delay 100ms 20ms distribution normal
tc qdisc change dev enp0s5 root netem loss 50%
tc qdisc change dev enp0s5 root netem loss 0.3% 25%復(fù)制代碼
這個命令表示,丟包率是 0.3%开睡,并且當(dāng)前報文丟棄的可能性和前一個報文有 25% 相關(guān)因苹。默認(rèn)的丟包模型為隨機(jī),loss 也支持 state(4-state Markov 模型) 和 gemodel(Gilbert-Elliot 丟包模型) 兩種模型的丟包篇恒,因為兩者都相對復(fù)雜扶檐,這里就不再詳細(xì)介紹了。
需要注意的是胁艰,丟包信息會發(fā)送到上層協(xié)議款筑。如果是 TCP 協(xié)議,那么 TCP 會進(jìn)行重傳腾么,所以對應(yīng)用來說看不到丟包奈梳。這時候要模擬丟包,需要把 loss 配置到網(wǎng)橋或者路由設(shè)備上哮翘。
3. 模擬包重復(fù)
報文重復(fù)和丟包的參數(shù)類似颈嚼,就是重復(fù)率和相關(guān)性兩個參數(shù)毛秘,比如隨機(jī)產(chǎn)生 50% 重復(fù)的包:
ping dev-node-02
PING dev-node-02 (192.168.100.212) 56(84) bytes of data.
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=2 ttl=64 time=0.284 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=3 ttl=64 time=0.420 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=3 ttl=64 time=0.447 ms (DUP!)
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=4 ttl=64 time=0.437 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=4 ttl=64 time=0.515 ms (DUP!)
......復(fù)制代碼
4. 模擬包損壞
報文損壞和報文重復(fù)的參數(shù)也類似饭寺,比如隨機(jī)產(chǎn)生 2% 損壞的報文(在報文的隨機(jī)位置造成一個比特的錯誤)。
ping dev-node-02
......
PING dev-node-02 (192.168.100.212) 56(84) bytes of data.
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=3 ttl=64 time=0.362 ms
Warning: time of day goes back (-4611686018427387574us), taking countermeasures.
Warning: time of day goes back (-4611686018427387454us), taking countermeasures.
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=4 ttl=64 time=0.000 ms
wrong data byte #53 should be 0x35 but was 0xb5
16 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
48 30 31 32 33 34 b5 36 37
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=5 ttl=64 time=0.476 ms
......復(fù)制代碼
5. 模擬包亂序
網(wǎng)絡(luò)傳輸并不能保證順序叫挟,傳輸層 TCP 會對報文進(jìn)行重組保證順序艰匙,所以報文亂序?qū)?yīng)用的影響比上面的幾種問題要小。
報文亂序和前面的參數(shù)不太一樣抹恳,因為上面的報文問題都是獨(dú)立的员凝。針對單個報文做操作就行,而亂序則牽涉到多個報文的重組奋献。模擬報亂序一定會用到延遲(因為模擬亂序的本質(zhì)就是把一些包延遲發(fā)送)健霹,Netem 有兩種方法可以做。
第一種是固定的每隔一定數(shù)量的報文就亂序一次瓶蚂。
# 每 5 個報文(第 5糖埋、10、15…報文)會正常發(fā)送窃这,其他的報文延遲 100ms瞳别。
ping -i 0.05 dev-node-02
PING dev-node-02 (192.168.100.212) 56(84) bytes of data.
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=9 ttl=64 time=2.55 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=8 ttl=64 time=100 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=10 ttl=64 time=100 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=11 ttl=64 time=100 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=13 ttl=64 time=0.245 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=12 ttl=64 time=102 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=14 ttl=64 time=1.00 ms
......復(fù)制代碼
要想看到 ping 報文的亂序,我們要保證發(fā)送報文的間隔小于報文的延遲時間 100ms,這里用 -i 0.05 把發(fā)送間隔設(shè)置為 50ms祟敛。
第二種方法的亂序是相對隨機(jī)的疤坝,使用概率來選擇亂序的報文。
ping -i 0.05 dev-node-02
PING dev-node-02 (192.168.100.212) 56(84) bytes of data.
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=4 ttl=64 time=0.423 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=7 ttl=64 time=0.250 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=2 ttl=64 time=301 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=3 ttl=64 time=301 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=9 ttl=64 time=0.238 ms
64 bytes from dev-node-02 (192.168.100.212): icmp_seq=5 ttl=64 time=301 ms
......復(fù)制代碼
50% 的報文會正常發(fā)送馆铁,其他報文(1-50%)延遲 300ms 發(fā)送跑揉,這里選擇的延遲很大是為了能夠明顯看出來亂序的結(jié)果。
6. 其它技巧
查看已經(jīng)配置的網(wǎng)絡(luò)條件
該命令將查看并顯示 enp0s5 網(wǎng)卡的相關(guān)傳輸配置埠巨。
$ tc qdisc show dev enp0s5復(fù)制代碼
推薦兩個工具
Netem 在 TC 中算是比較簡單的模塊畔裕,如果要實現(xiàn)流量控制或者精細(xì)化的過濾需要更復(fù)雜的配置。這里推薦兩個小工具乖订,它們共同的特點(diǎn)是用法簡單扮饶,能滿足特定的需求,而不用自己去倒騰 TC 的命令乍构。
1. Wondershaper
項目地址:https://github.com/magnific0/wondershaper
Netem 只能模擬網(wǎng)絡(luò)狀況甜无,不能控制帶寬,Wondershaper 則能完美解決這個問題哥遮。Wondershaper 實際上是一個 SHELL 腳本岂丘,它使用 TC 來進(jìn)行流量速率調(diào)整,使用 QoS 來處理特定的網(wǎng)絡(luò)接口眠饮。外發(fā)流量通過放在不同優(yōu)先級的隊列中奥帘,來達(dá)到限制傳出流量速率的目的;而傳入流量通過丟包的方式來達(dá)到速率限制的目的仪召。
安裝 Wondershaper
在 Ubuntu / Debian 下安裝 Wondershaper
$ sudo apt-get install wondershaper復(fù)制代碼
在 Fdora / CentOS / RHEL 中安裝 Wondershaper
# 需啟用 EPEL 倉庫
sudo wondershaper enp0s5 200 150復(fù)制代碼
如果你要將速率限制消除召娜,可以通過運(yùn)行下面的命令來達(dá)到目的运褪。
comcast --device=enp0s5 --latency=250
--target-bw=1000
--default-bw=1000000
--packet-loss=10%
--target-addr=8.8.8.8,10.0.0.0/24
--target-proto=tcp,udp,icmp
--target-port=80,22,1000:2000復(fù)制代碼
--device 說明要控制的網(wǎng)卡為 enp0s5雅倒。
--latency 指定 250ms 的延遲璃诀。
--target-bw指定目標(biāo)帶寬。
--default-bw 指定默認(rèn)帶寬屯断。
--packet-loss 指定丟包率文虏。
--target-addr侣诺、 --target-proto、--target-port 參數(shù)指定在滿足這些條件的報文上實施上面的配置氧秘。
總結(jié)
可以看出年鸳,TC 的 Netem 模塊主要用來模擬各種網(wǎng)絡(luò)的異常狀況,本身并沒有提供寬帶限制的功能丸相,而且一旦在網(wǎng)卡上配置了 Netem搔确,該網(wǎng)卡上所有的報文都會受影響,如果想精細(xì)地控制部分報文灭忠,需要用到 TC 的 filter 功能膳算。
參考資料
http://www.google.comhttp://t.cn/RsUAV3yhttp://t.cn/RsUwmQXhttp://t.cn/RsUVqk0