一次高并发下分布式事务的实战突围:从踩坑到稳如老狗
背景介绍:为什么我们避不开分布式事务?

我在一家做跨境电商平台的技术公司工作,负责订单系统、库存系统的后端开发与架构优化。随着业务的快速扩张,原本单体的应用已经完全扛不住流量,我们在去年完成了服务化改造,拆分出了订单中心、库存中心、支付中心等多个独立微服务模块。
这本来是件好事,但很快我们就遇到了一个非常头疼的问题——如何保障跨服务操作的一致性。比如用户下单时,需要调用订单服务创建订单、库存服务扣减库存,还可能涉及营销服务使用优惠券等操作。如果这些操作不能原子性地完成,就会出现“库存扣了但订单没建成功”或者“订单生成但优惠券没生效”的问题。
这其实就是典型的分布式事务问题。
这篇文章我将从一次大促中遇到的真实场景出发,讲讲我是怎么一步步解决这个问题的,踩了哪些坑,又得到了什么经验教训。希望读完你能对分布式事务有更深刻的理解,并在实际项目中有信心应对类似问题。
问题描述:一场大促背后的危机

今年618大促前一晚,压测过程中我们发现了一个严重问题:
某些场景下,会出现“订单创建成功、库存未扣减”的情况。也就是说,在高并发的情况下,我们的多个服务之间的事务一致性出现了异常!
当时的系统结构大致如下:
- 前端 H5 -> 订单服务(Java Spring Boot)
- 订单服务调用 库存服务(HTTP 接口)扣减库存
- 订单创建和库存扣减之间没有事务控制
整个流程看起来简单明了,但在测试中我们通过模拟大量请求并发下单发现,有一部分订单状态已经是已创建,而对应的库存字段却仍然为原值。
为什么会这样?我们深入排查后发现问题出在两个地方:
- 网络不稳定导致接口超时,订单创建成功但库存扣减失败;
- 服务间的调用顺序不可靠,即使加了重试机制,也可能因幂等处理不当引发数据不一致;
- 最关键的是,我们没有引入任何分布式事务机制,只依赖了数据库本地事务。
这种做法在低并发下可以勉强应付,但在大促期间的高负载下暴露无遗。
那怎么办呢?当时摆在我们面前的选择有几个:
- 两阶段提交(XA)
- TCC(Try-Confirm-Cancel)
- 本地消息表(Local Message Table)
- 最终一致性方案 + 人工补偿
- 引入 Seata 等开源解决方案
下面我会详细分享我们是怎么选型并落地的全过程。
解决方案:从Seata入手,搭建一个可靠的分布式事务体系


最终我们决定采用TCC模式结合Seata框架来构建整个分布式事务系统,因为以下几个原因:
- 性能要求高:我们不想因为引入分布式事务而导致吞吐量下降明显;
- 技术栈限制:我们使用Spring Cloud Alibaba,而Seata天然支持这一生态;
- 开发可控性强:TCC虽然比最终一致性复杂,但我们可以通过封装降低复杂度;
- 未来扩展性考虑:后续引入支付回调、积分同步等功能时也能统一接入。
技术选型分析
| 方案 | 优点 | 缺点 | 是否适合我们 |
|---|---|---|---|
| XA | 强一致性 | 性能差、锁资源多 | ❌ 不适合高并发 |
| TCC | 自主控制粒度、性能好 | 侵入性较强 | ✅ 可控 |
| SAGA | 实现简单、性能好 | 不保证中间态一致性 | ❌ 风险高 |
| 本地消息表 | 成熟可靠 | 实现较复杂、耦合度高 | ⚠️ 备选方案 |
| 最终一致性+补偿 | 简洁灵活 | 容错要求高 | ⚠️ 配合主方案 |
我们选择了TCC + Seata的方式,主要是看中其可伸缩性和成熟度。而且Seata社区活跃,文档也比较完善。
架构设计思路
我们先来看一个简化版的流程图:
[订单服务]
↓ (Try)
[库存服务 - 冻结库存]
↓ (Try)
[优惠券服务 - 锁定优惠券]
↓ (Confirm / Cancel)
[订单落库]
整个过程分为三个阶段:
- Try阶段:资源准备阶段,所有服务检查是否满足条件,预留资源;
- Confirm阶段:资源确认阶段,执行最终操作;
- Cancel阶段:如果其中一个服务失败,则所有服务执行逆向操作进行回滚。
具体来说:
- 在Try阶段,我们冻结库存、锁定优惠券;
- 在Confirm阶段,我们实际扣减库存、扣除优惠券;
- 如果任一环节失败,则触发Cancel操作,解冻库存、释放优惠券。
具体实现细节
1. Seata 的整合
我们采用Spring Cloud Alibaba + Nacos作为注册中心,所以直接使用spring-cloud-starter-alibaba-seata这个 starter 就可以方便集成。
引入Seata之后,我们在Controller层使用了@GlobalTransactional(rollbackFor = Exception.class)注解:
@PostMapping("/placeOrder")
@GlobalTransactional(rollbackFor = Exception.class)
public Result<OrderVO> placeOrder(@RequestBody OrderDTO orderDTO) {
// 创建订单
orderService.create(orderDTO);
// 扣减库存
inventoryService.deductInventory(orderDTO.getProductId(), orderDTO.getCount());
// 锁定优惠券
couponService.lockCoupon(orderDTO.getCouponId());
return Result.success();
}
这个全局事务注解会自动开启Seata的XID传播,并协调后续各服务参与方的TCC操作。
2. TCC编写规范
每个服务都需要提供自己的TCC接口:
- Try:
prepare()方法 - Confirm:
commit()方法 - Cancel:
rollback()方法
例如,库存服务:
public interface InventoryTccAction {
boolean prepare(BusinessActionContext ctx);
boolean commit(BusinessActionContext ctx);
boolean rollback(BusinessActionContext ctx);
}
其中BusinessActionContext就是Seata用于上下文传递的对象,里面包含了事务ID、参数等信息。
我们在每个方法中都做了幂等判断(防止重复提交)、以及日志追踪记录。
3. 数据库设计要点
为了支撑TCC的实现,我们在数据库层面也做了几个关键改动:
- 增加库存冻结字段
frozen_quantity和真实库存字段available_quantity - 每次Try阶段对库存进行冻结,而不是直接扣除
- Commit阶段才真正更新可用库存
- Rollback阶段则释放被冻结的数量
这样的设计可以避免因为事务失败导致库存丢失或错误减少。
同时,我们在每张表中加入了transaction_id字段,记录关联的事务编号,方便后续对账和排查。
实施效果:从“怕死”到“安心”

经过约两周的改造和压测后,我们上线了这套基于TCC的分布式事务机制。
性能对比(压测数据)
| 场景 | QPS | 平均响应时间 | 数据一致性达标率 |
|---|---|---|---|
| 无事务机制 | 2000 | 120ms | 78% |
| Seata-TCC | 1850 | 145ms | 99.99% |
| 最终一致性(补偿) | 2200 | 110ms | 97.5% |
可以看到,虽然QPS略有下降,但是数据一致性大大提高,这对电商系统至关重要。
更重要的是,我们有了统一的事务模型,无论后面增加新的业务模块还是接入第三方系统,都可以轻松接入Seata体系。
经验总结:关于分布式事务的几点心得
作为一个在生产环境折腾过分布式事务的人,我想给各位同行一些真诚的建议:
1. 别轻易说“不需要事务”,数据一致性永远是底线
我们最初以为“只要加上足够多的补偿逻辑就行”,结果吃尽了苦头。尤其在金融、交易、库存等场景里,一致性绝对不能妥协。
2. 选择合适的模型很重要
并不是所有场景都要上TCC。比如日志写入、非核心功能可以用“最终一致性+补偿”的方式;但对于资金、库存这类关键操作,TCC更适合。
3. Seata 是个好工具,但别指望它能“一键修复一切”
Seata本身只是一个框架,真正的实现还是要靠你自己写代码。TCC接口的设计、幂等的处理、重试策略、日志埋点、事务对账等等,每一项都不容易。
我们当时光为了实现库存服务的幂等逻辑就花了不少时间调试,尤其是在并发环境下。
4. 做好监控和对账系统才是真正的兜底手段
哪怕你用了Seata,也要有监控告警机制。我们后来专门做了一套“事务对账服务”,每天凌晨自动比对订单、库存、优惠券等数据,自动修复少数不一致的数据。
5. 团队沟通和协作是推进这种项目的关键
TCC是一个全链路的工作,涉及到多个服务团队。我们必须统一接口规范、约定事务生命周期、定义日志格式……这些都不是技术难点,但如果没有良好的协作机制,很难推进下去。
结语:技术人的成长总是在一次次“踩坑”中发生的
说实话,刚接触Seata的时候我也一头懵。尤其是看到各种配置文件、事务日志、回滚机制的原理,一度怀疑自己是不是选错了方向。但现在回头看看,那次项目的推进不仅解决了业务痛点,也让我对整个系统的稳定性、可观测性、容错能力有了全新的理解。
技术从来不是孤立存在的,每一个决策的背后都是权衡与取舍。我希望这篇来自真实项目的分享,能够帮助你少走弯路,勇敢面对分布式架构下的挑战。
如果你正在处理类似的分布式事务问题,欢迎留言交流。一起踩过的坑,也可以变成前进的台阶。
作者简介:一名有着五年电商领域后端开发经验的程序员,经历过大型高并发系统的洗礼,热爱架构设计与稳定系统建设。目前专注于云原生与分布式系统落地实践。

评论 0