分布式事务方案选型-元一软件

发布时间:2026/11/4 8:09:04

分布式事务方案选型-元一软件 在微服务架构下跨服务的数据一致性保证是个绕不开的难题。如果在一次业务操作中写多个DB或既写本地DB、又调外部RPC接口就会面临一致性问题怎么保证跨库、跨系统的操作要么都成功、要么都失败呢先说结论最常用的分布式事务方案是TCC、Saga、可靠消息。最推荐的开源框架是Apache Seata支持多种分布式事务模式包括TCC、Saga、AT等。下面展开介绍。BASE理论在一个数据库事务内多个sql写操作可以保证强一致。而到了分布式场景只能做到最终一致。这就引出了BASE理论基本可用、软状态、最终一致性即允许系统存在中间不一致状态只要最终达到一致即可。分布式事务方案大多在BASE理论指导下放弃强一致追求最终一致。主流方案和最佳场景下面每种方案都用一个独立的、最适合的业务场景来介绍。1. TCC最佳场景下单时扣库存、扣余额比如下单流程涉及订单服务、库存服务、支付服务。需要同时创建订单、冻结库存、冻结余额并发量较高且对一致性要求严格。原理与实现机制TCC需要一个协调者一般称为事务管理器负责编排整个流程。但资源锁定做到了业务层、而非DB层由应用代码显式实现Try、Confirm、Cancel三个接口。TM事务管理器负责调用各个服务的Try方法根据结果决定全部Confirm或全部Cancel。需记录事务日志处理重试和异常RM资源管理器各业务服务自身需要提供Try/Confirm/Cancel三个接口并保证幂等可能会调多次流程细节TM依次调用每个服务的Try接口预留业务资源如冻结库存、冻结余额不用上数据库行锁若所有Try成功TM依次调用Confirm接口将预留资源实际消耗或状态推进若任何Try失败或超时TM调用所有已成功服务的Cancel接口释放预留资源框架需要处理空回滚Try未执行但Cancel被调用、悬挂Cancel比Try先到、幂等接口被重复调用等问题一般通过记录全局事务状态并用全局事务ID查询状态来实现举例库存服务Try/Confirm/Cancel// Try阶段冻结库存、扣减可用库存 Transactional public boolean tryFreezeInventory(String productId, int qtyDelta, String txId){// 冻结库存、扣减可用库存update inventorysetfrozen_qtyfrozen_qty #{qtyDelta}, available_qty available_qty - #{qtyDelta}// where product_id#{productId} and available_qty - #{qtyDelta} 0if(inventoryMapper.freeze(productId, qtyDelta)0){// 冻结库存成功记录库存变更明细状态为TRY freezeRecordMapper.insert(txId, productId, qtyDelta);returntrue;}else{returnfalse;}}// Confirm阶段扣减冻结库存 Transactional public void confirm(String productId, int qtyDelta, String txId){// 扣减冻结库存update inventorysetfrozen_qtyfrozen_qty -#{qtyDelta} where product_id #{productId}inventoryMapper.deduct(productId, qtyDelta);// 更新库存变更明细为已完成 freezeRecordMapper.updateStatus(txId,CONFIRMED);}// Cancel阶段释放冻结库存、可用库存 Transactional public void cancel(String productId, int qtyDelta, String txId){FreezeRecord rfreezeRecordMapper.selectByTxId(txId);if(rnull){return;// 空回滚}// 释放冻结库存、可用库存update inventorysetfrozen_qtyfrozen_qty -#{qtyDelta}, available_qty available_qty #{qtyDelta}// where product_id#{productId}inventoryMapper.release(productId, qtyDelta);// 更新库存变更明细为已取消 freezeRecordMapper.updateStatus(txId,CANCELLED);}TCC将所有资源操作变成“预留”而非直接扣减避免了数据库行锁长时间持有非常适合秒杀、支付等并发高、资源竞争激烈的场景。2. SagaSaga一词的本意是长篇故事在分布式事务场景下是指一连串的事务。最佳场景出行预订机票酒店门票比如在线旅行平台用户一次性预订机票、酒店、门票三个服务相互独立、流程长并且每个预订都会调用外部第三方接口。因为无法控制外部服务的实现只能通过Saga模式来实现调外部接口、长流程的正向事务、补偿事务。原理与实现机制Saga模式的核心思想是将一个长事务拆分为多个有序的本地事务每个本地事务执行后直接提交不锁定资源。如果后续步骤失败则通过逆序调用之前的补偿事务来回滚。Saga一般采用编排式Orchestration存在一个中心协调者Orchestrator它负责调用每个步骤的本地事务并在失败时按逆序调用补偿。逻辑集中易于监控。协调者需要持久化Saga状态机以便在自身宕机后能够恢复并继续执行或补偿。关键实现点每个正向事务都必须有一个对应的补偿事务且补偿必须是幂等的因为可能存在重试缺少隔离性Saga不锁资源中间状态可被读取到因此业务设计上需要允许暂时的脏读例如预订酒店后变为“酒店预订成功”但因为机票出票失败后回滚为“酒店预订已取消”补偿失败时需要告警并人工介入因为回滚本身也可能失败举例出行预订的正向事务与补偿// 正向事务调用第三方接口预订酒店 public Booking bookHotel(HotelReq req){String bookingIdhotelApi.reserve(req);returnbookingRepo.save(new Booking(bookingId,RESERVED));}// 补偿事务取消预订 public void cancelHotel(Booking booking){hotelApi.cancel(booking.getBookingId());bookingRepo.updateStatus(booking.getId(),CANCELLED);}Saga不占用数据库锁各服务完全独立非常适合调用外部服务、流程长的业务。代价是需要实现补偿逻辑且中间状态可见业务必须能容忍短暂的不一致。3. 可靠消息最佳场景非核心链路的联动处理场景确保一定通知到、但可能多发消息联动方需做好幂等。比如用户注册送积分场景在用户注册后需要发送欢迎邮件、初始化积分账户。这些动作可以异步完成允许秒级延迟但必须保证最终完成。原理与实现机制要实现可靠消息需要通过本地消息表模式即本地事务消息队列实现最终一致。核心思想是将业务操作和消息持久化放在同一个DB事务中然后通过后台任务将消息发送到MQ下游消费时保证幂等。关键流程消息生产方执行业务操作的同时向本地DB的outbox表插入一条“待发送”消息两者在同一数据库事务中提交。然后发消息到MQ最后更新状态为“已发送”这2步可能失败兜底定时任务定时查询outbox表中超过一定时间仍处于“待发送”状态的记录将消息发送到MQ成功后更新状态为“已发送”消息消费方监听消息执行本地事务如初始化积分通过业务唯一键保证幂等举例注册用户时写入本地消息表、发消息-- 用户服务本地事务 BEGIN;INSERT INTO users(user_id, email,...)VALUES(...);INSERT INTO outbox(message_id, topic, payload, status)VALUES(msg_reg_123,USER_REGISTERED,{userId:...},PENDING);COMMIT;4. 两阶段提交2PC2 Phase Commit最佳场景内部低并发强一致转账比如公司内部财务系统A账户向B账户转账两个账户分别在不同数据库。并发量极低但绝不允许出现金额不一致。原理与实现机制2PC需要一个全局事务协调者Coordinator通常由事务管理器如JTA实现充当。参与者是各个资源管理器RM如数据库。协调者负责调度整个事务流程发送指令收集投票结果。参与者实际持有资源的节点执行预提交和最终提交/回滚。流程细节阶段一准备/投票协调者向所有参与者发送事务内容询问是否可以提交。参与者各自锁定资源如数据库行锁执行事务操作并写入undo/redo日志但不提交然后返回Yes或No阶段二提交/回滚若所有参与者返回Yes协调者发送提交指令若任一返回No或超时则发送回滚指令。参与者根据指令完成提交或回滚并释放锁。存在“协调者单点故障”问题若阶段二指令未能送达所有参与者部分参与者可能处于不确定状态需要人工介入或日志恢复举例公司内部跨系统转账通常基于XA协议实现如Java JTA。开发无需实现Try/Confirm但两个数据库资源在阶段一就被锁定其他事务无法操作A和B的余额直到协调者发出最终指令。内部管理系统的转账逻辑简单并发低这种强一致和阻塞是可以接受的。5. AT模式SeataAT模式是Seata引入的一种非侵入式的分布式事务解决方案Seata在内部做了对DB操作的代理层会生成业务层的undo log相当于在业务层实现了2PC。最佳场景无侵入改造老系统比如一个老旧的单体应用刚拆分为订单服务和库存服务数据库也一分为二。业务代码不想大改又需要保证“下单必须扣库存”的事务一致性。原理与实现机制一阶段在同一个本地事务中提交业务数据和undo log需先加全局锁。undo log是业务回滚日志在更新前查出前镜像然后做更新操作最后根据前镜像的主键id查出后镜像前镜像、后镜像的内容就是undo log的组成部分二阶段提交成功后异步删除对应的undo log。回滚通过一阶段的undo log进行反向补偿举例库存更新sql是update inventory set qty qty - 1 WHERE product_id 1001Seata自动记录前镜像qty100、后镜像qty99。回滚时生成sqlupdate inventory set qty 100 WHERE product_id 1001。业务代码完全不用加 Try/Confirm/Cancel只需引入Seata的代理数据源即可。AT模式适合对业务侵入性要求极低、SQL操作相对简单的改造场景。但它依赖关系型数据库默认读未提交需注意脏读问题复杂查询多或性能要求极高的场景要谨慎。方案选项总结方案一致性性能代码侵入性最适合的场景TCC强一致/最终一致高高资源争夺型高并发下单扣库存、余额Saga最终一致高中长流程、调用外部服务旅行出游预订可靠消息最终一致高中异步解耦的非核心流程注册送积分2PC强一致低低内部低并发强一致转账AT模式弱一致/读未提交中低无侵入改造老系统没有一套方案能覆盖所有分布式事务场景做方案选型时重点关注数据不一致的窗口能容忍多久并发量有多大是否能实现补偿逻辑再结合上述表格就能找到最合适的分布式事务方案通过Apache Seata来实现TCC、Saga、AT模式通过本地消息表来实现可靠消息。
延伸阅读

更多相关文章

2026/11/4 6:17:37

Herro晨间定制流程:用自动化聚合信息,打造个人数字管家

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/4 1:29:55

Java EE 进阶:2.1 HTML

目录 1.HTML 1.1 HTML基础 1.1.1 什么是HTML 1.1.2 认识 HTML 标签 1.1.3 HTML 文件基本结构 1.1.4 标签层次结构 1.2 HTML 快速入门 1.2.1 开发工具 1.2.2 快速开发 1.3 HTML 常见标签 1.3.1 标题标签 h1-h6 1.3.2 段落标签:p 1.3.3 换行标签&#xf…

2026/11/4 8:09:03

Tika文件解析异常排查与优化实践

1. 问题现象与背景解析 上周排查一个文件解析服务时,遇到个典型的Tika解析异常案例。当时系统正在处理一批用户上传的PDF文档,突然抛出"org.apache.tika.exception.TikaException: Error creating document"错误,导致整个文件解析流…

2026/11/4 8:09:03

VSCode搭建C语言开发环境全指南

1. 为什么选择VSCode搭建C语言开发环境? 作为一名长期使用各种IDE进行C/C开发的程序员,我深刻理解初学者在搭建开发环境时的困惑。Visual Studio Code(简称VSCode)之所以成为我的首选推荐,主要基于以下几个实际考量&am…

2026/11/4 8:09:03

600美元AI订阅账单拆解:大模型选型与成本优化实战

1. 先说说这600刀是怎么烧掉的,以及为什么值得 标题里那三个名字,我下文统一用 A、B、C 代称——A 是那种最早普及、生态最厚的对话型助手,B 是搜索起家、多模态能力最激进的那家,C 是长文本处理和写作质感口碑最好的那家。懂的人…

2026/11/4 8:09:03

XGBoost与神经网络在糖尿病预测中的对比实践

1. 项目背景与核心问题 疾病预测一直是医疗数据分析领域的重要课题。随着机器学习技术的发展,XGBoost和神经网络这两类算法在实际应用中各有拥趸。我在某三甲医院合作项目中,需要构建一个糖尿病早期预测模型,面临算法选型的实际问题&#xff…

2026/11/4 8:09:03

Docker容器技术核心原理与实战部署指南

1. Docker核心概念与优势解析 1.1 虚拟化技术演进历程 传统虚拟机技术通过在物理机上运行Hypervisor(如VMware、VirtualBox)来模拟完整硬件环境,每个虚拟机需要运行独立的操作系统内核。这种架构带来三个显著问题: 资源开销大 …

2026/11/4 8:04:02

千笔AI:MBA学习场景的AIGC工具解析

1. 项目概述:千笔AI如何重塑MBA学习场景 在商学院的案例研讨室里,经常能看到这样的场景:小组讨论时有人对着电脑屏幕抓耳挠腮,PPT上的数据分析图表迟迟无法成型;凌晨三点的图书馆角落,赶作业的学生对着空白…

2026/11/3 7:47:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/4 0:03:20

AI辅助技术栈评估:提升研发决策效率60%

1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年…

2026/11/4 0:03:20

从生成Token到直接决策:Jev如何重塑AI Agent工程实践

1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你…

2026/11/4 0:03:20

32G统一内存跑大模型:内存账、TPS实测与端云分流

想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统…

2026/11/3 7:47:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑