计算机网络 39:独立研究小项目,复现一个拥塞、排队或协议性能结论
“发送的数据总量相同,完成时间就应接近”忽略了到达过程。固定出口每毫秒服务一个报文时,24 个报文均匀到达可以几乎不排队;同样 24 个报文在很短窗口内到达,最后一部分会等待多个服务周期。
本篇把这个判断做成一个小型可复现实验。研究问题是:总报文数、报文大小和服务率不变时,发送同步程度是否改变队列等待分布;pacing 能否在该模型内缩短尾部等待。第 19、20、35 篇提供拥塞、队列和 incast 前置知识。
假设、基线与判定标准
实验使用离散 FIFO 单服务台。每个报文的服务时间固定为 1000 微秒,每次运行处理 24 个等长报文。三种到达模式只改变时间分布:
steady:单个来源每 1000 微秒提交一个报文,并加入 0–200 微秒固定种子抖动。burst:24 个报文都在 0–200 微秒窗口到达。paced:三批各有 8 个报文,批起点相隔 8000 微秒,每个报文再加 0–200 微秒的固定种子抖动。
种子固定为 7、19、43。每次运行保存每个报文的到达时间、服务开始/结束时间、等待值和到达时前方未完成报文数(包含正在服务的报文),并计算平均值、p50、p99 与最大值。本次研究假设为每个种子都满足 burst p99 > paced p99 > steady p99。脚本总是先输出数据,再报告假设在各次运行中是否得到支持;改参数后即使排名变化,也不会因预期排名断言而在输出前终止。
这里的 p99 使用 nearest-rank:对 24 个等待值排序,取第 ceil(0.99 × 24) 个。样本很小,因此 p99 实际等于最大值;文章不会把它外推成线上 p99。
模式提炼:一次只改变待研究变量
固定服务模型与工作量 + 改变到达过程 + 重复固定种子 + 保存原始值
性能结论需要同时交代输入、统计口径和反例。只给一张平均值图,无法判断尾部是否由少数突发产生。
可复跑实现
queue_experiment.py 使用 Python 标准库生成到达时间,按 start = max(arrival, previous_finish) 计算 FIFO 服务开始时刻,等待时间为 start - arrival,服务结束为 start + service_time。“模型实现正确性”只检查这三条算术关系;“研究假设是否成立”另行比较三种模式的 p99。前者通过不会使后者自动成立。
unfinished_packets_ahead_at_arrival 统计到达时完成时间严格大于到达时间的前序报文,包含正在服务的报文,不等同于前序等待报文数。到达 [0, 500]、服务时间 1000 时,第二包前方未完成报文数为 1、前序等待报文数为 0、等待时间为 500 微秒。前序报文恰在到达时完成则不计入;脚本在每次输出前断言这两个边界。
1 | |
素材包括实验配置、实验脚本、逐报文原始数据与汇总、资料与运行记录和审阅记录。
结果与解释
实际输出如下,单位均为微秒:
| seed | 模式 | mean | p50 | p99 | max |
|---|---|---|---|---|---|
| 7 | steady | 82.333 | 59 | 157 | 157 |
| 7 | paced | 3439.042 | 2974 | 6871 | 6871 |
| 7 | burst | 11435.042 | 10948 | 22843 | 22843 |
| 19 | steady | 103.417 | 117 | 173 | 173 |
| 19 | paced | 3427.333 | 2953 | 6875 | 6875 |
| 19 | burst | 11416.667 | 10928 | 22811 | 22811 |
| 43 | steady | 64.083 | 55 | 191 | 191 |
| 43 | paced | 3420.292 | 2984 | 6902 | 6902 |
| 43 | burst | 11386.625 | 10886 | 22809 | 22809 |
三个种子都支持本次排名假设。steady 的 p99 从 157 到 191,paced 从 6871 到 6902,burst 从 22809 到 22843。样本只有 24 个,nearest-rank p99 就是最大值,因此这里的 p99 不是稳定的尾延估计。
批间隔 8000 恰好等于 8 × 1000 微秒,不是大于一批的服务时间。每批内最早到达的报文带有随机相位,因此前一批的完成时刻可以跨过下一批的首个到达时刻。下图取原始时间线中的关键点:
1 | |
seed 19 的第二批在 8027 微秒到达,前一批在 8011 微秒结束,中间空闲 16 微秒;第三批则恰在前一批结束的 16027 微秒到达。pacing 在这个模型中缩小了单次突发规模,所以等待分布显著低于 24 包同批到达;它并未保证批间队列每次都完全清空。
与 RFC 8289 的对照
RFC 8289 §2 将 sojourn time 定义为报文进入缓冲区到离开缓冲区的时间(发送或丢弃均可导致离开)。§3.1 讨论估计器:对每个 RTT 都能消散的短突发,平均队列或平均驻留时间可能把短暂积压误判成持续队列;CoDel 因而关注近期时间窗内的最小 sojourn time。
该论点的前提包括:能在入队时记录时间戳,在离开缓冲区时计算 sojourn time,且观察窗口要长到足以覆盖预期的最大突发或相关 RTT。RFC 的评价方法是用近期最小驻留时间判断队列是否持续,而不是只看平均队列长度。
本模型只计算 FIFO 单服务台的到达 arrival_us、开始服务 service_start_us 和完成服务 service_end_us。wait_us = service_start_us - arrival_us 只表示服务前等待;服务开始不等于离开缓冲区,不能把 wait_us 直接称为 RFC 的 sojourn time。前方未完成报文数按完成时间计数,因此包含正在服务的报文。模型用逐包时间线和 p50/p99 比较三种到达过程,没有计算 CoDel 的时间窗最小值、TARGET、INTERVAL、drop state 和控制律,也没有 RTT、TCP/QUIC 反馈、多流竞争或真实链路。它只检查给定参数下的 FIFO 等待分布,不构成 CoDel 或真实网络性能验证。
模型没有反馈环,因此不能声称复现了 TCP 或 QUIC 拥塞控制。RFC 9002 中的拥塞窗口、ACK、丢包检测与 pacing 约束远比单服务台复杂。这里只验证一个有条件的排队结论:在给定的 FIFO 服务率下,相同总工作量的到达时序不同,会产生不同等待分布。
反例与证据强度
第一个反例是无限快出口。服务时间趋近零时,三种到达模式的等待都趋近零,同步本身不会造成可观测队列。
第二个反例是足够大的 pacing 间隔只改善发送端可控的突发。如果多个独立来源仍在同一时刻汇聚,单个来源 pacing 不保证消除 incast。
第三个边界是 FIFO。FQ-CoDel 把流隔离与受控延迟算法组合起来,CoDel 根据队列驻留时间采取动作。本文没有实现二者,不能从结果推导其真实参数或收益。
练习
练习一:把 pacing 间隔从 8000 微秒改为 4000 微秒,先预测 p99 如何变化,再运行脚本。解释哪一批报文开始与前一批队列重叠。
练习二:保持 24 个报文不变,把服务时间改为 100 微秒。说明为何 burst 的绝对等待下降,但“同步到达增加队列”的方向仍可能成立。
模式速查表
| 研究要素 | 本篇固定内容 | 结论边界 |
|---|---|---|
| 工作量 | 24 个等长报文 | 不代表真实业务大小分布 |
| 服务 | FIFO、每包 1000 微秒 | 不代表交换机或内核调度 |
| 重复 | 固定种子 7、19、43 | 只覆盖 0–200 微秒抖动 |
| 原始数据 | 每包等待时间 | 没有真实时间戳与抓包 |
| 反例 | 快出口、短 pacing 间隔 | 结论必须带容量条件 |
官方一手参考资料
- RFC 8289:The Controlled Delay Active Queue Management Algorithm,IETF,2018-01,访问于 2026-09-24。
- RFC 8290:The Flow Queue CoDel Packet Scheduler and Active Queue Management Algorithm,IETF,2018-01,访问于 2026-09-24。
- RFC 8257:Data Center TCP (DCTCP),IETF,2017-10,访问于 2026-09-24。
- RFC 9002:QUIC Loss Detection and Congestion Control,IETF,2021-05,访问于 2026-09-24。
验证边界
已验证:Python 3 标准库在三个固定种子下运行 FIFO 离散模型,保存逐报文到达、服务开始/结束、等待和前方未完成报文数(包含正在服务的报文)。事件算术与研究假设分开报告;本次三个种子均支持排名假设,验证类型为 STATIC。
NOT_RUN:未使用真实 NIC、交换机、内核 qdisc、TCP/QUIC 实现、硬件时间戳或跨主机链路;没有真实吞吐和延迟测量。模型输出不得与论文或设备结果拼接成性能排名。






