云计算百科
云计算领域专业知识百科平台

2PC / XA——强一致分布式事务的基础模型

2PC / XA——强一致分布式事务的基础模型

  • 先从问题开始:为什么不能直接提交?
  • 2PC 是什么?
  • 第一阶段:Prepare
  • Prepare 到底意味着什么?
  • 第二阶段:Commit
  • 如果有人 Prepare 失败呢?
  • 完整流程
  • 为什么一定需要两阶段?
  • 2PC 最大的问题:锁资源
  • 举个高并发场景
  • 协调者挂了怎么办?
  • 第二阶段消息丢了也会麻烦
  • 2PC 的核心缺点
  • 那 2PC 有没有优点?
  • XA 和 2PC 是什么关系?
  • XA 的基本思想
  • MySQL 里的 XA
  • Seata XA 又是什么?
  • Seata XA 的特点
  • 2PC 和本地事务有什么本质区别?
  • 为什么 2PC 不适合长事务?
  • 2PC 和 TCC 有什么直觉区别?
  • 面试题:
    • 2PC 为什么是阻塞协议?
    • 2PC 能绝对保证一致性吗?
    • XA 和 2PC 有什么区别?
  • 把整个知识链串起来
  • 本篇博文必须记住的 8 个结论

上一篇:《ACID、CAP、BASE,以及强一致性和最终一致性》 下一篇:《TCC——业务层面的分布式事务》

本篇开始进入 2PC / XA——强一致分布式事务的基础模型。

需要搞懂的不是“背两阶段流程”,而是:

为什么需要两个阶段、Prepare 到底干了什么、为什么会锁资源、协调者挂了会怎样,以及 XA 和 2PC 的关系。

先从问题开始:为什么不能直接提交?

假设一个转账业务涉及两个数据库:

DB1:A 账户 -100
DB2:B 账户 +100

最直接的做法:

先提交 DB1
再提交 DB2

问题来了:

DB1 COMMIT 成功 ✅
DB2 COMMIT 失败 ❌

结果:

A -100
B 没 +100

业务不一致。

所以我们希望:

在真正提交之前,先确认所有参与者都“准备好了”。

这就是 2PC 的核心思想。


2PC 是什么?

2PC,全称:

Two-Phase Commit

中文:

两阶段提交。

参与角色主要有两个:

Coordinator
协调者

Participant
参与者

例如:

Coordinator

┌──────────┴──────────┐
↓ ↓
Participant A Participant B
DB1 DB2

协调者负责:

询问
决定
通知

参与者负责:

执行本地事务
准备提交
最终提交 / 回滚


第一阶段:Prepare

第一阶段不是正式提交。

而是:

先执行事务,但暂时不要最终提交。

例如:

Coordinator

├── Prepare → DB1
└── Prepare → DB2

DB1:

A账户 -100

DB2:

B账户 +100

但此时:

还没有最终 COMMIT

参与者会告诉协调者:

DB1:我准备好了
DB2:我也准备好了

也就是:

YES
YES


Prepare 到底意味着什么?

这是本篇博文最关键的点。

Prepare 不是简单说一句:

“我可以”

而是通常意味着:

我已经把事务执行到一个“只差最后提交”的状态。

也就是说:

业务 SQL 已经执行
日志已经持久化
需要的锁还持有着

例如:

UPDATE account
SET balance = balance 100
WHERE id = 1;

这条 SQL 已经执行。

但:

事务还没有最终结束

所以资源通常仍然被锁住。


第二阶段:Commit

如果所有参与者都回答:

YES

协调者决定:

全局提交

然后:

Coordinator

├── Commit → DB1
└── Commit → DB2

最终:

DB1 COMMIT
DB2 COMMIT

事务完成。


如果有人 Prepare 失败呢?

例如:

DB1:YES
DB2:NO

可能 DB2 因为:

余额不足
SQL 执行失败
死锁
数据库异常

无法进入 Prepared 状态。

协调者就会通知:

ROLLBACK

于是:

Coordinator

├── Rollback → DB1
└── Rollback → DB2

最终:

大家都不提交

所以 2PC 追求的是:

要么一起 Commit
要么一起 Rollback


完整流程

正常提交: 在这里插入图片描述

失败:

在这里插入图片描述


为什么一定需要两阶段?

因为协调者必须先回答一个问题:

所有人都具备提交条件了吗?

如果不做 Prepare:

DB1 COMMIT

DB2 COMMIT

DB1 一旦提交,就不能轻易撤销。

而 Prepare 的价值就是:

先不要真正提交

所有人先进入“可提交状态”

再统一决定

所以你可以把 2PC 理解成:

第一阶段:大家都准备好了吗?

第二阶段:既然都准备好了,那一起提交


2PC 最大的问题:锁资源

现在来看它为什么性能不好。

假设 DB1 执行:

UPDATE account
SET balance = balance 100
WHERE id = 1;

在 Prepare 后:

事务不能结束

因为它还在等待协调者最终决定。

于是可能一直持有:

行锁
表锁
事务资源
连接

这时候另一个请求也想修改这个账户:

Transaction B

它可能只能:

等待……

所以:

Prepare

等待协调者

资源持续被占用

并发下降

这就是 2PC 很大的代价。


举个高并发场景

某热门商品库存:

stock = 100

大量用户同时抢购。

如果每一个请求都进入分布式 2PC:

锁库存

Prepare

等待其他服务

支付 Prepare

订单 Prepare

统一 Commit

库存锁可能持有很长时间。

结果:

吞吐量下降
请求等待
超时增加
锁竞争严重

所以:

2PC 的一致性很强,但协调成本和锁资源成本也很高。


协调者挂了怎么办?

这是经典问题。

假设:

DB1 已 Prepare
DB2 已 Prepare

它们都在等待:

Commit?
还是 Rollback?

就在这时:

Coordinator 崩了

参与者不知道最终决定。

于是:

DB1:我到底提交不提交?
DB2:我也不知道。

这就是 2PC 中经典的:

阻塞问题。

参与者可能必须继续保持 Prepared 状态。

也意味着:

锁不能释放
资源不能释放

一直等协调者恢复。


第二阶段消息丢了也会麻烦

假设:

Coordinator 决定 Commit

发送:

Commit → DB1
Commit → DB2

结果:

DB1 收到 ✅
DB2 没收到 ❌

那么:

DB1 已提交
DB2 仍在 Prepared

DB2 不知道:

到底该提交还是回滚

最终往往需要:

恢复
重试
状态查询
日志判断

所以分布式事务不是一句:

“加个协调器”

就解决了。


2PC 的核心缺点

你可以直接记成 4 个:

1. 同步阻塞
2. 资源锁定时间长
3. 协调者故障影响大
4. 网络异常会产生不确定状态

再加一个工程层面:

5. 性能和吞吐通常较差


那 2PC 有没有优点?

当然有。

最大优点:

一致性强

特别适合:

对一致性要求非常高
参与资源比较有限
并发压力不算特别高
事务时间较短

的场景。

例如:

传统金融核心交易
企业内部系统
强一致数据同步

但不能简单理解成:

金融 = 一定 2PC

实际金融系统也大量使用:

账务
消息
补偿
对账
幂等

共同保证业务一致性。


XA 和 2PC 是什么关系?

这是面试高频问题。

先记一句:

2PC 是一种协议思想,XA 是一种标准接口规范。

2PC 讲的是:

Prepare
Commit / Rollback

而 XA 解决的是:

不同事务资源怎么按照统一接口参与这种分布式事务?

XA 最早由 X/Open 提出。

一个典型 XA 架构:

Application


Transaction Manager

├── XA Resource → MySQL
└── XA Resource → Oracle

其中:

TM:Transaction Manager
事务管理器

RM:Resource Manager
资源管理器

数据库可以作为 RM。


XA 的基本思想

事务管理器:

TM

负责控制全局事务。

多个数据库:

RM1
RM2
RM3

分别加入同一个全局事务。

然后 TM 使用 XA 接口:

XA START
XA END
XA PREPARE
XA COMMIT
XA ROLLBACK

控制参与者。

因此:

XA

标准化接口

2PC

核心提交协议

你可以理解为:

XA 是 2PC 在数据库事务资源上的一种标准化实现方式。


MySQL 里的 XA

MySQL 支持 XA 事务。

概念上可以这样理解:

XA START 'xid';

UPDATE account
SET balance = balance 100
WHERE id = 1;

XA END 'xid';

XA PREPARE 'xid';

这时事务进入:

Prepared

最后由事务管理器决定:

XA COMMIT 'xid';

或者:

XA ROLLBACK 'xid';

实际开发中一般不会手动这样写,而是由:

事务管理器
框架
中间件

帮你处理。


Seata XA 又是什么?

Seata 里也有 XA 模式。

可以粗略理解成:

应用


Seata TC

├── MySQL XA
├── MySQL XA
└── MySQL XA

其中:

TC = Transaction Coordinator
TM = Transaction Manager
RM = Resource Manager

Seata TC 负责协调全局事务。

各数据库使用 XA 能力参与。


Seata XA 的特点

优点:

强一致
利用数据库原生 XA 能力
业务侵入相对较低

缺点:

Prepare 阶段会锁资源
性能受影响
依赖数据库 XA 支持
长事务不适合

所以:

Seata XA

并没有从根本上消除 2PC 的特点。

它只是:

帮你更方便地管理和协调 XA 两阶段事务。


2PC 和本地事务有什么本质区别?

本地事务:

一个事务管理器

一个数据库资源

2PC:

一个全局协调者

多个事务资源

本地事务:

BEGIN
SQL
COMMIT

2PC:

多个数据库分别执行

全部 Prepare

全局统一 Commit / Rollback


为什么 2PC 不适合长事务?

假设业务:

用户下单

酒店预订

机票预订

租车

保险

支付

整个流程可能几十秒,甚至几分钟。

如果都使用 2PC:

酒店数据库锁着
机票数据库锁着
租车数据库锁着
支付数据库锁着

等待:

所有业务完成

这个代价非常高。

所以长事务通常更适合:

Saga

后面会专门讲解 Saga。


2PC 和 TCC 有什么直觉区别?

现在先建立一个直觉。

2PC:

数据库层面
Prepare
Commit
Rollback

TCC:

业务层面
Try
Confirm
Cancel

比如扣款。

2PC:

数据库 UPDATE

事务锁住

等待 Commit

TCC:

Try:
把 100 元变成“冻结状态”

Confirm:
正式扣除

Cancel:
释放冻结

TCC 不一定长时间持有数据库锁。

所以 TCC 用:

业务资源冻结

换取:

数据库锁持有时间更短

代价是:

业务代码复杂很多

这就是为什么后面会出现 TCC。


面试题:

2PC 为什么是阻塞协议?

答题思路:

在第一阶段,参与者完成本地事务并进入 Prepared 状态后,需要等待协调者的第二阶段决策。在等待期间通常需要持有事务资源和锁,因此如果协调者迟迟没有发送 Commit 或 Rollback,参与者就无法独立结束事务,会产生阻塞。

这句话基本就是标准回答。


2PC 能绝对保证一致性吗?

不要简单回答:

更好的回答是:

2PC 设计目标是保证原子提交,但在真实分布式系统中仍需要处理协调者故障、消息丢失、网络分区、节点恢复等异常,因此工程上依赖日志、恢复机制、重试和状态查询来维持事务一致性。

这样更准确。


XA 和 2PC 有什么区别?

可以这样回答:

2PC 是一种分布式原子提交协议,定义了 Prepare 和 Commit/Rollback 两个阶段;XA 是 X/Open 定义的分布式事务接口规范,用于让事务管理器统一协调不同资源管理器。XA 通常通过两阶段提交完成全局事务。

这是非常常见的一道题。


把整个知识链串起来

现在我们的知识已经变成:

本地事务

ACID

跨数据库

出现一致性问题

需要协调

2PC

Phase 1:Prepare

Phase 2:Commit / Rollback

获得较强一致性

代价:
锁资源
阻塞
性能下降
协调者故障

于是继续出现
TCC / Saga / MQ 最终一致性

你会发现:

后面的分布式事务方案,本质上很多都是在解决 2PC 太“重”的问题。


本篇博文必须记住的 8 个结论

  • 2PC = 两阶段提交。
  • 第一阶段是 Prepare,不是最终提交。
  • Prepare 后,参与者通常已经执行了业务 SQL,并持有事务资源。
  • 所有参与者 Prepare 成功后,协调者才统一 Commit。
  • 任一参与者 Prepare 失败,则整体 Rollback。
  • 2PC 的核心问题是阻塞、锁时间长、协调成本高。
  • XA 是接口规范,2PC 是提交协议。
  • Seata XA 本质上仍然属于基于数据库 XA 能力的强一致事务方案。
  • 下一篇博文将直接进入 TCC。

    因为你现在已经知道 2PC 最大的问题:

    Prepare 后资源一直锁着

    那么 TCC 要解决的问题就是:

    能不能不用长时间锁数据库资源,而是由业务自己先“预留资源”?

    下一篇我会重点讲:

    Try 到底做什么
    Confirm 怎么设计
    Cancel 怎么设计
    为什么必须幂等
    什么是空回滚
    什么是悬挂
    TCC 怎么设计账户扣款
    TCC 为什么比 2PC 性能更高
    TCC 又为什么开发成本更高

    上一篇:《ACID、CAP、BASE,以及强一致性和最终一致性》 下一篇:《TCC——业务层面的分布式事务》


    若有转载,请标明出处:https://blog.csdn.net/CharlesYuangc/article/details/165342002

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 2PC / XA——强一致分布式事务的基础模型
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!