摘要

  • RFC 3525 只保证一个事务内部的命令依次执行;不同事务即使放进同一条消息,也可以乱序或并行处理。
  • TransactionPending、重传、响应确认与“至多执行一次”各自证明有限的传输事实,不能替代跨事务因果顺序,更不能证明媒体结果。

2003 年的 RFC 3525 面对的是一个已经拆开的多媒体网关。Media Gateway Controller 掌握控制逻辑,Media Gateway 掌握媒体侧资源。协议必须让控制者改变远端状态,同时又不能让所有无关资源排成一条长队。

它的结构很规整:Message 包含 Transaction,Transaction 包含 Action,Action 面向一个 Context 并包含 Command。正因为层级整齐,人们很容易误以为外层容器会把内层工作全部排好顺序。

真正的保证只在一个 Transaction 内。命令依次执行;第一个失败的非 Optional 命令会阻止后续命令继续。若失败命令被标为 Optional,队列可以越过它。这是一条清楚、可测试的执行规则。

事务之间则没有顺序保证。网关可以任意排序,也可以同时处理。把 A、B、C 三个事务放在同一条 Message 里并不会生成统一时钟。规范甚至明确说,Message 本质上只是传输机制。

回复也可能重新分组:A 与 C 的结果先出现在一条消息里,B 的结果随后单独到达。编码上的相邻,不代表执行上的相邻;一条消息的完整送达,也不是一组事务的应用层确认。

这种选择保护了并行能力。不同 Termination 可以由不同进程或线程控制,互不依赖的动作无需彼此等待。若协议强迫整个网关全局串行,局部关系就会变成全局瓶颈。

责任因此落回真正知道依赖关系的控制器。对同一个 Termination,通常最多只应有一条未完成的 Add、Modify 或 Move,除非这些命令本来就在同一事务中。需要“先创建、后修改”时,控制器必须把顺序写进事务,或者等到前一张回执。

Subtract 把问题暴露得尤其直接。它可以随时发出。此前发送的 Modify 可能较晚才被处理,而目标 Termination 已经被删除。网关应忽略这条 Modify 并返回错误。发送日志仍然整齐,运行状态却走了另一条时间线。

Notify 也可能迟到。控制器已经发出新的 EventsDescriptor 后,旧 Notify 才抵达。在 UDP 等不保证按序交付的传输上,规范建议每个 Termination 通常最多保留一个未完成 Notify。判断事件需要 RequestID、Termination 身份和时间,而不是消息队列中的位置。

“Transaction”这个名字也不应被理解成数据库式原子提交。一个命令失败时,网关应在可能范围内恢复到尝试执行该命令之前的状态。文本没有承诺撤销本事务中更早已经成功的命令。

TransactionReply 恰好保留了这种细节:它包含成功命令的返回值,也包含失败命令及其错误描述。只把整笔事务压成“成功/失败”,会丢掉已经生效、尝试失败和根本未尝试三类事实。

通配 TerminationID 让部分结果更明显。同一命令会对每个匹配目标分别尝试,并分别生成响应。只要一个匹配项出错,后续命令便不再尝试。于是,一笔事务中完全可能同时存在若干成功目标、一个错误和一段未执行尾部。

TransactionPending 仍然只是窄回执:接收方还在主动处理,发送方应重置定时器。它没有说明走到第几条命令,也没有保证最终状态,更没有让其他事务停下来等它。

附录中的事务 ID、重传、保存回复与响应确认解决的是重复执行问题。回复丢失后,请求可能重发;接收方需要识别旧事务并返回旧结果。做到“至多一次”并不意味着两个不同事务有了顺序,也不等于用户服务“恰好成功一次”。

控制链路的认证与完整性保护同样有边界。它能证明命令来自正确一方且未被篡改,却不能补上一条控制器没有表达的依赖。真实命令照样可能在错误的时间到达。

即便最终回复成功,证据链也没有到终点。它能证明协议处理结果;Audit 可以读取 Context 或 Termination 属性。媒体包是否经过预期路径、解码器是否输出声音、用户是否听到通话,仍需各自观察。

RFC 3525 的身份后来也发生了变化。它在 2003 年取代 RFC 3015,承载 IETF Megaco 工作组与 ITU-T 第 16 研究组的共同文本。RFC 5125 于 2008 年将其改列 Historic,因为 H.248.1 已由 ITU-T 继续修订。今天引用它,应当引用历史机制,而不能把它说成所有现网设备的当前规范。

IANA 的 Megaco/H.248 注册表仍在维护包、错误码、ServiceChange 原因与 profile 名称。注册表证明共同词汇继续被协调;它既不证明某台网关运行哪个版本,也不记录事务真正如何竞速。

这段历史留下的设计原则很薄,却很强:只在真正共享依赖的最小范围内强制顺序。无关 Termination 可以并行;相关命令必须同处一个事务,或等待上一层回执。容器负责协调,运行代码负责现实。

Sources