摘要

  • RFC 1016 提出 SQuID:由源主机的 IP 模块为近期通信的目的地记录逐包等待时间 D。默认 D 为零,只有被限速的目的地需要保留状态。
  • 文中的示例参数把首次警告后的 D 设为至少 75 毫秒,后续警告事件增加 20 毫秒,两秒内多条警告合成一次事件;有数据待发时,每过一个符合条件的秒数减去 1 毫秒。作者用 C 语言写的模拟网络观察了效果。

一条快速局域网向慢速线路递包裹,就像电梯门口的人把整栋楼的快递同时塞给一辆自行车。W. Prue 和 Jon Postel 在 1987 年 7 月的 RFC 1016 算过一笔账:若有 1 MB 数据排队等一条 56 kb/s 的线路,最后一个数据报要等两分钟以上才能出发。网关的输出队列一旦吃紧,可以丢弃数据报,并向源主机发 ICMP Source Quench,要求它降低发往相关目的地的速度。警告说得很清楚:这里堵了。具体的节奏,却留给发送端自己算。

作者把办法叫作 SQuID,即 Source Quench Introduced Delay。它不先去改应用,而是让源主机的 IP 模块给每个受影响的目的地设等待时间 D。同一目的地的两个数据报之间留出 D;普通状态下 D 为零。主机只需保存 D 大于零的近期目的地。某个方向在等,发往另一处的数据报仍可先走。一个网关的窄口,不必把所有出口都拉进同一场罚站。

秒表往上拨得快,往下拨得慢。文中的参数是:一轮 Source Quench 到来时,D 取“原值加 20 毫秒”和“75 毫秒”之中的较大者。两秒内不管收到一条还是多条警告,只算一次增加。因为网关可能成批报告拥塞;主机若把每声喊叫都当成独立命令,等待时间会被抬得过高。之后,若距上次减少已经过了一个符合条件的秒数且有数据待发,D 才减去 1 毫秒,最低到零。目的地闲着的时候,钟表空转不会替它自动消除这笔延时。

75 毫秒放在日常生活里几乎看不见。放在同一目的地的每个数据报之间,快局域网送来的洪水就能被拆成一股股小流。警告不再只是抽象的情绪,而变成发送端可以执行、可以调整的动作。作者在备忘录开头自称这是篇“疯狂点子”的讨论稿;数字和公式恰好让讨论有了可试的东西。

网关也被分配了具体活儿。作者建议在队列达到一个预警水位时就发 Source Quench,同时放行触发警告的数据报;只有进入更高的危险水位才丢数据。其示例把预警 SQK 放在队列的 70%,丢弃 SQT 放在 95%,停止持续警告的低水位 SQLW 放在 50%。水位不同,动作不同。网关掌握自己的排队情况,发送端掌握下一批数据报何时出门;两端靠一条警告衔接。

为了看这套分工和 TCP 一起工作时会怎样,Prue 与 Postel 用 C 写了网络模型。示例路径是 10 Mb/s 局域网、56 kb/s 广域线路、另一端的 10 Mb/s 局域网。模型里有排队、512 字节数据报和固定路由;碎片处理与 TTL 不在模拟范围内。试验发现各种算法都会振荡。若 D 加得太慢、减得太快,发送端会长时间超过线路承受力,继续丢包。更大的增加和更缓的减少,在模型里更有希望;两秒合并警告也避免被一阵消息推得太远。

二十个数据报的一次 TCP 突发,把拥塞拍得像现场照片。按 RFC 选定的队列条件,它们 81 毫秒便涌到网关,而下一段线路约每 73 毫秒只能送走一个。第 17 到第 20 个数据报会在这轮窗口发送中丢失。TCP 看到窗口开着,便一口气递出二十个;慢线路没有义务跟着它冲刺。SQuID 试着把发送的间隔提前安排在源头,别等包裹到了窄门才发现排不上队。

论文还指出,许多当时的 TCP 实现并没有从 IP 和 ICMP 那里获得定义清楚的 Source Quench 通知。把动作安在源 IP 模块,至少让警告能直接改变下一批数据报的出发节奏。模拟结果显示,网关在丢包前先示警,可能改善有效吞吐;固定路由与简化流量则限定了这次试验的外推范围。真正上线的测量仍须另找。1987 年这篇文本留下的鲜明问题是:谁把网关的“慢点”翻译成下一包实际要等的时间?SQuID 把翻译工作交给了主机的秒表。