当前位置: 首页 > article >正文

分布式事务解决方案:Saga/TCC/消息队列——面试必问的分布式事务,你真的懂吗?

一、问题现场还原那是一个双11大促的日子小王所在的电商公司系统架构是这样的用户下单 ↓ 订单服务 → 扣减库存 → 支付服务 → 发货 → 增加积分 ↓ ↓ ↓ ↓ ↓ 订单库 库存库 支付库 物流库 积分库问题场景用户支付成功后库存扣减了但积分增加失败了1. 订单服务订单创建成功 ✓ 2. 库存服务库存扣减成功 ✓ 3. 支付服务支付成功 ✓ 4. 积分服务积分增加失败 ✗ 5. 结果用户付了钱但没有得到积分要投诉小王一开始想用Transactional解决但很快就发现// ❌ 本地事务无法解决分布式事务问题 Transactional public void placeOrder(Order order) { orderService.createOrder(order); // 订单库 inventoryService.decreaseStock(); // 库存库另一个服务 paymentService.processPayment(); // 支付库另一个服务 pointService.increasePoints(); // 积分库另一个服务 }为什么不行每个服务调用不同的数据库Transactional只能保证单个数据库的ACID无法跨多个数据库保证一致性二、分布式事务的核心挑战2.1 CAP理论C (Consistency): 一致性——所有节点数据同时成功或失败 A (Availability): 可用性——系统一直可用 P (Partition Tolerance): 分区容错性——网络故障时系统仍能运行 分布式系统中P是必须的所以只能选择CP或AP - CP保证一致性牺牲可用性如传统2PC - AP保证可用性牺牲一致性如消息最终一致性2.2 分布式事务分类类型一致性性能复杂度适用场景2PC/XA强一致性低中对一致性要求高的场景TCC最终一致性中高对性能有一定要求的场景Saga最终一致性高中业务流程较长的场景消息队列最终一致性高低允许延迟一致的场景三、解决方案一TCC模式3.1 TCC核心思想TCC Try尝试 Confirm确认 Cancel取消 Try阶段 - 资源检查和预留 - 锁定资源但不完成业务 Confirm阶段 - Try阶段成功后执行 - 完成实际业务操作 - 提交事务 Cancel阶段 - Try阶段成功后后续步骤失败 - 回滚Try阶段预留的资源 - 取消事务3.2 TCC实战案例场景用户下单扣减库存Service public class InventoryServiceTCC { /** * Try阶段预留库存 */ Transactional public void tryDecreaseStock(Long productId, Integer count) { // 1. 检查库存是否充足 Inventory inventory inventoryMapper.selectByProductId(productId); if (inventory.getAvailable() count) { throw new RuntimeException(库存不足); } // 2. 冻结库存不真正扣减 int frozen inventoryMapper.frozenStock(productId, count); if (frozen 0) { throw new RuntimeException(库存冻结失败); } // 3. 记录TCC事务日志 TccTransactionLog log new TccTransactionLog(); log.setTransactionId(UUID.randomUUID().toString()); log.setProductId(productId); log.setCount(count); log.setStatus(TRY); tccMapper.insert(log); } /** * Confirm阶段确认扣减库存 */ Transactional public void confirmDecreaseStock(String transactionId) { // 1. 获取事务日志 TccTransactionLog log tccMapper.selectByTransactionId(transactionId); if (log null || !TRY.equals(log.getStatus())) { throw new RuntimeException(事务状态异常); } // 2. 真正扣减库存 inventoryMapper.decreaseFrozenStock(log.getProductId(), log.getCount()); // 3. 更新事务日志 log.setStatus(CONFIRM); tccMapper.updateStatus(log); } /** * Cancel阶段取消扣减库存 */ Transactional public void cancelDecreaseStock(String transactionId) { // 1. 获取事务日志 TccTransactionLog log tccMapper.selectByTransactionId(transactionId); if (log null) { return; // 幂等性没有Try记录直接返回 } if (!TRY.equals(log.getStatus())) { return; // 幂等性已经确认或取消过直接返回 } // 2. 释放冻结库存 inventoryMapper.releaseFrozenStock(log.getProductId(), log.getCount()); // 3. 更新事务日志 log.setStatus(CANCEL); tccMapper.updateStatus(log); } }3.3 TCC优缺点优点 ✅ 强一致性最终一致性 ✅ 性能优于2PC ✅ 适合高并发场景 缺点 ❌ 代码侵入性强每个业务都要写三个方法 ❌ 开发成本高 ❌ 需要处理幂等性、空回滚、悬挂等异常情况四、解决方案二Saga模式4.1 Saga核心思想Saga 将长事务拆分为多个本地事务 每个本地事务都有对应的补偿操作 正常流程 T1 → T2 → T3 → T4 → T5 全部成功 ✓ 异常流程 T1 → T2 → T3 → T4 ✗ 执行补偿 C3 ← C2 ← C1 回滚4.2 Saga实战案例场景订单处理流程/** * 订单Saga编排 */ Service public class OrderSagaService { Autowired private OrderService orderService; Autowired private InventoryService inventoryService; Autowired private PaymentService paymentService; Autowired private PointService pointService; /** * 正向流程执行所有步骤 */ Transactional public void executeSaga(Order order) { String sagaId UUID.randomUUID().toString(); try { // 步骤1创建订单 SagaStep step1 createOrder(order, sagaId); // 步骤2扣减库存 SagaStep step2 decreaseInventory(order, sagaId); // 步骤3处理支付 SagaStep step3 processPayment(order, sagaId); // 步骤4增加积分 SagaStep step4 increasePoints(order, sagaId); // 更新Saga状态为成功 updateSagaStatus(sagaId, COMPLETED); } catch (Exception e) { // 执行补偿流程 compensateSaga(sagaId, e); throw new RuntimeException(订单处理失败, e); } } /** * 补偿流程反向执行补偿操作 */ Transactional public void compensateSaga(String sagaId, Exception e) { log.error(Saga执行失败开始补偿sagaId{}, sagaId); // 获取所有已完成的步骤 ListSagaStep completedSteps sagaStepMapper.selectCompletedSteps(sagaId); // 按执行顺序反向补偿 Collections.reverse(completedSteps); for (SagaStep step : completedSteps) { try { switch (step.getStepName()) { case createOrder: orderService.cancelOrder(step.getBusinessId()); break; case decreaseInventory: inventoryService.restoreInventory(step.getBusinessId()); break; case processPayment: paymentService.refund(step.getBusinessId()); break; case increasePoints: pointService.decreasePoints(step.getBusinessId()); break; } // 更新步骤状态为已补偿 step.setStatus(COMPENSATED); sagaStepMapper.updateStatus(step); } catch (Exception ex) { log.error(补偿失败step{}, step, ex); // 补偿失败需要人工介入 alertService.sendAlert(Saga补偿失败 step.getStepName()); } } // 更新Saga状态为已补偿 updateSagaStatus(sagaId, COMPENSATED); } private SagaStep createOrder(Order order, String sagaId) { orderService.createOrder(order); SagaStep step new SagaStep(); step.setSagaId(sagaId); step.setStepName(createOrder); step.setBusinessId(order.getId()); step.setStatus(COMPLETED); sagaStepMapper.insert(step); return step; } private SagaStep decreaseInventory(Order order, String sagaId) { inventoryService.decreaseInventory(order.getProductId(), order.getQuantity()); SagaStep step new SagaStep(); step.setSagaId(sagaId); step.setStepName(decreaseInventory); step.setBusinessId(order.getId()); step.setStatus(COMPLETED); sagaStepMapper.insert(step); return step; } // ... 其他步骤类似 }4.3 Saga优缺点优点 ✅ 性能高不需要等待所有参与者 ✅ 适合长事务场景 ✅ 代码侵入性相对较小 缺点 ❌ 最终一致性不是强一致性 ❌ 补偿逻辑复杂 ❌ 无法保证原子性可能出现部分成功部分失败五、解决方案三消息队列推荐5.1 消息队列核心思想基于可靠消息的最终一致性 流程 1. 本地事务执行 发送消息原子性 2. 消息队列保证消息不丢失 3. 消费者重试机制 4. 死信队列处理失败消息5.2 RocketMQ事务消息实战/** * 基于RocketMQ事务消息的分布式事务 */ Service public class OrderTransactionMQService { Autowired private RocketMQTemplate rocketMQTemplate; Autowired private OrderMapper orderMapper; /** * 发送事务消息 */ public void placeOrderWithTransaction(Order order) { // 构建消息 MessageOrder message MessageBuilder.withPayload(order).build(); // 发送事务消息 // 参数1Topic // 参数2消息内容 // 参数3事务监听器 rocketMQTemplate.sendMessageInTransaction( order-topic, message, new OrderTransactionListener() ); } } /** * 事务消息监听器 */ RocketMQTransactionListener public class OrderTransactionListener implements RocketMQLocalTransactionListener { Autowired private OrderMapper orderMapper; Autowired private InventoryService inventoryService; /** * 执行本地事务 */ Override Transactional public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) { try { Order order (Order) msg.getPayload(); // 1. 创建订单本地事务 orderMapper.insert(order); // 2. 扣减库存远程调用 inventoryService.decreaseInventory(order.getProductId(), order.getQuantity()); // 本地事务成功返回COMMIT消息会被消费 return RocketMQLocalTransactionState.COMMIT; } catch (Exception e) { log.error(本地事务执行失败, e); // 本地事务失败返回ROLLBACK消息会被删除 return RocketMQLocalTransactionState.ROLLBACK; } } /** * 检查本地事务状态 * (MQ如果长时间没收到回执会调用这个方法检查) */ Override public RocketMQLocalTransactionState checkLocalTransaction(Message msg) { Order order (Order) msg.getPayload(); // 检查订单是否存在 Order existingOrder orderMapper.selectById(order.getId()); if (existingOrder ! null) { // 订单已创建返回COMMIT消息会被消费 return RocketMQLocalTransactionState.COMMIT; } else { // 订单未创建返回ROLLBACK消息会被删除 return RocketMQLocalTransactionState.ROLLBACK; } } } /** * 消息消费者异步处理积分 */ RocketMQMessageListener(topic order-topic, consumerGroup point-consumer) public class OrderPointConsumer implements RocketMQListenerOrder { Autowired private PointService pointService; Override public void onMessage(Order order) { try { // 增加积分 pointService.increasePoints(order.getUserId(), order.getAmount()); } catch (Exception e) { log.error(增加积分失败, e); // 抛出异常MQ会自动重试 throw e; } } }5.3 消息队列优缺点优点 ✅ 性能高异步处理 ✅ 容错性强消息重试、死信队列 ✅ 代码侵入性小 ✅ 最终一致性 缺点 ❌ 最终一致性不是强一致性 ❌ 依赖消息队列可靠性 ❌ 消息延迟六、三种方案对比维度TCCSaga消息队列一致性强最终最终性能中高高复杂度高中低代码侵入强中弱适用场景对一致性要求高长事务允许延迟一致七、选型建议选择TCC ✅ 对一致性要求高如金融交易 ✅ 涉及金额较大的场景 ✅ 开发团队技术能力强 选择Saga ✅ 业务流程较长如审批流程 ✅ 可以接受最终一致性 ✅ 需要快速交付 选择消息队列 ✅ 对延迟不敏感如积分、通知 ✅ 高并发场景 ✅ 团队技术能力一般八、总结今天我们学到了要点说明分布式事务问题跨多个数据库的数据一致性TCC模式Try-Confirm-Cancel强一致性Saga模式正向执行反向补偿最终一致性消息队列异步处理重试机制最终一致性选型建议根据一致性要求、性能、复杂度选择今日互动你的项目中遇到过分布式事务问题吗是用什么方案解决的

相关文章:

分布式事务解决方案:Saga/TCC/消息队列——面试必问的分布式事务,你真的懂吗?

一、问题现场还原 那是一个双11大促的日子,小王所在的电商公司系统架构是这样的: 用户下单↓ 订单服务 → 扣减库存 → 支付服务 → 发货 → 增加积分↓ ↓ ↓ ↓ ↓ 订单库 库存库 支付库 物流库 …...

Python音频信号处理:从基础到实战应用

1. Python音频信号处理基础与生态音频信号处理作为数字信号处理(DSP)的重要分支,涵盖了从基础的声音采集到复杂的音乐信息分析等广泛领域。作为一名长期从事音频算法开发的工程师,我见证了Python如何从最初的脚本语言成长为如今音频处理领域不可或缺的工…...

5分钟掌握:免费开源AI语音修复工具VoiceFixer终极指南

5分钟掌握:免费开源AI语音修复工具VoiceFixer终极指南 【免费下载链接】voicefixer General Speech Restoration 项目地址: https://gitcode.com/gh_mirrors/vo/voicefixer 还在为录音中的杂音、失真而烦恼吗?无论是会议录音、播客制作还是老式录…...

浏览器中的游戏资源解锁器:RPG Maker MV/MZ 解密工具终极指南

浏览器中的游戏资源解锁器:RPG Maker MV/MZ 解密工具终极指南 【免费下载链接】RPG-Maker-MV-Decrypter You can decrypt RPG-Maker-MV Resource Files with this project ~ If you dont wanna download it, you can use the Script on my HP: 项目地址: https://…...

2025届学术党必备的AI辅助论文方案推荐

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 用于降低文本重复率的在线服务平台,是降重网站之所为,其主要服务的领…...

3大核心问题深度解析:PMX到VRM转换的终极解决方案

3大核心问题深度解析:PMX到VRM转换的终极解决方案 【免费下载链接】VRM-Addon-for-Blender VRM Importer, Exporter and Utilities for Blender 2.93 to 5.1 项目地址: https://gitcode.com/gh_mirrors/vr/VRM-Addon-for-Blender 面对PMX到VRM模型转换中的骨…...

从压力导丝到AI计算:一文看懂FFR(冠状动脉血流储备分数)的技术演进与未来

从压力导丝到AI计算:冠状动脉血流储备分数的技术革命与临床突破 在心血管介入领域,没有哪个生理学参数像FFR(冠状动脉血流储备分数)这样彻底改变了临床决策路径。1993年荷兰学者Nico Pijls首次提出这个概念时,可能未曾…...

AI发展,软件开发到底该怎么搞?

当生成式AI全面渗透研发全流程,代码自动生成、智能调试、架构优化成为常态,软件开发的底层逻辑已被彻底重构。过去,企业做信息化、做软件,离不开庞大的研发团队、漫长的交付周期与高昂的人力成本;如今,AI让…...

8大网盘直链下载助手终极指南:告别限速,实现全速下载

8大网盘直链下载助手终极指南:告别限速,实现全速下载 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云…...

Jellyfin元数据终极指南:如何用MetaShark插件打造完美中文媒体库

Jellyfin元数据终极指南:如何用MetaShark插件打造完美中文媒体库 【免费下载链接】jellyfin-plugin-metashark jellyfin电影元数据插件 项目地址: https://gitcode.com/gh_mirrors/je/jellyfin-plugin-metashark 你是否曾为Jellyfin媒体库中混乱的电影信息而…...

5步恢复B站经典界面:Bilibili-Old完整实施手册

5步恢复B站经典界面:Bilibili-Old完整实施手册 【免费下载链接】Bilibili-Old 恢复旧版Bilibili页面,为了那些念旧的人。 项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Old 你是否厌倦了B站新版界面的复杂设计?每次打开视频…...

5个技巧让foobar2000歌词体验升级:ESLyric-LyricsSource完全指南

5个技巧让foobar2000歌词体验升级:ESLyric-LyricsSource完全指南 【免费下载链接】ESLyric-LyricsSource Advanced lyrics source for ESLyric in foobar2000 项目地址: https://gitcode.com/gh_mirrors/es/ESLyric-LyricsSource 想让你的foobar2000播放器拥…...

别再暴力解压了!用python-docx库精准提取Word文档内嵌图片(附源码)

用python-docx精准提取Word文档图片的工程实践 在文档自动化处理领域,Word文档中的图片提取是个高频需求。许多开发者第一反应是用zipfile解压.docx文件,然后在解压后的文件夹中寻找图片资源。这种方法看似直接,实则存在严重缺陷——你无法确…...

AI模型在.NET 11中推理速度不升反降?这5个被90%开发者忽略的JIT编译器配置,让吞吐量提升3.8倍!

第一章:AI模型在.NET 11中推理性能异常的典型现象与根因定位在 .NET 11 首次集成原生 ONNX Runtime 1.18 和 ML.NET 4.0 后,开发者普遍反馈 CPU 推理延迟较 .NET 8 提升 40%–300%,尤其在中小规模 Transformer 模型(如 DistilBERT…...

告别闪烁!用ESP32的RMT精准驱动WS2812灯带,附完整Arduino IDE配置流程

告别闪烁!用ESP32的RMT精准驱动WS2812灯带,附完整Arduino IDE配置流程 RGB灯带在智能家居和创意装饰中越来越受欢迎,但很多开发者在使用ESP32驱动WS2812灯带时,常常遇到信号不稳定、灯光闪烁的问题。这通常是由于软件模拟时序不精…...

别再复制链接了!手把手教你用微信公众号JS-SDK生成真正的微信导航二维码(附ASP鉴权源码)

微信导航二维码开发实战:从零实现原生位置唤起功能 每次在宣传单上看到商家地址,总忍不住想扫码直接导航过去——但现实往往是扫码后跳转到浏览器,再手动复制地址到地图App。这种割裂的体验其实可以通过微信JS-SDK彻底解决。本文将带你用ASP…...

PowerShell脚本执行受阻?一文读懂Execution Policies安全策略与实战配置

1. 为什么你的PowerShell脚本无法运行? 第一次在Windows上尝试运行PowerShell脚本时,很多人都会遇到这个令人困惑的错误提示:"cannot be loaded because running scripts is disabled on this system"。这就像你拿到了一把功能强大…...

3分钟掌握跨平台资源下载神器:从视频号到音乐平台的全能解决方案

3分钟掌握跨平台资源下载神器:从视频号到音乐平台的全能解决方案 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader …...

终极指南:免费下载Steam创意工坊模组的完整解决方案

终极指南:免费下载Steam创意工坊模组的完整解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否拥有GOG或Epic Games Store平台的游戏,却眼馋…...

保姆级教程:非华为笔记本也能用上华为多屏协同,手把手搞定电脑管家11和NFC卡贴

非华为笔记本实现多屏协同的完整实战指南 在移动办公时代,华为的多屏协同功能因其无缝连接手机与电脑的体验而备受追捧。但这项功能原本仅限于华为生态设备使用,让许多非华为笔记本用户望而兴叹。本文将彻底打破这一限制,通过系统化的解决方案…...

科研效率提升:如何用Zotero插件批量追踪文献引用量?

科研效率革命:用Zotero Scholar Citations打造智能文献追踪系统 在科研工作中,文献引用量不仅是学术影响力的直观体现,更是研究者评估自身成果价值的重要指标。传统手动查询方式效率低下,而Zotero Scholar Citations插件则为这一痛…...

MCP协议真的香:我用30行代码让AI对接了10个工具

说实话,之前我做AI Agent的时候,最头疼的就是对接各种工具。写插件、调API、处理权限,折腾了好几天才对接了3个工具。直到我用上了MCP,30行代码就搞定了10个工具的对接,真的香。 背景:AI Agent对接工具的痛…...

全网爆火的AI搭子DuMate!不是聊天花瓶,是真能替你上班的职场队友

最近科技圈、打工人圈子彻底炸锅了! 自从GPT、各类AI聊天工具火遍全网后,大家早就看透了套路:90%的AI,只会陪你聊天、给你写空话文案,真让它干活、处理电脑文件、操作办公软件,直接原地摆烂。 你让它写Excel公式、整理本地文件、批量改PPT格式、汇总桌面数据,它只会给…...

ROS可视化界面卡住?手把手教你解决WSL2+Ubuntu 20.04中rviz的Segmentation fault和X11连接问题

WSL2ROS可视化工具崩溃全解析:从X11原理到实战修复 每次满怀期待地在WSL2中键入rviz命令,却只等来一个闪烁的光标或冰冷的"Segmentation fault"提示——这种挫败感恐怕每个ROS开发者都深有体会。本文将带您深入X11转发的技术腹地,用…...

C#怎么实现EF Core全局查询过滤 C#如何用HasQueryFilter配置全局过滤条件自动排除已删除数据【数据库】

创建最小权限账号需先CREATE USER再GRANT,strict模式下漏USAGE会报错1410;localhost仅匹配socket连接,TCP需用IP段;FLUSH PRIVILEGES非DCL必需;程序连接参数如multi_statements可能触发隐式权限检查失败。创建最小权限…...

dsPIC33E电机控制实战:从边沿对齐到中心对齐互补PWM的完整配置流程(附代码)

dsPIC33E电机控制实战:从边沿对齐到中心对齐互补PWM的完整配置流程 在无刷电机控制领域,PWM信号的生成质量直接影响系统效率和运行平稳性。dsPIC33E系列数字信号控制器凭借其高性能PWM模块,成为电机驱动开发的理想选择。本文将深入探讨两种关…...

DOL-CHS-MODS:Degrees of Lewdity一站式汉化美化整合方案

DOL-CHS-MODS:Degrees of Lewdity一站式汉化美化整合方案 【免费下载链接】DOL-CHS-MODS Degrees of Lewdity 整合 项目地址: https://gitcode.com/gh_mirrors/do/DOL-CHS-MODS DOL-CHS-MODS是一个专为Degrees of Lewdity游戏设计的自动化构建系统&#xff0…...

城通网盘下载加速终极指南:3步解锁全速下载的免费开源方案

城通网盘下载加速终极指南:3步解锁全速下载的免费开源方案 【免费下载链接】ctfileGet 获取城通网盘一次性直连地址 项目地址: https://gitcode.com/gh_mirrors/ct/ctfileGet 还在为城通网盘几十KB/s的龟速下载而烦恼吗?面对几个G的大文件&#x…...

如何零侵入扩展《杀戮尖塔》:ModTheSpire模组加载器全解析

如何零侵入扩展《杀戮尖塔》:ModTheSpire模组加载器全解析 【免费下载链接】ModTheSpire External mod loader for Slay The Spire 项目地址: https://gitcode.com/gh_mirrors/mo/ModTheSpire 你是否曾经想在《杀戮尖塔》中添加新角色、新卡牌或改变游戏机制…...

让歌词动起来:给你的音乐播放器注入灵魂

让歌词动起来:给你的音乐播放器注入灵魂 【免费下载链接】ESLyric-LyricsSource Advanced lyrics source for ESLyric in foobar2000 项目地址: https://gitcode.com/gh_mirrors/es/ESLyric-LyricsSource 你是否曾经觉得,那些在屏幕上缓缓滚动的歌…...