微服务拆分之后,一次下单往往要同时改动好几个库:扣库存、扣余额、写订单。哪一步失败,数据就可能对不上。阿里云GTS(全局事务服务)就是为这类问题准备的分布式事务产品,底层基于开源的Seata框架,事务协调器由阿里云托管。业务代码只需要少量改造,就能拿到跨服务的事务一致性保障。但它并不适合所有场景,有些情况上线前最好先别直接套用。

分布式场景下,事务为什么难
单机数据库里,一个本地事务就能保证原子性。服务拆开后,每个服务有自己的库,本地事务各自提交,彼此看不见。假如订单服务已经提交,库存服务却因为网络超时失败,系统就停在了不一致的状态:订单有了,库存没扣;或者钱扣了,订单没生成。这类问题在测试环境里往往看不出来,流量上来之后才会冒出来。
两阶段提交(2PC)能解决一致性,但资源锁定时间长,高并发下吞吐受限,协调者本身也可能成为单点。很多团队只能退而求其次,改用补偿机制。补偿要自己写回滚逻辑,代码量大,漏掉一个分支就是一个坑。
三种模式各自适合什么
AT模式:改造最少,但要盯住表结构
AT模式最接近本地事务的写法。执行SQL时,框架会记录数据变更前后的镜像,写入undo_log表。提交后异步清理,回滚时根据镜像反向补偿。开发者只需要在入口方法上加全局注解,不用手写补偿代码。大多数关系型数据库的增删改查场景都适合它。
undo_log表是这套机制的基础。它要纳入备份和监控,表被误删或者增长失控,事务的回滚能力就会受影响。
TCC模式:资源控制细,接口要写得稳
TCC要求业务方实现三个接口:Try预留资源,Confirm确认提交,Cancel释放资源。好处是资源锁定粒度可控,性能通常比长时间持锁的方式好,适合库存、额度这类必须精确控制的资源。
代价是代码量明显增加,还有几个老问题要处理。接口必须幂等,否则网络重试会导致重复扣减。Cancel可能先于Try到达,需要处理空回滚。Try失败后Cancel又被补偿到,还会出现悬挂,需要记录事务状态来识别。这些做不好,线上很难排查。
SAGA模式:适合长流程,中间状态要接受
SAGA把长事务拆成一串本地事务,每一步都配一个补偿操作。审批流、物流履约这类耗时长、牵涉多个外部系统的流程,用它比较合适。
它不保证隔离性。中间状态对外是可见的,比如订单已经进入“待审批”,最终可能被撤回。页面展示、查询接口和对账逻辑都要按这个前提设计,否则用户会看到前后矛盾的状态。
一个下单链路的改造例子
拿一个电商下单链路来看。这条链路包含四个服务:订单、库存、账户、优惠券。拆分后如果初期只靠手动补偿,每次异常都要人工核对数据,工单堆积得很快。
引入GTS后,可以这样分工:
- 下单入口方法加上全局事务注解,由GTS分配全局事务ID,把四个服务的分支事务串起来。
- 库存扣减走AT模式,原有SQL基本不动,只多一张undo_log表。
- 优惠券核销涉及外部券系统,改用TCC,预留和确认分开,避免同一张券被重复使用。
- 每天凌晨跑一次对账任务,扫描未完成的全局事务,超时未结束的交给GTS的回查机制处理。
落地之后,这类不一致工单明显减少。过程中有几处要留意。undo_log表一旦出问题,回滚就不可靠,备份和监控要跟上。TCC接口的幂等不能省,否则重试就是重复扣减。全局事务的超时时间要结合业务实际耗时来定:设得太短,正常请求也会频繁回滚;设得太长,锁会长时间占着,别的请求只能排队。
哪些场景先别直接上
有几类情况,建议先停一下,不要急着全量接入。
- 涉及无法回滚的外部动作,比如已经发出的短信、已经提交给银行的转账。这类动作不在数据库里,AT模式的镜像回滚管不到,需要单独设计补偿。
- 高频热点库存,比如秒杀扣减。TCC或全局锁在这种场景下竞争激烈,先在压测里跑出吞吐数据,再决定用不用。
- 业务链路还没理清。哪些步骤必须强一致、哪些可以最终一致,如果团队说不清,分布式事务只会把问题放大。
- 数据库类型或版本不在支持范围内,或者表结构变动频繁。AT模式对SQL和表结构有前提要求,变更前要先确认兼容性。
上线前的三个检查动作
上线前可以先在测试环境模拟网络超时和服务宕机,逐条走一遍回滚路径。很多问题只在异常场景下才会暴露,正常流程跑通并不能说明什么。
监控上最好接入全局事务耗时、回滚率、悬挂事务数量,并设好告警阈值。上线第一周最好有人专门盯着。
另外,并非所有操作都需要分布式事务。能用本地事务或最终一致解决的,就不必硬上全局事务,否则会拖慢整条链路。
GTS把分布式事务的复杂度收拢到几种模式里,选哪一种,主要看业务的一致性要求和资源特点。它替代不了清晰的领域划分,但能省下不少自己造轮子的时间。