分布式事务解决方案:一个被裁老广程序员的血泪实践

Shell脚本侠
2025-12-23 13:38
阅读 433

去年十月,广州下着那种湿漉漉的“回南天”,我坐在珠江新城某大厂的会议室里,HR递给我一杯冰美式,然后轻描淡写地说:“公司战略调整,你这岗位……没了。”

那一刻我脑子是空的。不是因为震惊——互联网寒冬早有预兆,而是因为我刚交完这个月3500块的老城区一居室房租,老婆还在备孕,银行卡余额勉强够撑三个月。

更讽刺的是,我手头上正负责一个微服务重构项目,核心难点就是分布式事务。结果我人还没走,代码就得交接,连个完整的解决方案都没跑通。那天晚上回家,我在荔湾路夜市吃了碗牛杂,边吃边刷招聘APP,发现90%的岗位写着“熟悉分布式事务者优先”——可真他妈魔幻。


从“我以为我会”到“我根本不会”

被裁后头两周,我投了二十多份简历,面了七八家,有家公司技术总监直接问我:“你们之前怎么处理跨服务的订单-库存一致性?用Seata还是自研?”
我支支吾吾说用了TCC,但没跑通最终一致。他笑了笑:“那算了,我们这边要求上线即稳定。”

那一刻我才意识到:分布式事务不是面试题,是生产环境里的生死线

后来接了个外包单子,客户是做跨境电商的,系统用 Spring Boot 搭的订单、支付、库存三个微服务,还混着个用 Python 写的风控模块(别问为啥混语言,老板说Python写规则快)。需求很简单:用户下单要扣库存、生成支付单、触发风控校验——三件事要么全成功,要么全失败。

听起来不难?等你真上手就知道什么叫“分布式地狱”。


踩坑实录:那些让我凌晨三点还在改代码的方案

方案1:两阶段提交(2PC)?算了吧!

一开始我想上JTA + Atomikos,标准2PC。结果一测性能直接崩了——TPS从800掉到80。客户老板在群里@我:“能不能快点?我们大促就下周了!”
我苦笑:2PC锁资源太狠,库存服务一卡,整个链路都挂。在真实业务里,没人等你“协调者”慢慢投票

而且那个Python风控服务根本不支持XA协议!我总不能为了它重写成Java吧?时间+钱都不允许。

方案2:消息队列+本地消息表(最终一致)

这次我学聪明了。参考阿里早期的做法:

  1. 订单服务创建订单时,同时往本地message_outbox表插一条待发送消息(和订单在同一个DB事务里)
  2. 后台有个定时任务轮询这张表,发消息到RabbitMQ
  3. 库存、支付、风控服务各自消费,处理失败就重试

优点:简单、可靠、不依赖外部事务协调器。
缺点:代码啰嗦,每个服务都要维护出站/入站消息表;重试机制得自己写;Python服务消费消息还得装pika库,调试起来心累。

最要命的是——有一次MySQL主从延迟,订单创建了,但消息还没同步到从库,定时任务扫不到,导致支付单没生成。用户付款成功,却没发货。客服电话被打爆,我赔了客户500块红包才平息。

方案3:Saga模式 + 补偿事务(终于靠谱了)

痛定思痛,我决定上 Saga。逻辑很简单:

  • 正向流程:Order → Payment → Inventory → RiskCheck
  • 任一环节失败,就逆序执行补偿:CancelRisk → RestoreInventory → RefundPayment → CancelOrder

关键点在于:每个服务必须提供幂等的补偿接口

我在Spring Boot服务里用注解+状态机管理Saga流程:

@SagaStep(service = "inventory", action = "deduct", compensate = "restore")
public void deductInventory(Order order) {
    // 调用库存服务扣减
}

而那个Python风控服务,我逼着自己用Flask写了两个接口:

  • POST /risk/check (幂等)
  • POST /risk/cancel (幂等,传相同requestId就只取消一次)

为什么Saga这次成了?

  1. 无长时间锁:每个服务本地事务独立,不阻塞
  2. 语言无关:只要HTTP接口规范,Python/Go/Node都能接入
  3. 可观测性强:我在数据库加了saga_execution_log表,每一步状态清清楚楚

上周五晚上十一点,客户大促峰值来了。我盯着Grafana看监控:订单量飙到3000/min,Saga成功率99.87%,失败的那0.13%全是风控拒绝(正常业务逻辑),没有一笔数据不一致

那一刻我在出租屋里灌了罐珠江啤酒,差点哭出来——不是因为成功,是因为终于不用再背锅了。


给同行的真心话:别信“银弹”,要信“场景”

很多人问我:“Seata不好吗?为啥不用?”
我说:Seata确实牛,AT模式对业务侵入小。但你得考虑几点:

  1. 团队能力:我们外包团队就3个人,一个前端,一个Java(我),一个兼职Python。搞Seata要运维ZK/Nacos/TC,出了问题谁调?
  2. 成本:Seata需要所有服务用同一数据库类型(比如都是MySQL),但我们风控用PostgreSQL存规则——改架构?客户预算只够付我22k月薪。
  3. 复杂度:Seata在高并发下有性能损耗,而Saga靠异步+幂等,反而更稳。

所以我的结论很土:

  • 如果你的系统全是Java + Spring Cloud Alibaba,且有专职中间件团队——上Seata。
  • 如果你像我一样混语言、小团队、求稳不求新——Saga + 本地消息表 是性价比之王。
  • 别碰2PC,除非你在银行写核心系统(而且他们现在也不用2PC了)。

被裁之后,我反而更懂“事务”了

分布式事务的本质是什么?不是技术,是妥协的艺术

你要在一致性、可用性、性能、开发成本之间找平衡点。就像我现在的生活:不再追求大厂title,而是接能交付、能赚钱的活;不再迷信“高大上”框架,而是用最土但最稳的方式解决问题。

上个月,我把这套Saga方案封装成一个轻量级starter,开源到GitHub(搜guang-saga-spring-boot-starter),Star不多,但有几个老广同行私信我说“帮大忙了”。那一刻我觉得,被裁未必是坏事——至少我不再是个只会背八股文的螺丝钉了

如果你也在焦虑分布式事务,记住:

没有完美的方案,只有适合你当下处境的方案
技术是死的,人是活的。活下去,才有资格谈架构。


最后说句题外话:最近接了个新单子,客户指名要用Python写全套后端。我翻出尘封三年的Django手册,一边啃肠粉一边看。老婆笑我:“你不是说再也不碰Python了吗?”
我说:“为了下个月的奶粉钱,别说Python,让我写COBOL我都干。”

毕竟,在广州这座务实的城市里,能跑通的代码,才是好代码

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝