分布式事务解决方案:在实际项目中摸爬滚打后的最佳实践
引言:分布式系统带来的新挑战

我是一个有着五年后端开发经验的工程师,经历过从单体架构到微服务架构的全面转型。最近一次参与一个大型电商平台的重构项目时,我们遇到了一个非常典型也极具挑战性的难题——分布式事务处理。
这个平台初期是典型的单体应用,所有业务模块都在同一个数据库中,数据一致性通过本地事务就可以轻松搞定。但随着业务规模的增长和团队分工细化,我们将订单、库存、支付等模块拆分成了多个独立的服务,部署在不同的节点上,各自维护自己的数据库。
拆分带来了灵活性和可扩展性,但也引入了新问题:如何保证跨服务的数据一致性?比如用户下单后扣减库存,必须确保订单创建和库存减少这两个操作要么都成功,要么都失败。否则就会出现超卖或者订单丢失的风险。
这篇文章就是基于我在这一过程中踩过坑、调过代码、优化过性能的真实经历来写的。希望你能从中找到一些对自己有帮助的经验或启发。
项目背景与问题描述:电商系统的复杂交易流程

我们这次重构的是一个B2C电商平台,核心流程包括:
- 用户下单
- 库存服务进行库存预扣
- 订单服务生成订单记录
- 支付服务完成支付
- 物流服务开始发货
这些操作分别由不同服务独立处理,并且每个服务都有自己的数据库。这就意味着,原本一个本地事务就能完成的操作,现在必须跨多个服务和数据库,协调一致地提交或回滚。
遇到的问题
最开始我们采用的是“伪分布式”处理方式,也就是通过消息队列(Kafka)异步通知的方式来做最终一致性。但在高峰期压测的时候发现:
- 库存被多次重复扣减;
- 订单已创建但未扣库存,导致超卖;
- 支付成功但订单状态异常。
这些问题的根本原因在于,我们的处理流程缺乏一套完整的事务边界控制机制。简单来说,各个子系统之间没有形成协同一致的原子操作能力。
这个时候我们意识到:光靠异步最终一致是不够的,我们必须设计一套真正能保障事务完整性和可靠性的方案。
解决思路:选择合适的技术方案
经过技术选型,我们决定采用 TCC 模式 + Saga 模式结合的方式来实现关键路径的分布式事务。为什么?
- TCC(Try - Confirm - Cancel)模式可以实现强一致性,适合对数据一致性要求极高的场景。
- Saga 模式则更适合长周期、补偿逻辑比较清晰的场景。
我们在订单创建、库存扣减这样需要强一致性的环节使用 TCC;而在物流发货、优惠券核销等相对松散的步骤使用 Saga。
关键决策点
- 不使用 XA 或 Seata 的 AT 模式:XA 性能差,AT 虽好但依赖全局锁,在高并发场景下容易成为瓶颈。
- 不完全依赖 Kafka 最终一致:虽然轻量,但无法解决失败重试下的幂等和状态跟踪问题。
- 自研事务协调器 + 状态管理表:为了更灵活地控制整个事务生命周期。
方案实施:从设计到落地的具体过程

1. TCC 流程设计(以订单为例)
Try 阶段
- 订单服务:创建临时订单,状态为“待确认”
- 库存服务:冻结库存,标记为“锁定中”,但不真实扣减
- 支付服务:占位支付通道,预留支付上下文
Confirm 阶段
- 订单服务:将订单置为“已确认”
- 库存服务:执行实际的库存扣除
- 支付服务:正式发起支付请求并更新状态
Cancel 阶段
- 订单服务:取消订单,清理临时订单记录
- 库存服务:释放冻结的库存
- 支付服务:释放支付上下文
TCC 协议的核心结构
public interface OrderTccService {
@TwoPhaseBusinessAction(name = "createOrder")
boolean prepare(BusinessActionContext ctx);
@Commit
boolean commit(BusinessActionContext ctx);
@Rollback
boolean rollback(BusinessActionContext ctx);
}
我们使用的框架是阿里巴巴开源的 Seata,它为我们提供了良好的事务协调机制和日志追踪能力。
2. Saga 模式用于后续流程
Saga 更适合像物流、发票这样的子流程,因为它们不需要在创建阶段马上完成。我们采用的是事件驱动 + 状态机引擎的方式:
- 事件总线发布事件,例如 “ORDER_PAID”
- 物流服务监听事件,触发发货任务
- 若发货失败,触发补偿动作(例如退单或标记异常)
这种方式的好处是流程解耦、易于维护,而且天然支持自动化补偿。
开发中的几个坑与应对方法
坑一:事务状态难以追踪
在早期版本中,我们遇到一个问题:当某次事务部分成功后发生系统宕机,重启后无法判断当前状态到底是需要 Commit 还是 Rollback。
解决方法:
- 新增一张
distributed_transaction表,保存全局事务 ID、各子事务状态、最后更新时间。 - 启动定时任务定期扫描未完成的事务,重新执行对应的 Confirm / Cancel 操作。
CREATE TABLE distributed_transaction (
tx_id VARCHAR(64) PRIMARY KEY,
status ENUM('PREPARING', 'COMMITTED', 'ROLLED_BACK') NOT NULL,
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
retries INT DEFAULT 0
);
坑二:Cancel 失败导致死循环
有些情况下,Cancel 操作本身也会出错,比如网络中断或数据库连接失败。
解决办法:
- Cancel 必须具备幂等性,即使多次调用也不能产生副作用。
- 引入重试机制 + 死信队列 + 人工干预机制。
- 在 Cancel 操作中加入前置检查,避免无效操作。
坑三:性能瓶颈出现在协调器上
在并发量提升之后,Seata 的 TC 服务出现了明显的吞吐瓶颈。
优化措施:
- 使用 Redis 缓存部分事务信息,减少 DB 查询。
- 将一部分非关键事务降级为异步处理。
- 对 TC 服务做横向扩容,配合 Nacos 进行服务治理。
效果总结:上线后的表现与收益
这套分布式事务方案上线后,我们观察了三个月的运行情况,整体效果如下:
| 指标 | 上线前 | 上线后 | 提升幅度 |
|---|---|---|---|
| 订单事务成功率 | 98.7% | 99.99% | +1.29% |
| 事务处理延迟 | 平均 120ms | 平均 95ms | 降低20.8% |
| 超卖错误次数 | 每日约 20 次 | 几乎为零 | 显著减少 |
更重要的是,整个系统的稳定性大大增强,尤其是在大促期间承受住了压力测试,没有出现大规模数据不一致的问题。
我的一些经验和建议
如果你也在面临类似的分布式事务挑战,以下是一些我在工作中总结出来的经验,供你参考:
1. 不要盲目追求“强一致性”
很多同学一开始就想把每个步骤都纳入事务中,结果搞得系统复杂度飙升、性能还下降。要根据业务特点选择合适的模型。
比如物流、发票这种延后操作,完全可以使用 Saga 或最终一致性方案来降低复杂度。
2. 重视日志和监控建设
分布式事务一旦出错,定位问题比单体难十倍不止。我们搭建了一套基于 Zipkin 的链路追踪系统,并且对每一步事务操作记录详细日志。
举个例子,我们在 Confirm / Cancel 操作前后都会打印日志:
[Tx: abc123] Start to confirm order creation...
[Tx: abc123] Confirm payment success
[Tx: abc123] Deduct stock from warehouse A: success
[Tx: abc123] Confirm complete.
3. 写接口时一定要考虑幂等性
特别是 Cancel 和 Confirm 方法,很可能因为网络原因被重复调用多次。你需要确保这些方法无论如何被调用,都不会产生副作用。
常见的做法是在接口层面加上唯一标识+缓存去重,或在数据库增加 version 字段防止重复更新。
4. 不要忘了运维视角的设计
- 事务表要设计得便于排查,字段齐全,比如 tx_id, business_key, status, create_time, retry_count。
- 定期清理已完成的事务记录,防止表过大。
- 对失败事务设置重试上限,超过自动转入人工处理流程。
- 给业务方提供事务查询接口,方便对账和运营支持。
技术趋势展望
随着云原生的发展,越来越多的基础设施层开始支持原生的分布式事务功能,比如 TiDB、Google Spanner、AWS Aurora Global Database 等。
不过目前大多数公司还停留在传统架构改造阶段。个人认为,在未来的 2~3 年里,轻量级事务框架 + 自定义状态引擎仍然会是主流方案,直到真正的全栈数据库事务支持普及为止。
如果你还在用本地事务那套思维写微服务,那真的该好好补一补分布式事务的知识了。
结语:技术是解决问题的工具,不是炫技的资本

写这篇文章的过程也是我对过去一年工作的回顾和沉淀。分布式事务并不是什么黑科技,也不是必须掌握不可的神器。它的本质还是为了解决现实业务中的一致性问题。
有时候我们会陷入各种框架对比和技术辩论中,但别忘了,最终客户关心的是能不能下单、会不会少发货。技术的最终目标,是让业务平稳高效地运转,而不是让自己看上去很厉害。
希望这篇来自实战经验的文章对你有所帮助。如果你们也有类似的经历,欢迎留言交流。共同成长,才是技术人最有价值的事。
作者:一名在一线搬砖5年的Java后端工程师。专注高性能系统设计、微服务架构及企业级稳定性建设。欢迎关注我的公众号或知乎主页,一起探讨更多实战技术。

评论 0