Skip to content

分布式事务 ​

标签
分布式
分布式/事务
字数
3666 字
阅读时间
15 分钟

XA 模型 ​

概述 ​

XA 模型是一种基于两阶段提交(2PC, Two-Phase Commit)的分布式事务协议。它由 X/Open 组织定义,旨在确保分布式系统中的多个资源管理器(如数据库、消息队列等)在事务提交时能够保持一致性。

两阶段提交(2PC) ​

  1. 准备阶段(Prepare Phase):

    • 事务协调者(Transaction Coordinator)向所有参与者(Participants)发送准备请求,询问它们是否可以提交事务。

    • 参与者执行事务操作,但不提交,而是将事务状态记录在日志中,并向协调者返回“准备就绪”或“无法准备”的响应。

  2. 提交阶段(Commit Phase):

    • 如果所有参与者都返回“准备就绪”,协调者向所有参与者发送提交请求,参与者完成事务提交。

    • 如果有任何一个参与者返回“无法准备”,协调者向所有参与者发送回滚请求,参与者回滚事务。

优点 ​

  • 强一致性:确保所有参与者要么全部提交,要么全部回滚,保证事务的强一致性。

  • 标准化:XA 协议是标准化的,许多数据库和消息队列都支持 XA 协议。

缺点 ​

  • 性能问题:两阶段提交过程中,所有参与者都需要锁定资源,直到事务提交或回滚,可能导致性能瓶颈。

  • 单点故障:事务协调者是单点故障点,如果协调者失败,整个事务可能无法继续。

TCC 模型 ​

概述 ​

TCC(Try-Confirm-Cancel)模型是一种基于补偿机制的分布式事务处理模型。它将事务分为三个阶段:Try、Confirm 和 Cancel。

三个阶段 ​

  1. Try 阶段:

    • 尝试执行事务操作,但不提交,而是预留资源或执行部分操作。

    • 如果所有参与者都成功完成 Try 阶段,则进入 Confirm 阶段;如果有任何一个参与者失败,则进入 Cancel 阶段。

  2. Confirm 阶段:

    • 确认事务操作,提交所有预留的资源或完成所有部分操作。

    • 如果 Confirm 阶段成功,则事务完成;如果失败,则需要回滚。

  3. Cancel 阶段:

    • 取消事务操作,释放所有预留的资源或撤销所有部分操作。

    • 确保事务回滚到初始状态。

优点 ​

  • 性能优化:TCC 模型在 Try 阶段不锁定资源,减少了资源锁定时间,提高了性能。

  • 补偿逻辑可自定义:TCC 模型允许在 Confirm 和 Cancel 阶段编写自定义补偿操作,适用于复杂的业务场景。

缺点 ​

  • 复杂性:TCC 模型的实现较为复杂,需要开发者编写 Try、Confirm 和 Cancel 阶段的逻辑。

  • 一致性问题:TCC 模型不能保证强一致性,可能会出现部分提交或部分回滚的情况。

Saga 模型 ​

概述 ​

Saga 模型是一种基于事件驱动的分布式事务处理模型。它将一个长事务分解为多个短事务,每个短事务都有对应的补偿操作。

执行流程 ​

  1. 正向操作:

    • 按顺序执行一系列短事务操作,每个操作都有对应的补偿操作。

    • 如果所有操作都成功,则事务完成。

  2. 补偿操作:

    • 如果某个操作失败,则按相反顺序执行补偿操作,撤销之前已完成的操作。

    • 确保事务回滚到初始状态。

优点 ​

  • 高可用性:Saga 模型通过事件驱动的方式,减少了资源锁定时间,提高了系统的可用性。

  • 补偿逻辑可自定义:Saga 模型允许在每个短事务中定义补偿操作,适用于复杂的业务场景。

缺点 ​

  • 最终一致性:Saga 模型不能保证强一致性,只能保证最终一致性。

  • 复杂性:Saga 模型的实现较为复杂,需要开发者编写每个短事务及其补偿操作的逻辑。

三种模型的适用场景 ​

  • XA 模型:适用于需要强一致性的场景,但性能和可用性较差。

  • TCC 模型:适用于性能要求较高且业务逻辑复杂的场景,但实现复杂。

  • Saga 模型:适用于高可用性和最终一致性的场景,但实现复杂且不能保证强一致性。

安全性与活性:2PC 的问题出在哪 ​

前面三节把 XA / TCC / Saga 并列讲了,但要判断一个协议的好坏需要一把尺子。分布式算法有两条性质:

  • 安全性(safety):坏事不会发生;
  • 活性(liveness):好事最终会发生。

2PC 是安全的(不会把坏数据写进数据库),但它的活性不好:TM 在错误的时点失败,整个事务就阻塞。这是 2PC 最被人诟病的地方,也是后面三节要解决的对象。

2PC 的出处与「必然要三段」这个结论 ​

  • 2PC 由 Jim Gray 在 Notes on Database Operating Systems(1979)里描述。
  • Skeen 在 NonBlocking Commit Protocols(1981)里证明:分布式事务要避免 2PC 的阻塞问题,需要三段提交(3PC)。必要性得到了证明,但一个可用的 3PC 算法迟迟没有出现 —— 用该文的说法,这件事「花了将近 25 年」。

这条结论把问题定了性:阻塞的根源在两阶段的形态本身,不在 2PC 实现得好不好。

事务提交不是拜占庭问题 ​

1986 年,做共识的人和做事务的人开了一次会。当时共识侧最好的算法是拜占庭将军方案,但它对事务来说太贵。Jim Gray 把会议整理成 A Comparison of the Byzantine Agreement Problem and the Transaction Commit Problem(1987),引言里写道:

Prior to the conference, it was widely believed that the transaction commit problem faced by distributed systems is a degenerate form of the Byzantine Generals Problem studied by academe. Perhaps the most useful consequence of the conference was to show that these two problems have little in common.

也就是说:在会议之前大家以为事务提交是拜占庭问题的退化情形,会后发现两者几乎没有共同点。

而事务提交真正对应的共识变种是 uniform consensus(一致共识):所有进程都必须就取值达成一致,包括故障的那些。理由很直接 —— 事务只有在所有 RM 都 prepared 的前提下才允许提交。这与「只要非故障进程达成一致」的普通共识不同,uniform consensus 比普通共识更难(见 Uniform consensus is harder than consensus,2000)。

Paxos 的安全性来自一个简单的交集论证 ​

Paxos 的多数派要求(majority quorum)常被当成一条规则背下来,它背后的推理只有一句话:给定固定的进程数,任意两个多数派必然至少有一个共同进程。

以三个进程 A、B、C 为例,可能的多数派只有 AB、AC、BC 三种。假设在 AB 在场时做出了一个决定,那么将来任意一个多数派在场时,至少有一个进程记得上次的决定:

将来在场的多数派谁记得上次的决定
ABA 与 B 都记得
ACA 记得
BCB 记得

于是旧的决定不可能被后来的多数派推翻。 这就是 Paxos 安全性的来源,也是它不需要依赖时钟的原因。

Paxos 能容忍的故障形态(按该文的列举):消息丢失、延迟、重复、乱序。达成共识的条件是:存在单个 leader 持续足够久,使它能与多数派通信两次。容错范围还包括:

  • 任何进程(包括 leader)都可以失败并重启;
  • 所有进程同时失败过,算法仍然是安全的;
  • 可以同时存在多个 leader(安全性不受影响,只影响活性)。

活性是有条件的:Paxos 是异步算法,没有显式超时,它只在系统表现得同步(消息在有界时间内送达)时才达成共识;否则保持安全但不做决定。存在符合 FLP 结论的病理性场景,但那类场景在实践中容易避开。

Paxos Commit:用 Paxos 让 2PC 的 TM 容错 ​

Lamport 与 Gray 在 Consensus on Transaction Commit(2005)里把 Paxos 用到事务提交上。做法是:

  1. 用 Paxos 复制 2PC 的 TM(TM 不再是单点);
  2. 为每一个参与事务的 RM 起一个 Paxos 实例,用来就「该 RM 能否提交」达成一致。

「每个 RM 一个 Paxos 实例」看起来开销很大,但该文给的计算是:在无故障情形下 Paxos Commit 两个阶段就完成,消息延迟与 2PC 相同(只是消息条数更多)。只有在出现故障时才需要第三阶段 —— 这与上面 Skeen 的结论一致。

容错界是:给定 2n+1 个 TM 副本,可以容忍 n 个副本故障。

有一处容易误解的地方值得单独指出:Paxos Commit 并没有用 Paxos 去直接解 uniform consensus,它是用 Paxos 让系统容错。

那它到底还阻不阻塞:一场带数字的具体争论 ​

这是这一篇材料里最有价值的部分 —— 博客评论区里博主与读者就 Paxos Commit 是否仍然阻塞展开了来回,双方都承认了一部分。

  • 博主的断言:「因为 2PC 会阻塞所以分布式事务不该用」是个空洞的论点,Paxos Commit 已经处理了阻塞问题。
  • 读者的反驳:Paxos Commit 仍然是阻塞协议。若一个 RM 投了 prepare,而网络故障、或 leader 长时间无法与多数派通信两次,这个 RM 会处于阻塞状态。
  • 博主承认的两种阻塞条件:① 可用 acceptor 不足多数派;② 有两个活跃 leader 试图选出不同结果。他同时指出第二种不太可能,因为 Paxos Commit 里任何新 leader 都会试图让 Abort 胜出。
  • 读者补的第三种:RM 投出 yes 之后,若网络断到无法与任何 acceptor 通信,它会无限期不知道事务到底提交还是中止。

争议的落点不在概率,而在状态:prepared 状态下资源提供方可能无限期等待结果,这件事在跨管理域、跨信任域时尤其要紧。

博主随后给了量化:5 个 acceptor、平均无故障时间 120 天、平均修复时间 1 天,则平均到 Paxos 发生阻塞的时间是 160 年。 他也立刻补了一句:这个值是否真的能达到、需要什么条件才达到,才是关键问题。

以上出自 2007 年的一篇博客及其评论区(Mark Mc Keown, Beta Thoughts),未经同行评审。引用到的文献是真实的经典文献,但转述与推理过程未经评审,采信时需要知道这一点。评论区里「160 年」这类数字是博主的估算,文中未给出推导。

用共识视角看 CAP ​

同一篇材料给了一个把 CAP 与共识直接对上的推法,值得记下来作对照(CAP 定理 那篇从 Gilbert-Lynch 的形式化走,这里从 FLP 走):

  1. 把 consistency 等同于 consensus;
  2. 异步系统加一个故障进程 → 由 FLP 可知无法达成共识;
  3. 于是异步系统下不可能同时具备一致性与可用性。

再用三节点的 Paxos 系统 A、B、C 具体看分区:

  • 两个节点可用即可达成共识 —— 也就是一致性与可用性都有;
  • 若 C 被分区,C 无法响应。原因是 C 分不清三种情况:自己被分区了、另外两个节点宕了、还是网络只是很慢;
  • 另外两个节点仍是多数派,可以继续服务。

所以要绕开分区带来的不可用,只能靠工程手段:

  • 数据中心内部:用两张相互独立的网络 —— Paxos 不在意消息重复,所以多路径是安全的;
  • 互联网上:让客户端同时查询全部节点,C 不通就查 A 或 B;
  • 同步网络下另有一条路:C 若在固定时间内收不到消息,可以判定自己被分区,于是主动向客户端声明自己已宕机。

最后这条与 CAP 定理 那篇里 Brewer 的说法正好对上 —— 「检测分区、进入显式的分区模式」是同步模型给的能力,纯异步模型没有。

相关 ​

  • 01-CAP 定理 —— 本篇「用共识视角看 CAP」一节用的是那篇的结论
  • 02-BASE 理论 —— 两种取舍口径同源:一个在定理层,一个在模式层
  • 03-一致性模型 —— 事务隔离(可串行化)与一致性模型是两个正交的轴

参考 ​

  • Mark Mc Keown. A brief history of Consensus, 2PC and Transaction Commit. Beta Thoughts, 2007-06-13.
  • Jim Gray. Notes on Database Operating Systems. 1979.
  • Dale Skeen. NonBlocking Commit Protocols. SIGMOD 1981.
  • Jim Gray. A Comparison of the Byzantine Agreement Problem and the Transaction Commit Problem. 1987.
  • Leslie Lamport, Jim Gray. Consensus on Transaction Commit. ACM TODS 2006(2005 年提交).
  • Bernadette Charron-Bost, André Schiper. Uniform consensus is harder than consensus. 2000.

贡献者 ​

文件历史 ​