使用 tc 和 netem 在 Linux 上模拟网络延迟、丢包与乱序

在网络应用的开发和测试过程中,我们经常需要验证程序在恶劣网络条件下的表现。真实网络环境中的延迟抖动、丢包和乱序往往难以复现,而 Linux 内核自带的 tc(Traffic Control)工具配合 netem(Network Emulator)模块,恰好提供了一套强大且灵活的网络损伤模拟方案。本文将系统介绍如何使用这两件工具,在本地或测试环境中精确模拟各种网络异常。

一、认识 tc 与 netem

tc 是 Linux 下用于配置内核流量控制子系统的命令行工具,它能够对网卡出口(egress)和入口(ingress)方向的数据包进行排队、调度、整形和过滤。netem 则是 tc 的一个排队规则(qdisc)模块,全称 Network Emulator,专门用于模拟网络传输中的延迟、丢包、重复、乱序和损坏等行为。

需要特别注意的是,netem 主要作用于出口方向。也就是说,当你在某台主机上对 eth0 添加 netem 规则时,影响的是从该主机发出的数据包。如果希望同时影响入口流量,通常需要借助 IFB(Intermediate Functional Block)虚拟设备进行重定向,这一点后文会详细说明。

二、准备工作

在开始之前,请确认内核已编译 netem 模块,并且系统已安装 iproute2 套件(通常默认包含 tc)。可以通过以下命令检查:

tc qdisc show
modinfo netem

如果 modinfo 能正常输出模块信息,说明 netem 可用。大多数现代发行版(如 Ubuntu、CentOS、Debian)都默认支持。

三、基本操作语法

tc 的核心操作围绕 qdisc(排队规则)、class(类别)和 filter(过滤器)展开。模拟网络损伤时,最常用的命令形式是:

tc qdisc add dev <网卡> root netem <参数>

其中 <网卡> 替换为实际接口名,如 eth0ens33 等。root 表示将该 qdisc 挂载到网卡的根位置。修改已有规则使用 change,删除使用 del

四、模拟网络延迟

延迟是最常见的网络损伤。以下命令为 eth0 的出站流量增加 100 毫秒固定延迟:

tc qdisc add dev eth0 root netem delay 100ms

真实网络中的延迟往往带有抖动,netem 支持指定延迟范围或抖动值:

tc qdisc change dev eth0 root netem delay 100ms 20ms

这表示延迟在 100ms 上下 20ms 范围内随机波动。还可以加入相关性参数,让抖动更接近真实网络:

tc qdisc change dev eth0 root netem delay 100ms 20ms 25%

最后的 25% 表示前一个数据包的延迟与当前数据包延迟之间的相关性。延迟参数支持 usmss 等单位。

五、模拟丢包

丢包通过 loss 参数实现。以下命令模拟 10% 的随机丢包:

tc qdisc change dev eth0 root netem loss 10%

netem 的丢包模型基于随机数生成器,也可以指定相关性,使丢包呈现突发特征:

tc qdisc change dev eth0 root netem loss 10% 50%

此外,还可以使用 loss gemodel 采用更符合真实网络的两状态 Gilbert-Elliott 模型:

tc qdisc change dev eth0 root netem loss gemodel 1% 10% 70% 0.1%

这四个参数分别表示良好状态丢包率、不良状态丢包率、进入不良状态概率和离开不良状态概率,适合模拟具有突发性的无线网络丢包。

六、模拟乱序

乱序通过 reorder 参数控制。要模拟乱序,通常需要先配合延迟,因为 netem 实现乱序的方式是:将一部分数据包延迟发送,从而打乱到达顺序。例如:

tc qdisc change dev eth0 root netem delay 10ms reorder 25% 50%

这里 25% 表示有 25% 的数据包会被乱序发送,50% 表示这些乱序包与前一包的相关性。需要注意的是,如果只写 reorder 而不设置延迟,乱序效果可能不明显,因为内核需要一定的时间窗口来重排数据包。

七、组合多种损伤

实际网络问题往往同时包含延迟、丢包和乱序。netem 允许在一条命令中组合多个参数:

tc qdisc change dev eth0 root netem delay 50ms 10ms loss 5% reorder 10% 50%

这条规则同时施加了 50ms 基础延迟、10ms 抖动、5% 丢包和 10% 乱序,能够较好地模拟一条质量较差的移动网络链路。

八、模拟入口流量

如前所述,netem 默认只影响出口流量。若要限制入口方向,需要加载 ifb 模块并创建虚拟接口:

modprobe ifb
ip link set ifb0 up
tc qdisc add dev eth0 handle ffff: ingress
tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
tc qdisc add dev ifb0 root netem delay 100ms

这样,从 eth0 进入的数据包会被重定向到 ifb0,再经由 netem 处理,从而实现入口方向的延迟模拟。丢包和乱序同理。

九、查看与清除规则

查看当前规则:

tc qdisc show dev eth0
tc -s qdisc show dev eth0

-s 参数会显示统计信息,包括已发送、已丢弃的数据包数量,便于验证规则是否生效。

清除所有规则,恢复默认状态:

tc qdisc del dev eth0 root

对于入口方向的规则,需要分别清除:

tc qdisc del dev eth0 ingress
tc qdisc del dev ifb0 root

十、实用建议与注意事项

第一,netem 规则只影响本机发出的流量,测试时应在客户端或服务端其中一侧配置,避免双向叠加导致结果难以分析。第二,延迟值不宜设置过大,否则可能触发 TCP 重传超时,反而掩盖了原本要测试的问题。第三,在生产环境操作前务必在测试机验证,错误的 qdisc 规则可能导致网络中断。第四,若使用容器或虚拟机,需确认网卡名称与宿主机不同,规则应加在容器实际使用的 veth 接口上。

结合 pingiperf3curl 等工具,可以直观地观察规则生效后的网络表现。例如在配置了 100ms 延迟后,ping 的 RTT 应明显上升;配置丢包后,iperf3 的吞吐量会下降并出现重传。

结语

tcnetem 的组合为 Linux 平台提供了一套低成本、高精度的网络损伤模拟方案。无论是测试 TCP 拥塞控制算法、验证音视频应用的抗抖动能力,还是评估分布式系统在弱网下的容错表现,它都能派上用场。掌握延迟、丢包、乱序这几个核心参数的用法,再结合 IFB 处理入口流量,基本可以覆盖绝大多数弱网测试场景。建议读者在自己的实验环境中反复练习,逐步建立起对网络参数与真实体验之间对应关系的直觉。

未经允许不得转载:任鹏个人博客 » 使用 tc 和 netem 在 Linux 上模拟网络延迟、丢包与乱序

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏