沉默是金,总会发光
大家好,我是沉默
一天晚上,已经快九点,办公室还亮着几盏加班的灯。
“有用户投诉,说他下单后扣了钱但没生成订单。”
运营在群里甩了一张截图,配着一句:“请技术看看?”
我放下刚背起的书包,脑子嗡地一下清醒过来。
点开后台一查,账务系统里记录确实有了:付款成功,流水号齐全;可订单系统那边,却啥也没有。库存也没动,用户就这么凭空“花了钱”,啥也没买着。
我们几个后端同事一边翻日志,一边脑补出了整件事的经过——用户付款后,请求先打到支付服务,支付成功后应该顺序调用订单服务、库存服务……但某个环节出了问题,请求“半路失踪”。
更糟的是,这已经不是第一次出现类似问题了:
-
有时候,订单创建成功了,但库存没扣;
-
有时候,扣了库存,余额也少了,可订单失败了。
说到底,这些服务之间各自为政,各用各的数据库,本地事务各保一亩三分地,但业务流程是跨系统的。
那一晚,我们彻底意识到:
系统已经“分布式”了,但事务处理还停留在“单机时代”。
如果你也经历过类似的夜晚,或者正准备把业务系统从“一个大坨”拆成多个服务,那这篇文章也许能替你提前避坑。
接下来,我们会带你一起回顾:
-
什么是本地事务与分布式事务;
-
分布式事务有哪些典型场景;
-
分布式事务的经典解决方案;
-
如何优雅地设计你的分布式事务方案;
**-**01-
什么是本地事务与分布式事务
什么是事务?
说起“事务”,大家最熟的是数据库里的“本地事务”。它保证了数据库操作的四个特性——ACID:
-
原子性(Atomicity):要么都成功,要么全失败;
-
一致性(Consistency):事务前后数据要满足一致性约束;
-
隔离性(Isolation):并发时互不干扰;
-
持久性(Durability):一旦提交,掉电都不怕。
本地事务简单、高效,适合一个系统内部搞定一切的“小而美”应用。
分布式事务:
随着微服务和系统拆分成为主流,很多应用不再是一个系统独立完成所有业务流程,而是多个服务(通常对应多个数据库)协同完成。
举个例子,一个电商平台的“下单”操作,可能要跨越这些服务:
-
用户服务(扣用户积分);
-
商品服务(减库存);
-
订单服务(生成订单);
-
支付服务(冻结余额);
每个服务都可能有自己的数据库,各自为政,本地事务解决不了多个服务间的数据一致性问题。这时,我们就需要“分布式事务”。
举个栗子 🌰
你去餐厅吃饭,点了三道菜:红烧肉、麻婆豆腐、小炒黄牛肉。服务员分头通知三个厨师做菜。
本地事务像是一个厨师做完所有菜;分布式事务则是三个厨师分别做菜,还得保证——要么三道菜都上齐,要么都别上,不能让你只吃上小炒黄牛肉,红烧肉没了,还得照单全收。
而这,正是分布式事务想解决的难题:让多个独立系统之间的数据操作保持“一致性”。
**-**02-
分布式事务有哪些典型场景
1. 微服务场景
微服务拆分后,每个服务独立部署、独立数据库。这时候,一个完整的业务流程往往要调用多个服务,例如:
-
创建订单时,需要调用库存服务、账户服务、物流服务;
-
用户注册时,可能要调用用户中心、CRM 系统、短信网关;
每个服务都用自己的数据库,本地事务只能保自己不出错,无法保证“整体一致”。
就像打排球,一个人扣球再猛,没人配合就赢不了比赛。
只靠本地事务不够看,得来点“团队协作”式的分布式事务支持。
2. 传统中间件拆分场景
一些老系统最初是 All in One(全部模块放一个应用里),后来为了扩展或接入中台,开始把部分功能拆出去,比如:
-
用户模块独立成用户服务;
-
订单模块独立成订单服务;
-
商品模块独立成商品服务;
这些服务拆开后,原来一个本地事务就能搞定的操作,现在变成了多个服务间的调用,比如:
- 创建订单 → 减库存 → 扣余额
过去这一步事务在一个方法里,现在变成了远程调用+多数据库操作,一不小心就出现“扣了钱但没下单”、“下单成功但库存没减”的尴尬场景。
系统架构一旦分布化,事务也必须升级成“分布式事务”才行。
3. 异构系统集成场景
有些业务流程需要跨系统打通,比如:
-
电商平台对接外部支付平台;
-
SaaS 系统同步数据到企业内部系统;
-
订单处理调用第三方供应商的接口(比如仓储系统);
这些系统之间 可能语言不同、数据库不同、架构不同,甚至不一定你能控制它们的事务。
这时候,如果还想保证流程的完整性和一致性,那就要引入一些更灵活、兼容性更强的分布式事务机制,比如 TCC 或消息队列事务等。
**-**03-
分布式事务的经典解决方案
搞清楚了为什么需要分布式事务,接下来就得看一看:怎么搞?有哪些套路?
1. 两阶段提交(2PC):
2PC(Two-Phase Commit)是分布式事务的鼻祖级方案,流程像军事行动:
-
第一阶段:准备阶段(Prepare)
总指挥(协调者)先发通知给所有小分队(参与者):
“大家都准备一下,别动手,先告诉我能不能执行。”各分队收到后做“预处理”操作,写入事务日志,然后回复“我准备好了”。
-
第二阶段:提交阶段(Commit)
如果所有人都说 OK,总指挥就下达统一命令:“干!”
每个分队正式提交事务,否则就发“取消任务”命令,全部回滚。
听起来很严谨对吧?但现实里这套流程也有几个老毛病:
-
协调者单点故障:总指挥挂了,大家等指令等到老;
-
阻塞问题严重:所有分队等着总指挥说话,谁也不敢动,系统容易“卡壳”;
-
不支持非数据库资源:你要协调 MQ、缓存这类资源?对不起,不会。
2PC 更像是“书生治军”,讲究规矩但效率不高,现代微服务里已经不太流行。
2. Seata AT 模式:
AT(Automatic Transaction)是 Seata 的默认模式,设计思路是:帮你在数据库层偷偷搞定分布式事务。
它有个核心组件叫 代理数据源,会在你执行 SQL 时自动做三件事:
-
执行前:记录“快照”,比如订单创建前,这条数据长啥样;
-
执行中:照你 SQL 正常执行;
-
回滚时:根据“快照”还原数据(像 Ctrl+Z 一样);
这套机制最大优点是——对业务开发透明。你写普通的 JDBC/MyBatis 代码,它就悄悄替你完成分布式事务控制。
但副作用也不少:
-
只能操作关系型数据库,NoSQL、MQ 统统不支持;
-
对 SQL 要求高,复杂 SQL、存储过程容易出问题;
-
大数据量下性能损耗明显,毕竟要记录快照、做日志,还要支持回滚。
AT 模式像是会“时光倒流”的数据库代理人,平时默默无闻,一旦出事立马“时光修复”。
3. Seata TCC 模式:
TCC(Try-Confirm-Cancel)是经典的业务层分布式事务方案,讲究 预占资源 + 明确提交 + 明确取消,就像保险理赔流程一样:
-
Try(尝试):试着“预定”资源,比如锁库存、冻结余额;
-
Confirm(确认):业务成功后,正式扣减资源;
-
Cancel(取消):业务失败后,释放资源,比如解冻、加回库存;
好处是:
-
每个步骤都由你自定义实现,可以控制资源精度;
-
不依赖数据库类型,适合对接第三方接口或 NoSQL 等异构系统;
-
更贴近真实业务流程,比如电商的“锁库存”逻辑就是天然的 TCC 模式;
但难点也很现实:
-
开发成本高:每个业务都得写三套接口(Try/Confirm/Cancel),劝退一批程序员;
-
接口幂等性 + 空回滚 + 悬挂问题,一个不注意就翻车,测试压力大;
TCC 更像一套“强制上保险”的流程,保得住,但保费(研发成本)也不低。
**-**04-
如何优雅地设计你的分布式事务方案
很多人学完分布式事务后脑袋里冒出一个问题:“那我到底该选哪种方案?”
答案其实很现实——“看场景,看代价,看你能不能扛得住。”
下面咱们从几个维度,来讲讲工程上如何优雅、聪明、不掉坑地搞分布式事务。
1. 场景为王:别为了一只鸡,用高射炮
分布式事务不是银弹,更不是标配。绝大多数业务,不需要那么“事务性”强的解决方案。
来看几个例子:
-
下单 + 扣库存 + 扣余额:属于强一致性场景,不能出现“钱扣了、订单没了”的情况,适合 TCC;
-
订单状态同步到搜索引擎、推荐系统:弱一致性,允许几秒延迟,MQ 异步补偿就够;
-
会员注册 + 送积分:注册成功是关键,送积分失败可以补发,不一定非要搞分布式事务;
所以第一步要问自己:“这几个操作,真的必须同时成功、同时失败吗?”
如果答案是“可以分步兜底”,那就别上 2PC / TCC 了,换轻量级方案。
2. 能拆就拆,别让事务撑破你的架构胃口
很多人一听“要分布式事务”,第一反应是引框架、上工具。其实工程界还有一个朴素哲学:
没有分布式,就没有分布式事务的烦恼。
这不只是玩笑,而是真·架构哲学。
举个栗子:
-
你有个“下单服务”,原本一个接口做了:
-
校验库存 → 扣减库存 → 插入订单 → 扣减余额;
-
后来你拆成了库存服务 + 订单服务 + 支付服务,于是“需要分布式事务”了;
那如果换个思路:
拆服务,但保留部分事务在一个服务里,重要流程走同步,辅助操作异步 MQ 补偿。
这样你既有拆分的模块化,又减少了对强事务的依赖。少用分布式事务,其实是最好的分布式事务策略。
3. 方案选型指南:实战中的“战术地图”
根据你的业务场景、对一致性的要求、以及团队技术能力,可以做一个大致选型:
选型的本质,就是权衡:开发成本 vs 一致性需求 vs 性能可接受度。
4. 兜底方案不能少:要有“救火队”
再完美的事务设计,也挡不住现实世界出 Bug。所以在上线前你必须准备好:
-
事务状态表:记录事务状态 + 恢复流程,防止中间挂掉后“失忆”;
-
幂等性控制:防止事务重试时“扣多次库存”;
-
补偿机制:比如消息重发、定时对账、人工处理通道;
-
监控告警:一出问题,第一时间能发现、能查到、能还原;
俗话说:“设计是理想主义,运营是现实主义。”
搞分布式事务不怕出错,怕的是错了没人知道、修不了、补不上。
写在最后:分布式事务,是一场“工程权衡”的艺术
分布式事务看似是技术问题,其实更像工程哲学:
-
要数据一致,还是系统高可用?
-
要强控制力,还是开发快上线?
-
要完美方案,还是可运营、可兜底?
你必须在技术、美学、现实之间做选择。因为没有哪种分布式事务方案是完美的,只有“对你当下业务、团队能力、资源限制”最合适的。
愿你在分布式事务的世界里,能收放自如,左手技术,右手哲学,带着业务一路向前冲。
**-**05-
粉丝福利
点点关注,送你 Spring Cloud 微服务实战,如果你正在做项目,又或者刚准备做。可以仔细阅读一下,或许对你有所帮助!