2PC 两阶段提交分布式事务
FreeGuideOnline
最新
2026-07-12
text 协调者 参与者A 参与者B | | | |------ prepare -------->| | |------ prepare -------->------------------------| |<----- ready / fail ----| | |<----- ready / fail ----|-----------------------| | | | |------ commit/rollback ->| | |------ commit/rollback ->|---------------------->| |<------- complete -------| | |<------- complete -------|----------------------|
## 2PC 的关键问题与容错机制
### 协调者宕机怎么办?
- 协调者在发出 prepare 之前会**持久化事务日志**,记录当前状态。
- 若在 prepare 之后、commit 之前宕机,恢复后通过日志发现处于“预提交”状态,可向参与者询问确认状态,或直接重试 commit。
- 若参与者未收到 commit 且协调者失联,参与者会**一直阻塞等待**,这是2PC的最大痛点。
### 参与者宕机怎么办?
- 参与者恢复后,根据本地日志判断自己处于 prepare 阶段还是 commit 阶段。
- 如果是 prepare 阶段且未收到协调者最终指令,可以主动询问协调者。
- 如果已经 commit,直接完成。
## 2PC 的优势与劣势
### 优势
- **强一致性**:原子性地保证所有节点事务同时提交或回滚。
- **原理简单**:容易理解,协议清晰。
### 劣势
- **同步阻塞**:在准备阶段,参与者必须锁定资源直至第二阶段结束,期间其他事务无法访问,性能较低。
- **单点故障**:协调者如果永久宕机,参与者会无限期阻塞,系统可能瘫痪。
- **数据不一致风险**:若协调者发送 commit 后宕机,部分参与者收到并提交,部分未收到,会导致数据不一致。(可通过参与者在commit前持久化日志缓解)
- **网络开销大**:至少需要4次消息交互(prepare/回复 + commit/完成)。
## 实际应用场景
- **金融交易**:跨行转账、支付确认等需要绝对一致性的场景。
- **订单与库存**:电商系统中下单扣库存,要求强一致。
- **内部强一致系统**:同业务域内多个数据库的同步。
> 大部分互联网场景因2PC的性能问题,会转而选择**最终一致性方案**(如TCC、Saga、消息队列),只有在强一致性要求极高时才使用2PC。
## 2PC 的简单实现思路
以 X/Open DTP 模型中的 XA 规范为基础,多数数据库支持 XA 接口。例如在 Java 生态中,可使用 JTA 和 Atomikos、Bitronix 等事务管理器。
一个伪代码例子:
```java
// 获取全局事务
TransactionManager tm = ...;
tm.begin();
DataSource inventoryDS = ...;
DataSource orderDS = ...;
try {
Connection conn1 = inventoryDS.getConnection();
// 扣减库存操作 ...
conn1.close();
Connection conn2 = orderDS.getConnection();
// 生成订单操作 ...
conn2.close();
tm.commit();
} catch (Exception e) {
tm.rollback();
}