图片来源 NASA
0x00 前言
网络存在了很多不确定性,这是我们无法回避的问题。所以在 IA (Internet Application) 设计阶段首先需要考虑其在不确定性网络中的可用性和容错性,并且需要将网络的不确定性进行量化作为验证其性能的必要方法。本文描述了几种对体验影响较大的网络性能指标并讨论了对这些性能指标测试和模拟的方法。
0x01 网络性能指标
通常我们可以感知到的网络参数都是从供应商 (Providor) 的角度来讲的,例如 带宽 (Bandwith)、速率 (Bitrate) 等。作为网络的使用者,可能需要从体验的角度去描述网络性能,下面总结了几个在一定网络负载情况下对体验影响较大的网络性能指标:
- 延迟 (Latency)
- 丢包率 (Packet Lose Rate)
- 抖动 (Jitter)
① 延迟 (Latency)
延迟是数据包通过网络从发送方传输到接收方所需的时间量,通常通过数据的往返时间(Round-Trip Time)来测量。简单地说,它是发送用户请求到收到服务响应之间的时间。这个性能指标比较重要,因为它基本上会影响到所有类型网络应用程序的用户体验。 导致网络延迟的原因主要有以下几种:
- 距离 —— 信号以有限的速度(光速)通过传输介质,如果通信的两端分别位于上海和洛杉矶,按照直线距离 12,500 公里计算,最快的光信号单程需要 42ms,如果按照 rtt 计算需要 84ms 。
- 路由 —— 网络流量通常需要经过几次路由到达目的地,每一次路由都无法避免延迟;
- 流量 —— 如果网络发生拥塞,后面的数据将会进入队列等待,于是产生了延迟;
- 服务响应 —— 与业务相关的服务端响应时间也是 RTT 增加的主要因素;
② 丢包率 (Packet Lose Rate)
丢包对于体验的影响比较直观,尽管一些传输层协议支持重传机制,但是重传将会导致拥塞控制的启用和应用层延迟的增大。产生丢包的原因主要有:
- 网络拥塞 —— 当网络吞吐量达到上限时,等待队列中的数据会被超时丢弃;
- 传输故障 —— 信道噪声、信号衰减导致的误码率也是丢包的主要因素;
③ 抖动 (Jitter)
在网络环境中,抖动反应了传输单独数据包之间延迟的变化情况。由于数据包被均匀发送,但它们可能会由于抖动而以不同的延迟到达。当抖动值较高时,它们甚至可能以错误的顺序到达或者同时到达,这可能会导致数据包丢失和延迟增加。产生网络抖动的原因主要有:
- 网络拥塞 —— 当网络中出现突发性 (burst) 拥塞时会引起网络抖动;
- 传输信道不稳定 —— 对于移动网络在基站切换/信道调整时表现的比较明显;
最佳网络性能的参考值
Metric | Value |
---|
Latency (RTT) | < 100ms | Packet Loss | < 1% during 15s interval | Jitter | < 20ms during 15s interval |
0x02 网络性能测试
下面描述几种简单易用的网络性能测试方法。
① ping
ping 是使用最广泛并且最简单直观的测试方法,通过 ICMP 协议来测试网络的性能。
# ping -i 0.001 -c 5 -s 1200 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 1200(1228) bytes of data.
1208 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.067 ms
1208 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.049 ms
1208 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.044 ms
1208 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.047 ms
1208 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.043 ms
--- 127.0.0.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4ms
rtt min/avg/max/mdev = 0.043/0.050/0.067/0.008 ms
通过上面的示例,可以基本反应出网络的性能参数:
- packet loss 即丢包率;
- rtt (Round-Trip Time) 即 icmp 数据包的往返时间;
- mdev (Mean Deviation) 计算公式为:
m
d
e
v
=
1
N
∑
i
=
1
N
(
x
i
?
x
ˉ
)
2
mdev = \sqrt{\frac{1}{N}\sum_{i=1}^{N}{\left(x_i - \bar{x}\right)}^2}
mdev=N1?∑i=1N?(xi??xˉ)2
? ; 它表示 ICMP 的 RTT 偏离平均值的程度,值越大说明网络抖动越大。
② iperf
iperf 可以在传输层测试网络性能,支持的协议包括 TCP、UDP、SCTP 。iperf 更倾向于网络吞吐量 (Throughput) 的测试。
# iperf3 -s -i 1
-----------------------------------------------------------
Server listening on 5201
-----------------------------------------------------------
Accepted connection from 127.0.0.1, port 44566
[ 5] local 127.0.0.1 port 5201 connected to 127.0.0.1 port 58975
[ ID] Interval Transfer Bitrate Jitter Lost/Total Datagrams
[ 5] 0.00-1.00 sec 23.8 MBytes 200 Mbits/sec 0.025 ms 0/763 (0%)
[ 5] 1.00-2.00 sec 23.8 MBytes 200 Mbits/sec 0.021 ms 0/763 (0%)
[ 5] 2.00-3.00 sec 23.8 MBytes 200 Mbits/sec 0.023 ms 0/763 (0%)
[ 5] 3.00-4.00 sec 23.8 MBytes 200 Mbits/sec 0.012 ms 0/763 (0%)
[ 5] 4.00-5.00 sec 23.8 MBytes 200 Mbits/sec 0.011 ms 0/763 (0%)
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Jitter Lost/Total Datagrams
[ 5] 0.00-5.00 sec 119 MBytes 200 Mbits/sec 0.011 ms 0/3815 (0%) receiver
# iperf3 -c 127.0.0.1 -u -b 200M -i 1 -t 5
Connecting to host 127.0.0.1, port 5201
[ 5] local 127.0.0.1 port 58975 connected to 127.0.0.1 port 5201
[ ID] Interval Transfer Bitrate Total Datagrams
[ 5] 0.00-1.00 sec 23.8 MBytes 200 Mbits/sec 763
[ 5] 1.00-2.00 sec 23.8 MBytes 200 Mbits/sec 763
[ 5] 2.00-3.00 sec 23.8 MBytes 200 Mbits/sec 763
[ 5] 3.00-4.00 sec 23.8 MBytes 200 Mbits/sec 763
[ 5] 4.00-5.00 sec 23.8 MBytes 200 Mbits/sec 763
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Jitter Lost/Total Datagrams
[ 5] 0.00-5.00 sec 119 MBytes 200 Mbits/sec 0.000 ms 0/3815 (0%) sender
[ 5] 0.00-5.00 sec 119 MBytes 200 Mbits/sec 0.011 ms 0/3815 (0%) receiver
iperf Done.
通过 iperf 可以比较直观的观察到指定传输协议在指定负载下的网络性能表现。
0x03 网络性能模拟
定量模拟指定性能指标的网络具有很大的工程意义,在开发和设计阶段我们通常都需要一个确定性的非理想网络来进行方案的验证、对比和改进,所以如何去模拟指定性能指标的网络是一个非常重要的话题。下面分别讨论在各常见系统中模拟非理想网络的一般方法。
① Linux
由于 Linux 内核的开放性,所以在 Linux 中模拟网络环境可以调整的参数会比较丰富。很多基于 Linux 内核的上网行为管理路由器都是使用 tc (Traffic Control) 和 iptables 的组合搞出来的。通过 tc-netem 可以以下网络性能参数:
- limit packets
- delay
- distribution
- loss random
- loss state
- loss gmodel
- ecn
- corrupt
- duplicate
- reorder
- rate
- slot
使用 tc 模拟网络性能的基本实现步骤为:
- 针对网络物理设备绑定一个队列 qdisc (Queue Discipline) ;
- 在该队列上建立分类 class ;
- 为每一分类建立一个匹配过滤器 filter ;
- 最后与过滤器相配合,建立特定的网络模拟器 netem 。
示例:
sudo -s
ip address add 192.168.100.1/24 dev lo
tc class show dev lo
tc qdisc add dev lo root handle 1: prio
tc filter add dev lo parent 1:0 protocol ip prio 1 u32 match ip dst 192.168.100.1 flowid 2:1
tc qdisc add dev lo parent 1:1 handle 2: netem delay 100ms loss 0.1
tc qdisc del dev lo root
更多参考:
- https://tldp.org/HOWTO/Traffic-Control-HOWTO/
- http://ce.sc.edu/cyberinfra/workshops/Material/NTP/Lab%203.pdf
- https://man7.org/linux/man-pages/man8/tc-netem.8.html
② macOS
macOS 属于 Unix ,所以与流量控制相关的操作与 BSD 非常相似,一种比较简单的方法是通过 pfctl 和 dnctl 的组合来实现网络环境的模拟。
- dnctl: this is the control interface for the dummynet network shaping software. We use it to define network configurations based on their bandwidth, packet loss, and delay.
- pfctl: this is the control interface for the packet filter device (i.e., the system-internal firewall). We can have it obey dummynet rules and turn it on, which actually enables the network shaping for the host.
macOS 中 dummynet 的 pipe 支持的网络参数包括:
- bw bandwith
- delay ms-delay
- plr packet-loss-rate
- queue {slots | sizeKbytes}
pfctl 和 ductl 模拟网络的一般步骤为:
- 使用 dnctl 建立一个指定参数的 dummynet;
- 使用 pfctl 匹配指定规则的数据包到 dntcl 建立的 dummynet 中;
示例:
sudo -s
ifconfig lo0 alias 192.168.100.1 255.255.255.0
dnctl pipe 1 config bw 10Kbit/s delay 100
pfctl -e
echo "dummynet out proto icmp from any to 192.168.100.1 pipe 1" | pfctl -f -
pfctl -sa
dnctl list
dnctl -q flush
pfctl -f /etc/pf.conf
pfctl -d
如果想在操作系统层面对 macOS 的整体网络环境进行模拟可以使用 Additional Tools 的 Network Link Conditioner
更多参考:
- Simulating Poor Network Connectivity on Mac OSX
- Simulate weak network environment using command line under Mac
- Simulating Different Network Conditions For Virtual Devices
- https://man.openbsd.org/pfctl.8
- https://www.unix.com/man-page/mojave/8/dnctl
- dummynet – traffic shaper, bandwidth manager and delay emulator
③ Windows
Windows 官方没有提供流量控制相关的工具,所以需要第三方的注入式驱动级的插件来支持。比较流行的是开源的 WinDivert,大概的思路是在内核层拦截网络数据然后经过用户层处理后在送回内核层。
+-----------------+
| |
+------->| PROGRAM |--------+
| | (WinDivert.dll) | |
| +-----------------+ |
| | (3) re-injected
| (2a) matching packet | packet
| |
| |
[user mode] | |
....................|...................................|...................
[kernel mode] | |
| |
| |
+---------------+ +----------------->
(1) packet | | (2b) non-matching packet
------------>| WinDivert.sys |-------------------------------------------->
| |
+---------------+
clumsy 在 WinDivert 基础上增加了图形界面,和匹配规则的支持,可以满足常规的网络性能模拟。
更多参考:
- https://github.com/basil00/Divert
- https://reqrypt.org/windivert.html
- https://github.com/jagt/clumsy
- https://jagt.github.io/clumsy
④ Android/iOS
移动设备的网络性能模拟通常有两种实现路径:
- 通过另外一个 APP 来代理所有的网络连接,例如: QNET
- 通过连接代理网关的形式,例如:Charles
更多参考:
- How to simulate Slow Internet Connection on Android Devices
- Testing Android/IOS apps under network conditions
0x04 总结
最后,还是要强调一下确定性网络性能模拟在实践中的重要性。通过本文中讨论的一些方法,您可以从使用者的角度去查看应用程序可能面临的网络条件。如果是媒体传输或者实时交互类的应用场景,那么这些问题将变得更加有价值。
0x05 参考文档
- Network issues simulation: How to test against bad network conditions
- Sometimes Kill -9 Isn’t Enough
- Vagrent -> Documents -> Multi-Machine
- How we simulate real-world network conditions for testing
|