摘要

  • RFC 1046 设想用受限的小队列为已接纳的低时延报文限定单节点等待;溢出的报文直接丢弃,同时限制这一类流量的链路份额,避免它排挤其他服务。
  • 发生资源争用时,多个 Type-of-Service 请求是“或”而不是“且”。节点只能先给一个队列处理;回退到另一队列可能增加接纳机会,也会带来乱序、单向时延波动和不同的可靠性交换。

1988 年 2 月的 RFC 1046 是一篇公开征求讨论的 idea paper。它没有宣布互联网已经具备低时延服务,也没有给出全球通用的套餐。它问的是一个更早、更实在的问题:IPv4 头里已经有了“低时延”“高吞吐”“高可靠”的标记,路由节点在输出口拥塞时究竟该怎么做?

答案不在那几个比特里,而在缓冲区、调度机会与丢包规则里。

没有争用,分类就没有代价

RFC 791 给 IPv4 定义了八位 Type of Service 字节。三位表示 precedence,另外几位表达低时延、高吞吐和高可靠偏好。原文已经把三者称作一种交换关系:某项表现更好,往往意味着另一项变差,通常不应同时要求全部三项。

但抽象偏好不会自己长成队列。RFC 1046 的起点是“需求超过当前能力”。若输入与输出相称、队列始终很短,普通 FIFO 已足够,特殊调度反而多余。只有多类报文争用有限缓存和链路时间时,标记才迫使节点分配代价。

这也划出文章的证据边界。看到低时延位,只能知道发送方表达过偏好;要证明它获得了某种服务,还必须看到分类、接纳、队列和实际发送记录。

延迟上界来自队列不能变长

RFC 1046 把低时延目标称为每个节点的 Maximum Guaranteed Delay(MGD),而且附带一个常被忽略的条件:报文要成功穿过互联网。它约束的是被队列接纳后的等待,不是保证每个带标记的报文都能入队,更不是保证最终交付。

文中的关系式很直白:

最大等待 = N / (P × R)

其中 N 是低时延队列长度,P 是分配给该类的链路资源比例,R 是链路每秒可发送的报文数。若目标等待不变,链路越慢、份额越小,允许的队列就越短。传播时延较高的链路还要从预算中扣掉自身开销。

因此,MGD 依赖三个本地事实:多深的队列、多大的份额、多快的链路。头部没有携带这些配置。发送方不能只靠置位,就替节点决定它有多少缓存或传输机会。

小队列保护等待,也制造更早的损失

提案建议低时延队列的服务率低于其他类别,以免它消耗过多资源。队列要小到足以守住等待上界;到达量超过上限时,新报文直接丢弃。因为反馈赶不上小队列的变化,基础方案认为这一类不宜发送 Source Quench。

这就是“快”的真实价格。低时延不是同时获得更大带宽、更多缓冲和更可靠交付。恰恰相反,节点用更少的等待空间换取时间确定性,没挤进去的报文承担损失。

高可靠队列采取相反路线:缓冲更长,更早发出 Source Quench,直到队列真正填满才丢弃。它提高的是应对拥塞时的存活机会,却可能让报文等得更久,而且解决不了高误码链路或需要前向纠错的情况。

高吞吐队列则获得示例中最高的服务率和更大的缓冲,接受较高的平均节点时延。把同一 burst 尽量连在一起发送只是试探性建议,因为队列未必知道上层协议是否适合这种假设。

三种服务不是“普通、优质、豪华”。它们把损失、等待和容量分配给不同位置。应用真正需要选择的,不是最漂亮的标签,而是哪一种失败更可接受。

多打两个勾,不会叠出三份权利

RFC 1046 在算法部分先写下一个关键原则:资源争用时,多种类别请求应按 OR 解释,而不是 AND。只有没有争用时,低时延与高吞吐才可能同时兑现。

落到队列上,一个报文在一个节点只能进入一种类别。提案给出的选择顺序是低时延、高吞吐、高可靠。例如同时请求低时延和高可靠的报文,若小队列已满,可以回退到可靠队列。它多了一次被接纳的机会,却不再获得原先那种等待边界。

一组报文可能因为各自遇到的队列状态不同而走入不同队列。服务率不同,就可能发生乱序,单向时延也会更不稳定。接收端仅凭原始 TOS 位,无法还原途中哪一个节点选择了哪只队列,也无法知道哪些同类报文已经溢出。

因此,复合标记提供的是候选处理路径,不是累加的资源权利。

优先级可以插队,但不能永久插队

类别之外还有 0 到 7 的优先级。RFC 1046 允许高优先级报文在同一类别队列内向前移动,却给被多次越过的报文增加本地“frustration points”。累积到一定程度后,它不再被同等新来者反复压后,从而避免无限饥饿。

这个修正只在当前节点有效,下一跳重新开始。它不会篡改报文头里的原始优先级。高优先级新报文也不能把已经排队的低优先级报文踢出满队列;队列满时,仍是最新到达者被丢弃。

优先级还会破坏简单的 MGD 计算。RFC 1046 的示例指出,若低时延报文自身没有同等高优先级,实际等待可能达到不加优先调度时的 1 到 28 倍。“请求了低时延”这一条日志,显然不足以证明等待上界。

比例、上界与滥用控制都没有被比特决定

文中用 17% 低时延、50% 高吞吐、33% 高可靠演示调度,并提出按比例发放“chits”来平滑各类机会。这些只是建议值。末尾的问题清单仍在追问:比例该是多少,MGD 该定多大,如何限制人人都想要的类别和高优先级,是否值得增加路由复杂度,又该用什么模拟验证互联网反应。

提案建议统计报文最终实际使用了哪一种服务,而不是在复合请求时把每个位都算一遍。若类别分布失衡,运营人员需要据此调参。算法并没有把治理责任交给发送方的标记。

这段未完成性很重要。队列配置在分配谁先丢、谁多等、谁多用链路。它需要明确的配置者、可观察的后果和可撤销的更改,不能伪装成一个纯粹中立的字段解释。

后来的规范把历史位置限定得更清楚

RFC 1349 后来明确说,TOS 是严格的建议机制,不适合请求服务保证。设为“最小时延”只表示在可用路径中偏向较低时延,并不保证结果符合用户对“低”的理解。

1998 年的 RFC 2474 与 RFC 2475 用 DS 字段替代旧 TOS 解释,并把 codepoint、每跳行为、业务、流量调节和节点内实现机制分开。它们不能证明 RFC 1046 曾被部署,也不能证明 DiffServ 沿用了那套精确队列;它们只是进一步确认:跨路径携带的标记与本地兑现它的资源机制不是同一对象。

Source Quench 也必须放回年代中。RFC 1016 记录了当时用反馈让主机减速的设想;RFC 6633 后来要求主机不得发送 Source Quench、传输协议必须忽略它,并明确说 RFC 1016 的办法不得实现。本文引用它们是为了界定 1988 年的选择空间,不是给今天的网络操作建议。

来源与证据边界

RFC 791 提供原始 TOS 字段与交换关系;RFC 1046 提供 idea paper 身份、MGD、队列公式、OR 规则、优先处理及未决问题;RFC 1016 与 RFC 6633 限定 Source Quench 的历史;RFC 1349 提供建议性边界;RFC 2474 与 RFC 2475 提供后来的 DS 架构。

这些材料不能证明某个网络实现过算法,不能告诉我们运营者采用了什么队列深度和比例,也不能证明某一报文获得了请求的类别。标记、分类、入队、发送、丢弃、交付与应用结果必须分别记录。