使用qdisc注入时延,为什么会产生丢包?

115 阅读5分钟

在 Linux 系统中,qdisc(Queueing Discipline,排队规则)模块是网络子系统中的一个重要组件,主要用于管理和控制网络数据包的排队和调度行为。以下是 qdisc 模块的主要作用和功能:

  1. 数据包排队管理

  2. 流量控制和调度

  3. 拥塞控制

  4. 分类和过滤

  5. 支持多种调度算法

  6. 网络性能优化

  7. 模拟网络故障

2. 如何模拟网络故障

在 Linux 中,可以使用 tc(Traffic Control)工具结合 netem(Network Emulator)队列规则来模拟各种网络故障。以下是一些常见网络故障的模拟方法:

tc qdisc netem 是 Linux 中用于网络仿真和故障注入的工具,可以模拟各种网络问题,如延迟、丢包、乱序、重复等。以下是 netem 的主要参数及其用途:

  1. 延迟(Delay)
  • 参数:delay TIME [JITTER [CORRELATION]] [distribution TYPE]

  • 作用:

  • TIME:指定延迟时间,单位为毫秒(ms)。所有经过该队列的数据包都会被延迟指定的时间。

  • JITTER:抖动时间,表示延迟的随机变化范围。例如,delay 100ms 20ms 表示延迟时间在 80ms 到 120ms 之间随机变化。

  • CORRELATION:相关性,表示相邻数据包延迟的相关系数(百分比)。例如,50% 表示当前数据包的延迟受前一个数据包延迟的影响程度。

  • distribution:延迟分布模式,可选值包括:

  • uniform:均匀分布。

  • normal:正态分布。

  • pareto:帕累托分布,适合模拟长尾分布。

  • paretonormal:帕累托与正态分布的混合。

  1. 丢包(Loss)
  • 参数:loss MODEL [PERCENT]

  • 作用:

  • PERCENT:指定丢包率,单位为百分比。例如,loss 5% 表示丢弃 5% 的数据包。

  • MODEL:丢包模型,可选值包括:

  • random:随机丢包。

  • state:基于马尔可夫链的丢包模型。

  • gemodel:基于 Gilbert-Elliot 模型的丢包。

  1. 数据包损坏(Corrupt)
  • 参数:corrupt PERCENT

  • 作用:以指定的概率(PERCENT)随机修改数据包的内容。

  1. 数据包重复(Duplicate)
  • 参数:duplicate PERCENT

  • 作用:以指定的概率(PERCENT)复制数据包。

  1. 数据包乱序(Reorder)
  • 参数:reorder PERCENT [CORRELATION]gap DISTANCE

  • 作用:

  • PERCENT:指定乱序的概率。

  • CORRELATION:乱序的相关性。

  • gap:每隔 DISTANCE 个数据包,将一个数据包提前发送。

  1. 限速(Rate)
  • 参数:rate RATE [PACKETOVERHEAD] [CELLSIZE [CELLOVERHEAD]]

  • 作用:

  • RATE:限制数据包的发送速率。

  • PACKETOVERHEAD:每包的额外开销(字节)。

  • CELLSIZECELLOVERHEAD:用于模拟链路层的单元化。

  1. 队列限制(Limit)
  • 参数:limit COUNT

  • 作用:限制队列中可持有的最大数据包数量。

  1. 显式拥塞通知(ECN)
  • 参数:ecn

  • 作用:使用显式拥塞通知(ECN)标记数据包,而不是直接丢弃。

  1. 时间槽(Slot)
  • 参数:slot MIN_DELAY [MAX_DELAY] [distribution]

  • 作用:模拟时隙化网络,将数据包延迟到指定的时间槽内发送。

示例

以下是一些常见的使用示例:

  • 添加固定延迟:tc qdisc add dev eth0 root netem delay 100ms

  • 添加抖动和相关性:tc qdisc add dev eth0 root netem delay 100ms 20ms 50%

  • 丢包:tc qdisc add dev eth0 root netem loss 5%

  • 乱序:tc qdisc add dev eth0 root netem delay 10ms reorder 25%

通过这些参数,tc qdisc netem 可以模拟各种复杂的网络环境,帮助开发和测试人员验证应用程序在网络问题下的表现。

3. 注入时延导致丢包

现象描述

网卡:云芯/E810(25Gb)

在有业务流量(网口有流量500~600MB/s)的情况下,使用qdisc对一个网口注入netem 90ms~100ms的时延,流经此网口数据报文存在少量的丢包。

丢包率:使用ping进行测试,大概有1%的丢包

根因分析

  1. 先确认链路上是否真的有丢包

停掉业务流量,注入时延,ping不产生丢包;重新打开业务流量,注入时延,ping产生丢包。

结论:链路正常

  1. 确认ping包丢在哪里

发包测抓取ping包,接收测同时也抓取ping包,此时复现ping包丢失的场景。

丢包时发包测可以抓到icmp request,无icmp reply;接收测可以抓到icmp request,无icmp reply

结论:数据包丢失产生在接收测

  1. tc qdisc netem的参数调整

tc qdisc netem的参数中,有个limit,用来限制队列长度。调整队列长度测试

默认参数中limit为1000(iproute2/src/q_netem.c),固测试1000和100000

使用1000,复现出ping丢包的场景,使用tc qdisc change修改limit到100000,丢包消失。

  1. 复现测试

在netem_enqueue中丢包的位置添加日志打印

注入900ms + 5 limit的故障,使用ping进行测试

发现ping丢包50%(个数50),netem丢包150

  1. 流程总结

初始化:tc qdisc(iproute2) -> netem delay limit -> sch_netem.ko(netem_init)

-> sch_netem.ko(netem_change)

使用:sch_netem.ko(netem_enqueue) –> qlen > limit -> loss

处理方案

Limit值增大,相当于增大了队列长度,会增加内存占用,可能会对某些时间敏感的数据包造成更大的影响。

方案方案简介缺点
iproute2源码调整将limit默认值改大需要修改基础模块源码默认值大小不好定
使用ethtool获取Speed,计算limit值需要修改基础模块源码
驱动源码调整将limit值改大需要修改内核源码默认值大小不好定
tc命令套壳计算limittc命令套壳,发现delay/latency关键字,则使用ethtool获取Speed,计算limit值,以参数形式加入套壳命令管理困难若limit值增大引起其他问题,定位困难