一、什么是分布式事务?
想象一下,你去银行转账:从A账户转100元到B账户。这个操作需要两步:A账户扣钱,B账户加钱。如果这两步中任何一步失败,整个转账就失败了。在单机系统中,数据库事务可以保证这两步要么都成功,要么都失败。
但在分布式系统中,A账户和B账户可能在不同的服务器上,甚至在不同的数据库里。这时候,传统的单机事务就不管用了,我们需要分布式事务来保证多个服务之间的数据一致性。
二、2PC:最经典的分布式事务方案
2PC(Two-Phase Commit,两阶段提交)是最早的分布式事务解决方案之一。它的核心思想是:先问,再执行。
2PC 的工作流程
- 准备阶段(Prepare Phase):协调者(Coordinator)询问所有参与者(Participants):“你们能执行这个操作吗?”
- 提交阶段(Commit Phase):如果所有参与者都回答“可以”,协调者就通知大家“正式执行”;如果有任何一个参与者说“不行”,协调者就让大家“全部回滚”。
示例(基于Java + MySQL)
// 模拟2PC的协调者
public class TwoPhaseCommit {
public boolean transfer(Account from, Account to, int amount) {
// 第一阶段:询问所有参与者是否可以执行
boolean canCommit = true;
try {
canCommit &= from.prepareDebit(amount); // A账户准备扣款
canCommit &= to.prepareCredit(amount); // B账户准备收款
} catch (Exception e) {
canCommit = false;
}
// 第二阶段:根据第一阶段的反馈决定提交或回滚
if (canCommit) {
from.commit(); // A账户正式扣款
to.commit(); // B账户正式收款
return true;
} else {
from.rollback(); // A账户回滚
to.rollback(); // B账户回滚
return false;
}
}
}
// 模拟账户参与者
class Account {
boolean prepareDebit(int amount) {
// 检查余额是否足够
if (this.balance >= amount) {
this.tempHold = amount; // 临时冻结金额
return true;
}
return false;
}
void commit() {
this.balance -= this.tempHold; // 正式扣款
this.tempHold = 0;
}
void rollback() {
this.tempHold = 0; // 解冻金额
}
}
2PC 的优缺点
优点:
- 实现简单,容易理解。
- 强一致性,适合对数据一致性要求高的场景(如金融系统)。
缺点:
- 同步阻塞:所有参与者必须等待协调者的指令,如果协调者挂了,整个系统可能卡住。
- 单点故障:协调者一旦宕机,事务可能无法完成。
- 性能较低:需要多次网络通信,不适合高并发场景。
三、TCC:更灵活的分布式事务方案
TCC(Try-Confirm-Cancel)是另一种分布式事务方案,它的核心思想是:先预留资源,再确认执行。
TCC 的工作流程
- Try 阶段:尝试执行,预留资源(比如先冻结金额)。
- Confirm 阶段:如果所有Try都成功,就正式提交。
- Cancel 阶段:如果任何Try失败,就取消预留的资源。
示例(基于Java + MySQL)
// 模拟TCC事务
public class TCCTransfer {
public boolean transfer(Account from, Account to, int amount) {
// Try阶段:预留资源
boolean trySuccess = true;
try {
trySuccess &= from.tryDebit(amount); // A账户冻结金额
trySuccess &= to.tryCredit(amount); // B账户预留收款
} catch (Exception e) {
trySuccess = false;
}
// 根据Try阶段的结果决定Confirm或Cancel
if (trySuccess) {
from.confirm(); // A账户正式扣款
to.confirm(); // B账户正式收款
return true;
} else {
from.cancel(); // A账户解冻金额
to.cancel(); // B账户取消预留
return false;
}
}
}
// 模拟TCC账户
class Account {
boolean tryDebit(int amount) {
if (this.balance >= amount) {
this.frozenAmount = amount; // 冻结金额
return true;
}
return false;
}
void confirm() {
this.balance -= this.frozenAmount; // 正式扣款
this.frozenAmount = 0;
}
void cancel() {
this.frozenAmount = 0; // 解冻金额
}
}
TCC 的优缺点
优点:
- 异步化:Try阶段成功后,Confirm/Cancel可以异步执行,提高性能。
- 无阻塞:即使协调者挂了,参与者可以自己超时后执行Cancel。
- 适合高并发:比2PC更轻量,适合互联网业务(如电商、秒杀)。
缺点:
- 业务侵入性强:需要手动编写Try/Confirm/Cancel逻辑。
- 数据一致性稍弱:如果Confirm/Cancel失败,可能需要人工干预。
四、如何选择?2PC 还是 TCC?
| 对比项 | 2PC | TCC |
|---|---|---|
| 一致性 | 强一致性(适合金融) | 最终一致性(适合互联网) |
| 性能 | 较低(同步阻塞) | 较高(异步执行) |
| 复杂度 | 简单(数据库层面支持) | 复杂(需要业务代码配合) |
| 适用场景 | 传统企业级系统(如银行) | 高并发互联网业务(如电商) |
实际场景建议
- 金融支付:用2PC,因为数据不能出错。
- 电商下单:用TCC,因为要支持高并发。
- 混合方案:有些系统会结合两种方案,比如核心交易用2PC,非核心用TCC。
五、总结
分布式事务没有银弹,2PC和TCC各有优劣:
- 2PC 简单但性能低,适合强一致性场景。
- TCC 灵活但实现复杂,适合高并发业务。
选择时,要根据业务需求权衡一致性和性能。
评论