摘要

  • RFC 2371 规范的是事务管理器之间范围有限的两阶段协商;业务请求、参与者登记、授权和用户回执都由别的系统承担。
  • 持久化的 PREPARED 状态可以帮助故障恢复,却不能证明所有预期请求都已加入事务,也不能证明调用者收到了最终结果。

两条管道,不是一张收据

1998 年 7 月发布的 RFC 2371 把 Transaction Internet Protocol(TIP)定义为一种简洁的两阶段提交协议。事务的具体内容——订单、预订、转账或别的应用操作——从应用协议中传输;TIP 只让多个事务管理器对提交或中止达成一致。规范把它称为“双管道”模型。

这样做省去了为每一种业务重新规定消息格式和数据表示的负担。既有应用可以继续说自己的语言,事务管理器只需共享一套很小的协调语言。RFC 也没有宣称 TIP 要取代所有既有的两阶段提交机制。

代价是证据边界必须保持清醒。事务管理器可以正确地返回 COMMITTED,却不知道顾客是否看到确认页,不知道某个预期请求是否根本没有发出,也不知道应用是否把事务范围画错了。协调管道内部的正确,不会自动补齐业务管道遗漏的事实。

事务边界由应用画出

RFC 用购物场景说明:本地事务管理器与若干远端管理器加入同一事务,从而让多笔订购一起提交。TIP 可以保证已登记参与者之间的原子协商;“哪些操作属于这一笔事务”以及“什么时候可以提交”,仍由应用决定。

最危险的状态往往恰好不在协调协议里。一个应用请求可能还在途中;远端服务可能已经做了工作,却尚未向本地事务管理器登记;业务设计中应当出现的参与者也可能根本没有加入。配套的 RFC 2372 因而明确提醒:双管道模型下,TIP 未必能强制应用消息串行化。应用不能在仍有未完成请求时发起提交,也不应在本地事务管理器登记之前向上游报成功。

原子性只覆盖被纳入事务的参与者。它不会发现漏掉的人,也不会替应用修正画错的边界。

事务怎样找到另一台管理器

TIP 提供 PUSH 与 PULL 两种上下文传播方式。PUSH 由上级事务管理器主动要求下级关联某个事务;PULL 则由应用先携带一个 TIP URL,接收方再用其中的地址和事务引用去登记。

这个 URL 被要求“永久全局唯一”,但生成方式留给实现决定。RFC 提到 UUID 只是可能的办法之一;多年后发布的 RFC 4122 不能被倒推成 1998 年 TIP 的强制格式。

更关键的是,TIP 自己并不“打开”TIP URL。引用要经过应用管道传递。它是一处会合坐标,不是执行回执。拿到它不能证明 PULL 成功、业务请求获得授权,更不能证明资源已经提交。

状态机只陈述自己有权陈述的事实

TIP 通常运行在 TCP 上,可以协商 TLS,也能在一条连接上多路复用若干事务。状态机包含 Initial、Idle、Begun、Enlisted、Prepared、Multiplexing、TLS 与 Error 等状态。每一个状态约束的是两台事务管理器接下来可以说什么,并不描述完整的业务旅程。

PREPARED 尤其重要。它意味着参与方已经留下足够的持久恢复信息,并承诺日后能够执行上级决定。准备失败也不会悄悄等同于 ABORT。只要进入准备状态,这笔事务就会占据真实的恢复责任,直到结果得到确认。

COMMIT 的含义同样比日常语言窄。它是协调器对已登记事务作出的结果指令;下级的 COMMITTED 响应则报告协议层结果。两者与顾客看到的“订单完成”之间,还隔着本地资源落盘、连接故障、响应送达和应用展示。

结果成功,最后一条回复仍可能丢失

RFC 2372 把这个歧义写得直白:客户端调用提交后,可能收不到最终结果,而事务实际上已经成功完成。应用必须借助其他方式查明结果,例如实现自己的日志。沉默不等于中止,响应丢失也不能证明什么都没发生。

TIP 的恢复机制处理事务管理器这一层。持久记录配合 RECONNECT 与 QUERY,可以让故障后的双方重新找到准备状态与最终结果。它保存的是运行中的决定,不是用户业务旅程的全部重放。恢复记录可以证明某个参与者已提交,至于确认消息是否到达、顾客应看到什么状态,仍需应用自己对账。

安全性不会自动跨越接缝

规范允许使用 TLS,却把是否启用交给本地策略。它特别警告:只保护应用通信而不保护提交协议,会反过来破坏应用的安全。反面也成立——一条受保护的 TIP 会话,并不能证明底层购买行为获得了正确认证和授权。

PULL 与 PUSH 暴露的风险并不相同。恶意 PULL 可能诱使事务中止;PUSH 可能制造大量停留在准备状态的资源负担;伪造的重连或结果指令则可能篡改事务结果。这些是协议权限和资源控制的问题,不会让 TIP 变成应用的身份系统。

RFC 2371 真正提供的证据链

一份可靠的记录至少要把九件事分开:应用发出业务请求;事务上下文跟随正确的工作;所有预期参与者完成登记;各参与者完成应用操作;持久 PREPARED 记录存在;协调器选定结果;本地资源执行结果;协议确认返回;调用者收到可信的业务回执,并在之后观察到预期状态。

TIP 强化了这条链的中段,从未声称一行 COMMIT 能吞并整条链。

从 Lu Heng 的“最小初始规范”看,这种克制正是设计价值:只规定异构事务管理器互通所需的协调核心,把应用载荷、数据表示、业务身份与授权留在协议之外。按照“运行代码优先”的检验,事务的真实性来自登记、持久准备、结果交换、本地资源动作与恢复,而不是架构图上的名字。再用“现实层次”来报告,COMMIT 指令、COMMITTED 响应、用户回执与稍后的账户状态彼此相关,却绝不是同一个事实。

RFC 2371 留下的历史教训因此超出了某一种事务产品:协议只能在自己实际控制的边界内保证一致。COMMIT 是协调系统发出的一张重要凭据,但它不是业务回执。