请写一篇关于【分布式事务解决方案:最佳实践】的技术文章

深度学习小白
2025-12-18 08:43
阅读 1818

开篇:一碗云吞面,一个凌晨三点的崩溃

去年十月的一个深夜,广州老城区下着淅淅沥沥的小雨。我坐在西关老屋的窗边,桌上摆着一碗早已凉透的云吞面——那是老婆小敏临睡前给我留的宵夜。屏幕上的日志疯狂滚动,红色的 Transaction Rollback Failed 像血一样刺眼。

“又来了……”我揉了揉酸胀的眼睛,心里一阵发苦。

那会儿我刚接了一个远程外包项目,客户是国内一家做供应链金融的 SaaS 产品公司。他们用 Java 写的微服务架构,订单、库存、支付、账务四个核心模块各自独立部署,跨服务调用全靠 REST API。听起来挺高大上,但问题也来了:分布式事务

简单说就是,用户下单付钱,系统要同时扣库存、生成订单、记录账务。任何一个环节失败,其他操作都得回滚。可现实是,库存服务挂了,订单却创建成功了;或者支付回调超时,账务没记上,钱却扣了……用户投诉像雪片一样飞来。

老板在群里@我:“阿强,这问题再不解决,客户就要砍预算了。”
我回了个“收到”,心里却像被塞了块冰——月薪从15k涨到22k的承诺,眼看就要泡汤


我是谁?一个在广州老城区敲代码的自由开发者

先自我介绍一下吧。我叫阿强,土生土长的广州人,住在荔湾老城区一栋80年代的楼梯楼里,月租3500,走路五分钟到泮塘五约。大学学的是计算机,毕业后在天河科技园干了五年Java后端,前年疫情一来,公司裁员,我干脆咬牙辞职,成了自由开发者。

说实话,刚开始还挺爽:不用挤地铁,不用开站会,睡到自然醒,下午还能陪老妈去菜市场买鲩鱼。但自由的代价是——没人兜底。项目出了问题,你就是最后一道防线。

这次的分布式事务问题,就是我转型路上最痛的一课。


初期尝试:天真地以为加个 @Transactional 就行了

接到项目时,我心里其实有点飘。毕竟写了七八年 Java,Spring Boot、MyBatis、Redis 这些工具玩得挺溜。看到需求文档里写着“保证数据一致性”,我还跟小敏开玩笑:“不就是加个 @Transactional 吗?小学生都会。”

结果现实狠狠打了我一巴掌。

我一开始用了最简单的 本地事务 + 重试机制:每个服务内部用 Spring 的 @Transactional 保证自己的数据库操作原子性,失败就重试三次。但问题在于——跨服务调用不是原子的

比如:

  1. 订单服务创建订单(本地事务成功)
  2. 调用库存服务扣库存(网络抖动,超时)
  3. 系统认为失败,订单回滚
  4. 但库存服务其实在超时后处理成功了……

于是出现了“订单没生成,库存却少了”的鬼畜场面。

更糟的是,有一次支付回调延迟,账务服务没收到通知,用户钱扣了但没入账。客户直接打电话骂到项目经理头上,项目经理转头就把我微信拉黑了三天。

那几天我焦虑得睡不着,半夜爬起来查资料,头发一把一把掉。小敏看不下去,说:“要不咱接点简单的外包?别搞这些高大上的玩意儿了。”
我苦笑:“可这单做完,咱就能换套带电梯的房子了啊……”


转机:从“轮子哥”那儿偷来的思路

转机出现在一个技术沙龙。地点在珠江新城某共享办公空间,门票88块,我犹豫半天还是去了——因为主讲人是业内有名的“轮子哥”,开源过好几个 Java 分布式框架。

他讲到一半,突然说:“很多人以为分布式事务就是技术问题,其实是产品设计问题。”

这句话像闪电劈进我脑子。

他举了个例子:与其追求“强一致性”,不如在产品层面接受“最终一致性”,并通过状态机 + 补偿机制来兜底。比如电商下单,可以先冻结库存,等支付成功再真正扣减;如果支付失败,自动释放冻结。

我当场掏出手机狂记笔记,连茶歇的蛋糕都没顾上吃。

回来后,我重新梳理了整个业务流程,和产品经理开了三次线上会议(他人在杭州,说话带浓重口音,但逻辑极清晰)。我们达成共识:不要追求实时一致,而是通过状态流转 + 幂等 + 补偿,把问题拆解成可管理的单元。


实战:三种方案的落地与踩坑

方案一:TCC(Try-Confirm-Cancel)——优雅但复杂

TCC 是我最先尝试的。原理很简单:

  • Try 阶段:预留资源(如冻结库存)
  • Confirm 阶段:真正执行(扣减库存)
  • Cancel 阶段:释放资源(解冻)

我用 Java 写了三个接口,每个服务都要实现 TCC 三态。工具上选了 Seata ——阿里开源的分布式事务框架,对 Spring Cloud 支持不错。

但问题很快来了:开发成本太高。每个业务方法都要拆成三份,测试用例翻三倍。更坑的是,一旦 Confirm 阶段失败,Cancel 可能也无法执行(比如数据库连接池爆了),导致脏数据。

上线一周后,因为一个边界 case 没覆盖,库存被重复冻结。客户差点报警。

我蹲在阳台抽烟时想:“这玩意儿是不是只适合大厂?我们这种小团队玩不起啊……”

方案二:消息队列 + 本地消息表 —— 土但稳

痛定思痛,我转向了更接地气的方案:基于可靠消息的最终一致性

具体做法:

  1. 订单服务在本地事务中,同时写订单表 + 消息表(状态为“待发送”)
  2. 后台定时任务扫描消息表,发 MQ(RabbitMQ)
  3. 库存服务消费消息,执行扣库存,成功则回写 ACK
  4. 如果失败,消息重试,直到成功或人工介入

这个方案的好处是:只依赖本地事务 + 消息队列,不需要额外协调器。Java 里用 Spring 的 @Transactional + RabbitTemplate 就能搞定。

我花了三天重构代码,把原来的 REST 调用全换成 MQ 异步通知。虽然延迟从 200ms 升到 1s+,但稳定性飙升

最关键的是——产品侧配合做了优化:前端下单后显示“处理中”,1秒后自动刷新状态。用户根本感知不到背后的复杂性。

上线两周,0 数据不一致。客户主动加了5k尾款。

方案三:Saga 模式 —— 长事务的救星

后来项目扩展到跨境支付场景,涉及5个以上服务串联,TCC 太重,消息表又难以追踪全链路。

这时候我祭出了 Saga 模式:把整个流程拆成多个本地事务,每个步骤配一个补偿操作(Compensate)。如果第 N 步失败,就逆序执行 N-1, N-2… 的补偿。

工具上我用了 Eventuate Tram(一个支持 Saga 的 Java 框架),但配置复杂到想哭。最后干脆自己写了个简易版:用状态机引擎 + 补偿任务队列。

举个例子:

  • Step1: 创建订单 → Compensate: 删除订单
  • Step2: 扣库存 → Compensate: 加回库存
  • Step3: 调用支付网关 → Compensate: 发起退款

虽然补偿逻辑要写两遍,但业务语义清晰,产品经理都能看懂流程图。


区块链?别被 buzzword 带偏了

说到这儿,可能有人要问:“你提到了区块链,它能不能解决分布式事务?”

老实说,我研究过。Hyperledger Fabric、Ethereum 的智能合约确实能提供不可篡改的交易记录,但——性能太低,成本太高

我们的系统日均订单5万+,用区块链?Gas 费能把客户吓跑。而且区块链解决的是“信任”问题,不是“一致性”问题。我们内部服务之间本来就是可信的,何必上链?

所以我的结论是:除非你的产品本身就是去中心化应用(DApp),否则别为了蹭热点硬上区块链。工具要用在刀刃上,不是贴金箔。


工具链:我的 Java 分布式事务武器库

这两年踩坑下来,我总结了一套轻量级工具组合:

  • Seata:适合强一致性场景,但慎用 AT 模式(性能差),优先考虑 TCC。
  • RabbitMQ / Kafka:可靠消息投递的基石,记得开启持久化 + 手动 ACK。
  • ShedLock:分布式定时任务锁,防止补偿任务重复执行。
  • Prometheus + Grafana:监控事务成功率、延迟、重试次数。
  • 自研状态机引擎:用 Enum + Strategy 模式管理业务状态流转。

所有代码都用 Spring Boot 2.7 + Java 17 编写,Lombok 减少样板代码,MapStruct 做 DTO 转换——效率提升30%不止


感悟:技术之外,是人与产品的共舞

现在回头看,分布式事务从来不只是技术问题。

它逼我走出“纯技术思维”:不再执着于 CAP 定理谁对谁错,而是问——用户能容忍什么?产品愿意牺牲什么?

有一次和产品经理争论“是否允许短暂超卖”,我说:“技术上可以做到零超卖。”
他反问:“但如果因此导致下单失败率上升5%,损失的是真金白银。你愿意背这个锅吗?”

我哑口无言。

那一刻我明白了:好的架构,是技术和商业的妥协艺术


给同行的建议:别怕“土办法”

如果你也在折腾分布式事务,我的真心话是:

  1. 先问产品目标:是要强一致,还是最终一致?别一上来就谈 Paxos。
  2. 从小处着手:消息表 + 本地事务 能解决80%的问题,别急着上 Seata。
  3. 幂等是生命线:每个接口必须支持重复调用,否则补偿机制会崩。
  4. 监控比代码重要:没有可观测性,你就是在黑暗中裸奔。
  5. 别迷信新技术:区块链、Serverless 很酷,但不一定适合你的场景。

尾声:窗外的木棉花开了

写完这篇稿子时,已是三月。窗外的木棉花开得正盛,红得像火。小敏在厨房煲老火汤,香味飘进来,混着键盘的敲击声,竟有种奇异的踏实感。

自由开发者这条路,走得磕磕绊绊。有过凌晨三点的崩溃,也有过收到尾款时的狂喜。但正是这些“坑”,让我从一个只会写 CRUD 的码农,慢慢长成了能扛事的工程师。

分布式事务没有银弹,人生也没有。我们能做的,是在约束中寻找最优解,在混乱中建立秩序——无论是代码,还是生活。

最后送大家一句我贴在显示器边上的话:

“Consistency is overrated. Correctness with recovery is underrated.”

共勉。

—— 阿强,于广州西关老屋
2024年3月18日

评论 0

最热最新
暂无评论
深度学习小白Lv.1
0
影响力
0
文章
0
粉丝