👉 这是一个或许对你有用的社群
🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料:
《项目实战(视频)》:从书中学,往事上“练” 《互联网高频面试题》:面朝简历学习,春暖花开 《架构 x 系统设计》:摧枯拉朽,掌控面试高频场景题 《精进 Java 学习指南》:系统学习,互联网主流技术栈 《必读 Java 源码专栏》:知其然,知其所以然
👉这是一个或许对你有用的开源项目
国产Star破10w的开源项目,前端包括管理后台、微信小程序,后端支持单体、微服务架构
RBAC权限、数据权限、SaaS多租户、商城、支付、工作流、大屏报表、ERP、CRM、AI大模型、IoT物联网等功能:
多模块:https://gitee.com/zhijiantianya/ruoyi-vue-pro 微服务:https://gitee.com/zhijiantianya/yudao-cloud 视频教程:https://doc.iocoder.cn 【国内首批】支持 JDK17/21+SpringBoot3、JDK8/11+Spring Boot2双版本
-
前言 -
1.为什么分布式事务如此棘手? -
2. 常见的解决方案 -
2.1 2PC(两阶段提交) -
2.2 3PC(三阶段提交) -
2.3 TCC(Try-Confirm-Cancel) -
2.4 可靠消息最终一致性 -
2.5 最大努力通知 -
2.6 Seata AT模式 -
2.7 eBay事件队列 -
3.方案的选型指南 -
总结
前言
分布式事务问题,无论在面试,还是工作中经常会遇到。
分布式系统下,数据一致性不再是数据库事务那么简单的。
分布式事务作为其中最复杂的挑战之一,曾让无数团队深夜加班、焦头烂额。
今天这篇文章就跟大家一起聊聊分布式事务问题的7种常见解决方案,希望对你会有所帮助。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/ruoyi-vue-pro 视频教程:https://doc.iocoder.cn/video/
1.为什么分布式事务如此棘手?
在单体应用时代,数据库的ACID事务保证了数据一致性。
但在微服务架构下,一个业务操作需要跨多个服务、多个数据库 ,传统事务模型不再适用。
想象一下电商下单场景:
-
订单服务创建订单(订单数据库) -
库存服务扣减库存(库存数据库) -
支付服务处理支付(支付数据库) -
积分服务增加积分(积分数据库)
这四个操作要么全部成功,要么全部失败 。
这就是分布式事务要解决的核心问题。
那么,如何解决问题呢?
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/yudao-cloud 视频教程:https://doc.iocoder.cn/video/
2. 常见的解决方案
2.1 2PC(两阶段提交)
该方案是强一致性方案。
2PC是最经典的分布式事务协议,通过协调者(Coordinator) 统一调度参与者(Participant) 的执行。
分为两个阶段:
第一阶段:准备阶段 协调者询问所有参与者:“能否提交事务?”
参与者执行本地事务但不提交,锁定资源并回复YES/NO。
// 参与者伪代码
public boolean prepare() {
try {
startTransaction();
executeSql("UPDATE account SET frozen = 100 WHERE id = 1"); // 预留资源
return true; // 返回YES
} catch (Exception e) {
rollback();
return false; // 返回NO
}
}
第二阶段:提交/回滚阶段
-
若所有参与者返回YES,协调者发送commit命令,参与者提交事务 -
若有任一参与者返回NO,协调者发送rollback命令,参与者回滚事务
致命缺陷 :
-
同步阻塞 :所有参与者在prepare后锁定资源,直到收到commit/rollback(高并发下吞吐量骤降) -
单点故障 :协调者宕机导致参与者永久阻塞 -
数据不一致 :网络分区时部分参与者可能提交成功
2.2 3PC(三阶段提交)
该方案也是强一致性方案。
3PC可以解决2PC阻塞问题。
3PC在2PC基础上增加预提交阶段 ,并引入超时机制 :
-
CanCommit阶段 :协调者询问参与者状态(不锁定资源) -
PreCommit阶段 :参与者锁定资源并执行SQL(不提交) -
DoCommit阶段 :正式提交
改进点 :
-
参与者超时未收到命令自动提交(降低阻塞风险) -
预提交阶段发现异常可提前终止
但依然存在问题 :
-
网络分区时仍可能数据不一致 -
实现复杂度显著增加
2.3 TCC(Try-Confirm-Cancel)
该方案是最终一致性方案。
它是业务层面的2PC。
TCC将业务逻辑拆分为三个阶段:
-
Try :预留资源(如冻结库存) -
Confirm :确认操作(正式扣减库存) -
Cancel :释放资源(解冻库存)
// 积分服务TCC实现
publicclass PointsService {
@Transactional
public boolean tryDeductPoints(Long userId, int points) {
// 检查用户积分是否充足
UserPoints user = userPointsDao.selectForUpdate(userId);
if (user.getAvailable() < points) {
thrownew InsufficientPointsException();
}
// 冻结积分
userPointsDao.freeze(userId, points);
}
public boolean confirmDeductPoints(Long userId, int points) {
// 实际扣减冻结积分
userPointsDao.confirmDeduct(userId, points);
}
public boolean cancelDeductPoints(Long userId, int points) {
// 释放冻结积分
userPointsDao.unfreeze(userId, points);
}
}
执行流程 :
-
主业务调用所有服务的try方法 -
全部try成功则调用confirm;任一try失败则调用cancel
优势 :
-
无全局锁 :只在try阶段锁定局部资源 -
高可用 :协调者可集群部署
挑战 :
-
需手动实现回滚逻辑 (业务侵入性强) -
所有服务需提供三种接口
金融核心系统首选:某银行跨境支付系统采用TCC方案,日均处理200万笔交易,跨5个服务的事务成功率99.99%
2.4 可靠消息最终一致性
该方案也是最终一致性方案。
可以使用RocketMQ的事务消息。
RocketMQ的事务消息完美解决本地操作与消息发送的一致性 问题:
关键步骤 :
-
发送half消息(对消费者不可见) -
执行本地事务 -
根据本地事务结果commit/rollback -
MQ定时回查未决事务
示例代码 :
// 订单服务使用事务消息
publicclass OrderService {
@Autowired
private RocketMQTemplate rocketMQTemplate;
public void createOrder(Order order) {
// 1. 发送half消息
Message msg = MessageBuilder.withPayload(order).build();
TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction(
"order_topic", msg, null);
// 2. 执行本地事务(在TransactionListener中实现)
}
}
// 事务监听器
@RocketMQTransactionListener
class OrderTransactionListener implements RocketMQLocalTransactionListener {
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
try {
Order order = (Order) msg.getPayload();
orderDao.save(order); // 本地事务
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e) {
return RocketMQLocalTransactionState.ROLLBACK;
}
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
// 回查逻辑
return checkOrderStatus(msg);
}
}
2.5 最大努力通知
该方案是弱一致性方案。
适用于对实时性要求低 的场景(如短信通知):
-
业务主流程完成后发送通知 -
失败后按策略重试(如间隔1min、5min、10min) -
达到阈值后人工干预
// 最大努力通知服务
publicclass BestEffortNotifier {
privatestaticfinalint[] RETRY_INTERVALS = {1, 5, 10, 30, 60}; // 分钟
public void notify(String event) {
int retryCount = 0;
while (retryCount < RETRY_INTERVALS.length) {
try {
if (sendNotification(event)) {
return; // 通知成功
}
} catch (Exception e) {
// 记录日志
}
Thread.sleep(RETRY_INTERVALS[retryCount] * 60 * 1000);
retryCount++;
}
alertManualIntervention(event); // 人工介入
}
}
实战经验:支付回调采用此方案,重试8次跨12小时,99.5%的通知在30分钟内成功
2.6 Seata AT模式
该方案是自动化的TCC。
Seata的AT(Auto Transaction)模式 在不侵入业务代码 的前提下实现分布式事务:
核心机制 :
-
全局锁 :TC(事务协调器)管理内存级全局锁(替代数据库行锁) -
SQL代理 :解析业务SQL自动生成回滚日志 -
二阶段异步提交 :极大提升吞吐量
/* 原始SQL */
UPDATE product SET stock = stock - 10 WHERE id = 1001;
/* Seata自动记录回滚日志 */
INSERT INTO undo_log (branch_id, xid,
before_image, after_image)
VALUES (?, ?,
'{"stock":100}', -- 更新前值
'{"stock":90}'); -- 更新后值
性能对比 :
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
局限 :
-
不支持嵌套事务 -
热点数据更新冲突率高
2.7 eBay事件队列
该方案是基于本地事务的最终一致性方案。
eBay提出的经典方案:
-
将分布式操作拆分为本地事务+异步事件 -
使用事件表 确保事件不丢失 -
通过补偿机制 解决失败场景
-- 订单服务数据库
BEGIN TRANSACTION;
-- 1. 创建订单
INSERT INTO orders (...) VALUES (...);
-- 2. 记录事件(与订单在同一个事务)
INSERT INTO event_queue (event_type, payload, status)
VALUES ('ORDER_CREATED', '{"orderId":1001}', 'PENDING');
COMMIT;
-- 定时任务扫描事件表并发布
该方案在早期eBay系统中每天处理1亿+事件,保证核心交易链路最终一致
3.方案的选型指南
根据业务场景选择合适方案:
|
|
|
|
|
|
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
黄金法则 :
-
强一致性需求 :选择2PC/ZooKeeper(牺牲性能) -
高并发场景 :选择可靠消息/Seata AT(最终一致) -
弱一致性场景 :最大努力通知(成本最低)
总结
经过十年演进,分布式事务解决方案已从强一致性 向高性能最终一致性 发展。
技术没有绝对的好坏,只有适合与否。
我曾见过团队为了追求理论上的强一致性,把系统搞得复杂不堪;也见过过度追求性能导致资金损失的血泪教训。
分布式事务的本质,是在业务需求与技术可行性之间找到平衡点。
致开发者 :不必追求完美的分布式事务解决方案,适合业务场景的才是最好的 。
在设计时多问自己:
-
业务能容忍多长时间不一致? -
事务失败后如何补偿? -
是否有完善的监控和人工介入机制?
愿你在分布式系统的海洋中,乘风破浪,游刃有余。
欢迎加入我的知识星球,全面提升技术能力。
👉 加入方式,“长按”或“扫描”下方二维码噢:
星球的内容包括:项目实战、面试招聘、源码解析、学习路线。



文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)

