ARTICLE / 3 MIN READ
订单支付库存的一致性如何落地
用状态机、Outbox 和补偿任务处理跨服务写入,避免把分布式事务变成不可调试的黑盒。
订单、支付和库存通常属于不同服务,却共同决定用户是否成功购买。跨服务一致性不等于所有操作都同步提交,而是让每个状态变化可追踪、可重试、可补偿。
先定义业务状态机
订单待支付 -> 支付处理中 -> 支付成功 -> 待发货
| | |
v v v
已取消 支付失败 退款中
每次转换都要校验前置状态、操作者和幂等键。支付回调重复到达时,只有第一次能把待支付改成支付成功,后续请求返回已处理。
Outbox 保证事件不丢
业务表和 outbox 表在同一个本地事务中提交。事务成功后,由后台投递器把 outbox 事件发送到消息队列;发送成功再标记已发送。
本地事务:
UPDATE orders ...
INSERT INTO outbox(event_id, aggregate_id, payload)
提交
后台投递 -> MQ -> 消费者 -> 幂等处理
这样即使服务在提交后立即崩溃,事件仍然留在 outbox 中可继续投递。投递器要有锁、批量发送和失败退避。
Saga 和补偿
库存预扣成功但支付失败时,需要执行释放库存的补偿动作。补偿不是简单地“再写一次”,要检查原操作是否确实成功,并记录补偿结果。
每个步骤都保存业务流水和关联的 saga ID,最终形成一条可审计链路。补偿失败进入人工处理队列,不能无限重试把下游打满。
事务消息的边界
两阶段提交会增加锁持有和协调器复杂度,适合资源少、强一致要求高且延迟可接受的场景。多数互联网订单更适合本地事务加可靠事件,再用状态机和对账保证收敛。
对账比“理论一致”更重要
每天按订单号、支付流水号和库存流水号做三方对账,发现“支付成功但订单未变更”“订单成功但库存未扣减”等差异,自动生成补偿任务。对账结果和修复动作必须留下审计记录。
分布式一致性的终点不是所有服务永远同时成功,而是任何中间状态都有出处、下一步和可验证的恢复路径。
GITHUB DISCUSSION
评论与回复
评论保存在 GitHub Discussions,登录 GitHub 后即可参与,发布和回复都在本页完成。
评论区进入视口后自动加载。