弱网条件的模拟

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

Mac

在 MAC 系统中, Network Link Conditioner 是一个很好用的工具,您可以从 Apple Developers 页面下载,可通过 System Preferences 访问。它可以限制上行或下行链路的带宽、延迟和数据包丢失率。

安装说明参见 https://nshipster.com/network-link-conditioner/#installation

snapshot

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 国际许可协议进行许可。