弱网条件的模拟
Posted on Thu 16 February 2023 in Journal
Abstract | 弱网条件的模拟 |
---|---|
Authors | Walter Fan |
Category | learning note |
Status | v1.0 |
Updated | 2023-02-16 |
License | CC-BY-NC-ND 4.0 |
概述
在网络会议,实时通信,网络直播中,由于网络不稳定造成的卡顿,花屏,模糊屡见不鲜,这样不稳定的网络我们称为弱网。 需要采取诸如拥塞控制,重传,纠错等手段进行优化。
实际开发中,我们碰不到客户所遇到的各种网络问题,必须通过一些工具和手段来模拟弱网条件,从而有针对性的进行调优。
验证
在开始模拟弱网,进行网络限制之前,有必要用 iperf3 来验证我们实施的网络限制是否生效
- 在服务器端启动 iperf3 server
iperf3 -s -i 3s -V -f m -p 12000
- -s, --server: 以服务器模式启动
- -f m: 显示带宽的单位为 m
- -p 12000: 指定侦听的端口
-
-V --verbose: 输出更多的细节
-
在客户端启动 iperf3 client,这里我们用 udp 方式来传输数据, 这样可以观察到丢包的数据
iperf3 -c 10.224.84.89 -p 12000 -w 1m -b 10m -t 300s -i 3s -u -l 1000
- -c: 作为客户端连接服务器
- -w 5m: 设置 socket 的缓存大小
- -b 20m: 设置发送数据的比特率(带宽)
- -t 300s: 持续时间为 300秒
- -i 3s: 每隔3秒显示报告
- -u: 用 UDP 传输
- -l 1000k: 设置读写的缓存大小,TCP 默认是 128 KB,UDP 默认是 8 KB
具体参见 https://iperf.fr/iperf-doc.php#3doc
在服务器端的显示结果如下, 我们可以观察到传输过的数据量,带宽,抖动以及丢包率
Linux ubuntu 4.15.0-180-generic #189-Ubuntu SMP Wed May 18 14:13:57 UTC 2022 x86_64
-----------------------------------------------------------
Server listening on 12000
-----------------------------------------------------------
Time: Thu, 16 Feb 2023 06:54:46 GMT
Accepted connection from 10.224.85.58, port 37666
Cookie: ubuntu.1676530537.883608.68ec4248520
[ 5] local 10.224.84.89 port 12000 connected to 10.224.85.58 port 55932
Starting Test: protocol: UDP, 1 streams, 1000 byte blocks, omitting 0 seconds, 600 second test
[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams
[ 5] 0.00-3.00 sec 6.92 MBytes 19.4 Mbits/sec 0.005 ms 0/7257 (0%)
[ 5] 3.00-6.00 sec 7.15 MBytes 20.0 Mbits/sec 0.014 ms 0/7500 (0%)
[ 5] 6.00-9.00 sec 7.15 MBytes 20.0 Mbits/sec 0.013 ms 0/7501 (0%)
[ 5] 9.00-12.00 sec 7.15 MBytes 20.0 Mbits/sec 0.016 ms 0/7499 (0%)
[ 5] 12.00-15.00 sec 7.15 MBytes 20.0 Mbits/sec 0.018 ms 0/7501 (0%)
[ 5] 15.00-18.00 sec 7.17 MBytes 20.0 Mbits/sec 0.047 ms 0/7514 (0%)
Windows
在 windows 系统中,我们可以使用 clumsy 来模拟弱网条件,更改网络状况, 引入延迟(lag),丢包(drop),乱序等
- 关于Clumsy: https://jagt.github.io/clumsy/index.html
- 下载 Clumsy: https://jagt.github.io/clumsy/download.html
- Clumsy 手册: https://jagt.github.io/clumsy/manual.html
Mac
在 MAC 系统中, Network Link Conditioner 是一个很好用的工具,您可以从 Apple Developers 页面下载,可通过 System Preferences 访问。它可以限制上行或下行链路的带宽、延迟和数据包丢失率。
安装说明参见 https://nshipster.com/network-link-conditioner/#installation
Linux
在 Linux系统中, tc(Traffic Control)是最常用的网络控制工具,它既强大又复杂, 我们常用 netem 模块和 tc 命令常用来控制网络流量,模拟网络中常见的各种问题。
tc 用于在 Linux 内核中配置流量控制。流量控制包括以下内容:
- SHAPING 整形
当流量被整形时,它的传输速率是受控的。 整形可能不仅仅是降低可用带宽 - 它还用于平滑流量突发以获得更好的网络行为。 整形发生在出口处。
- SCHEDULING 调度
通过调度数据包的传输,可以提高需要它的流量的交互性,同时仍然保证批量传输的带宽。 重新排序也称为优先级,仅发生在出口处。
- POLICING 监管
整形处理的是流量的传输,而监管则与到达的流量有关。 因此,监管发生在入口处。
- DROPPING 丢弃
超过设定带宽的流量也可以立即被丢弃,丢弃可发生在入口和出口处
流量的处理由三种对象控制:
1) qdiscs : 简单来说,它可以理解为一个队列,以及入队出队的调度器,默认的调度器是 FIFO, 包括可分类和不可分类的 qdisc 2) classes: 类存在于 classful qdisc 中,它可以包含多个子类或单个子 qdisc, 可用于极其复杂的场景 3) filters: 过滤器 filter 是Linux流量控制系统中最复杂的组件,它提供了一种方便的机制,可以将流量控制的几个关键元素粘合在一起
关于 TC 的内容,三天三夜也讲不完,需要另外详细阐述,略过不表。
通过一些例子来看看怎么使用 TC
Loss 丢包
- 增加 loss
sudo tc qdisc add dev eth0 root netem loss 20%
- 更改 loss
sudo tc qdisc change dev eth0 root netem loss 30%
- 删除 loss
sudo tc qdisc del dev eth0 root netem loss 30%
Jitter 抖动
- 增加jitter 到 50ms
sudo tc qdisc add dev eth0 root netem rate 1000mbit delay 0ms 50ms 0%
- 更改jitter 到 100ms
sudo tc qdisc change dev eth0 root netem rate 1000mbit delay 0ms 100ms 0%
- 删除 jitter
sudo tc qdisc del dev eth0 root netem rate 1000mbit delay 0ms 100ms 0%
速率控制 Rate Control (带宽限制)
- 限制 rate 到 1mbps
sudo tc qdisc add dev eth0 root netem rate 1mbit
叠加多种限制条件 Impairments
- 使用 handle 1: 增加 rate control at root qdisc:
sudo tc qdisc add dev eth0 root handle 1: netem rate 1mbit
- 串接 500ms jitter 到 rate control qdisc handle 1:
sudo tc qdisc add dev eth0 parent 1:1 handle 10: netem rate 1000mbit delay 0ms 500ms
- 串接 5% 的丢包到 jitter qdisc
sudo tc qdisc add dev eth0 parent 10:1 netem loss 5%
inbound traffic 输入流量的限制
刚才说的都是输出流量的限制,tc 很容量来控制发送的速率,延迟和丢包,但是对于输入流量,需要引入一个虚拟网卡, 数据流向是 “client --> ifb --> nic --> server” , 其中 ifb 是虚拟网卡,nic 是真实网卡,我们用 tc控制 ifb 到 nic 之间的发送, 来达到网络限制的目的。
- 先用
modprobe ifb
命令来启动相关的内核模块, 以创建虚拟接口,代表输入的流量
modprobe ifb
modprobe ifb
默认创建两个 ifb 设备 ifb0 和 ifb1. 它位一开始的状态是 "down", 需要用以下命令启用
ip link set dev ifb0 up
- 如果上述命令失败,需要输入以下命令后重试上一步
ip link add ifb0 type ifb
- 在网络接口上启用 ingress 并使用 filter 将所有输入的流量重定向到虚拟的 ifb 设备
tc qdisc add dev eth0 ingress
tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0
- 在虚拟 ifb 设备上应用网络限制,就像在普通的网络设备上一样
tc qdisc add dev ifb0 root netem delay 750ms
- 显示当前的网络设置
sudo tc qdisc show
- 删除所有的网络限制
sudo tc qdisc del dev eth0 root
如果嫌命令太烦琐,可以用如下的脚本来做网络限制 netimpair.py (这个版本有点老,我做了一些改动,回头 fork 一个 git repo 提交上去)
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。