摘要

  • RFC 3321 让压缩端通过显式确认知道某个状态已在远端解压端建立,从而可以在不可靠传输上安全地推进动态压缩。
  • 确认描述的是建立时刻,不是永久租约;后续状态创建、保留优先级与有限内存仍可能删除它,压缩端必须不断修正自己的远端状态模型。

公告穿过了边界,状态没有留下

RFC 3321 在共享压缩优化中描述了一个很容易被监控系统抹平的时间差。一个端点把未压缩消息保存为共享状态,并向对端传递相应标识。对端若使用这个共享状态,原端点可以据此推断:另一份伴随状态已经在远端成功创建。这样就可能省去单独携带 acked_state_id 的开销。

紧接着,文档发出警告:公告信息可能已经成功转交,但被它间接确认的状态仍可能因为状态内存不足而被丢弃。如果压缩端继续把那条公告解释为“状态现在还在”,下一条消息就会引用一个已经不存在的基线,最终触发解压失败。

这里没有必要假定欺骗、篡改或实现违规。公告可以在产生时完全正确,删除也可以完全符合内存规则。错误发生在第三处:压缩端把一条关于过去的证据延长成了关于现在的保证。

动态压缩需要一份远端记忆模型

2003 年 1 月发布的 RFC 3321 是 Informational 文档,并不自称互联网标准。它说明怎样利用 RFC 3320 的通用解压虚拟机扩展 SigComp,包括显式确认、共享压缩、跨会话状态、用户专用字典、检查点状态和隐式字典删除。它没有给出实际部署率或带宽收益测量。

动态压缩依赖先前消息形成的状态。压缩端负责保证自己生成的消息能够被远端 UDVM 解开,因此不能只知道“我曾经要求对方保存状态”,还要知道对方确实建立了状态。RFC 3321 将收到确认的状态定义为远端已经建立的状态,并要求压缩端只使用远端已建立的状态;否则就会解压失败。

在不可靠传输上,创建状态的消息可能丢失或乱序,显式确认填补了这个证据缺口。可靠传输如 TCP 能保证消息到达,但“消息到达”仍不等于“衍生状态永久占据内存”。传输层证明不了应用是否授权保存,也证明不了后续分配是否将它淘汰。

这也是本文与前一篇 RFC 3320 文章的边界。前文讨论解压成功为什么不能自动授权创建持久状态;本文从创建和确认都已经发生的时刻开始,追问那条确认在多久以后仍可用作行动依据。

检查点有优先级,没有不死权

RFC 3321 的检查点状态机制把问题写得很清楚。压缩端可以把新状态的 state_retention_priority 设为自己发送过的最高值,并要求接收方显式确认。即便如此,文档仍列出状态不存在的三种原因:创建消息丢失;创建时内存不足;状态曾经建立,却在后来因内存不足被删除。

第三种原因意味着“已确认”和“找不到”可以同时是真实记录,只是时间不同。检查点是删除规则下更值得保留的恢复锚点,不是脱离有限资源约束的永恒对象。

压缩端因此必须跟踪远端可用于保存状态的内存。反馈参数 state_memory_size 可以帮助它推断:创建一个较新的检查点是否会把旧检查点挤出。它提供的是容量约束,不是一张逐项列出当前状态的远端目录。要判断某个标识现在是否仍存在,还必须结合创建顺序、年龄、优先级以及后来发生的状态变化。

标识本身没有完整语义

扩展反馈中的部分状态标识可能指向已确认状态、共享状态或全局状态,具体类型要由实现自行推断。RFC 3321 还说明,“remaining SigComp message”的最终格式属于实现决定;基础 SigComp 实现收到扩展标识时可以忽略它们。

所以,在抓包里看见某个标识并不能直接推出“双方此刻对同一状态达成一致”。解释需要本地映射:哪个机制产生了它,它对应哪个 compartment,是否有足够长度避免误认,之后是否发生内存变化,以及接收实现是否支持该扩展。脱离这些上下文,字段只能证明比运维报告通常声称的更少。

RFC 4896 把合法的不确定性写了出来

2007 年的 RFC 4896 更新并澄清了 RFC 3320 与 RFC 3321。它提醒实现者,保留优先级的顺序很反直觉:65535 比 0 还低,之后才是 1 到 65534。优先级属于某个 compartment 对状态的引用,而不是简单贴在全局状态字节上。

更重要的是,它用共享模式示例证明:一旦解压 compartment 中出现多份最低优先级状态,压缩端可能无法确定究竟哪一份仍在。新的最低优先级状态可能比预期更早挤掉旧状态,双方即使都正确执行状态规则也会出现这种认知差。文档因此要求压缩端除非能够确认状态存在,否则不应引用它。

RFC 4896 还澄清了端点发起的状态公告。公告表示状态已在 compartment 内成功创建,并将在由年龄和保留优先级删除规则定义的生命周期内可用。这个保证有规则边界,不是“永远可用”。将生命周期条件删掉,只保留“已公告”,就会把条件性承诺改写成永久承诺。

NACK 是更新,不是翻案

RFC 4077 后来定义了 STATE_NOT_FOUND 负确认。当接收方无法找到被引用的状态时,它把相应状态标识带回,压缩端通常应在未来消息中停止使用它。这条 NACK 并不反证早期确认是假的。状态完全可能先建立、获确认,再被合法删除。

正确的证据链应当同时保存正确认和负确认,以及两者之间的容量公告、状态创建和删除事件。只留下最后一个布尔值,会让排障者在“当时存在”和“现在不存在”之间被迫选择一个,仿佛二者不能同时成立。

RFC 3321 的历史意义因此不是让确认变得绝对,而是让远端状态第一次能够被有条件地依赖。条件包括机制、时间和资源。互联网协议里最危险的收据,往往不是伪造的收据,而是一张已经过期却仍被当作当前事实的真收据。

Sources