ICP备案

备案站点的 Saga 分布式事务与补偿机制

作者:备案源头内容团队内容审核:备案源头内容团队更新于 2026年10月2日

跨服务的业务做了一半,已经做掉的部分怎么收回来

单个数据库内部的事务有个很舒服的性质:要么全部成功,要么全部不生效,中间状态对外不可见。但一笔业务跨越多个服务、每个服务各自管着自己的数据库时,这个性质就消失了——订单服务创建了订单、库存服务扣减了库存,支付服务却失败了,此时前两步已经各自提交到了各自的数据库里,没有任何机制能把它们一起"回滚"掉。

Saga 模式给出的思路是:既然没法回滚,就用一个反向操作把已经做掉的事情抵消掉。扣了库存就加回去,创建了订单就标记取消,已经付的款就发起退款。这些反向操作叫做补偿,而 Saga 就是"一串正向操作 + 对应的一串补偿操作"的组合。

关键要点

  • Saga 用"补偿"替代"回滚",这不是等价替换:补偿是一次新的业务操作,会留下痕迹,而回滚不会。
  • 补偿操作必须满足幂等、可重试、且在正向操作成功后任何时刻都能执行这三个性质,否则 Saga 本身会成为新的故障源。
  • Saga 执行期间存在业务可见的中间态,这是和数据库事务最本质的差异,必须在业务设计层面接受并处理。
  • 卡在半途的 Saga 实例不会自己解开,需要专门的巡检和人工介入通道,这部分运维成本经常被低估。

编排式与协同式:运维可观测性差异很大

维度 编排式(有中心协调者) 协同式(服务间事件驱动)
流程定义位置 集中在协调者里,一处就能看全流程 分散在各服务的事件处理逻辑里
排查难度 较低,协调者有完整的执行记录 较高,需要跨服务拼凑事件时序
耦合度 协调者需要知道所有参与方 服务之间只依赖事件,耦合更松
单点风险 协调者本身是关键依赖,需要高可用 无中心节点,但流程的整体状态无人掌握

从运维角度看,编排式明显更友好:出问题时能从协调者的执行记录里直接看到"这笔业务走到了哪一步、哪一步失败了、补偿执行到了哪里"。协同式虽然在架构上更解耦,但代价是没有任何一个地方能回答"这笔业务当前的整体状态是什么",排查时要从多个服务的日志里按业务标识拼凑完整时序,见 日志规范与集中检索 中关于请求标识串联的讨论,这类跨服务链路的追踪能力见 可观测性建设。

协同式依赖事件可靠投递,事件丢失会导致流程永久卡住,相关的投递保证与幂等消费见 消息队列与异步任务运维。

补偿操作必须满足的三个性质

补偿不是随便写一个"反向操作"就行,它有硬性要求:

  • 幂等:补偿可能因为网络超时被重复触发,重复执行必须不产生额外影响。这和其他场景的幂等要求是同一套原则,见 超时设置与重试策略。
  • 可重试:补偿本身也可能失败(下游暂时不可用),必须支持重试直到成功,而不是失败一次就放弃——补偿失败比正向操作失败更严重,因为它意味着系统停留在了不一致状态。
  • 总是可执行:正向操作成功之后的任何时刻,补偿都必须能执行成功。这一条最容易被违反:比如正向操作是"扣减库存",补偿是"加回库存",看起来没问题;但如果中间有另一个流程把这批库存下架删除了,补偿就无法执行了。

这三条里第三条的设计约束最强,它实际上要求正向操作不能产生"无法撤销"的副作用。已经发出去的短信、已经推送给用户的通知、已经触发的第三方不可逆操作,都属于补偿无法真正抵消的动作,这类操作应该尽量放在 Saga 的最后一步,或者干脆移出 Saga 之外,外部依赖的不可逆性见 第三方服务依赖治理。

中间态可见:和数据库事务最本质的差异

数据库事务的隔离性保证了未提交的中间状态对其他事务不可见。Saga 没有这个保证:从第一步执行完到最后一步完成的这段时间里,部分数据已经是修改后的状态,而另一部分还没有,这个不一致的中间态对其他业务逻辑、对报表统计、甚至对用户本人都是可见的。

这带来几个必须在业务层面处理的现实问题:

  • 用户可能看到"中间态"的数据:订单已创建但支付未完成、库存已扣减但订单还没生效,界面要能合理地展示这类过渡状态,而不是显示成一个让用户困惑的矛盾状态。
  • 并发的其他流程可能基于中间态做判断:另一笔业务读到了这个还在进行中的状态,并基于它做了决策,这类问题需要用业务层的状态机约束来规避,而不能指望隔离级别帮忙。
  • 报表和对账要能识别进行中的 Saga:统计时如果把中间态当成最终状态计入,数据就是错的,对账逻辑要能区分"已完成""进行中""已补偿"这几类状态。

卡在半途的 Saga:不会自己解开

这是 Saga 运维里最容易被低估的部分。一个 Saga 实例可能因为各种原因卡住:某个参与服务长时间不可用、协调者自身重启丢失了内存中的执行状态、补偿操作反复失败超过了重试上限、或者遇到了上文说的"补偿无法执行"的情况。

这些卡住的实例不会自己恢复,它们会一直停留在不一致状态,直到有人发现并处理。必要的运维能力包括:

  • Saga 执行状态必须持久化,而不是只存在协调者的内存里,否则协调者一次重启就丢失了所有进行中流程的状态,这类状态的可靠存储要求和普通业务数据一致。
  • 巡检机制定期扫描超时未完成的实例,超过预期执行时长还没有达到终态的,要主动告警,这类巡检任务的幂等与补偿设计见 定时任务运维:幂等、防重与补偿。
  • 提供人工介入通道:对于补偿确实无法自动完成的情况,需要有工具让运维或业务人员能查看卡住的流程、手动推进或手动标记处理结果,所有人工操作都要留痕,见 运维权限治理与操作审计。
  • 卡住实例的数量应该是一项常规监控指标,持续增长说明某个环节存在系统性问题,而不是偶发故障,告警接入见 备案网站监控告警体系。

什么时候不该用 Saga

Saga 的复杂度不低,引入它之前值得先确认是否真的需要:

  • 如果所有涉及的数据能收敛到同一个数据库,用普通的本地事务更简单可靠,强行拆分服务再用 Saga 把它们粘回来是本末倒置。
  • 如果业务能接受最终一致性且不需要补偿(比如"发送通知"这类失败了重试就好、不需要撤销的操作),用可靠的异步消息加重试就够了,不必上 Saga。
  • 如果涉及的步骤里有无法补偿的不可逆操作,Saga 提供的一致性保证实际上是打折的,需要重新审视业务流程设计,而不是硬套模式。

分片场景下跨分片的操作也常被认为需要 Saga,但实际上优先考虑的应该是调整分片策略让相关数据落在同一分片,见 分库分表架构与运维实践 中关于把强一致性需求收敛到单分片的讨论。

常见坑

  • 补偿操作不幂等:超时重复触发时产生额外的影响,比如库存被重复加回。
  • 正向操作包含不可逆副作用:已发短信、已推送通知无法真正撤销,补偿形同虚设。
  • Saga 执行状态只存在内存里:协调者重启后,所有进行中的流程状态全部丢失,无从恢复。
  • 没有卡住实例的巡检和告警:不一致状态长期存在却无人知晓,直到用户投诉或对账发现差异。
  • 忽视中间态对业务和用户的可见性:界面展示矛盾状态、报表把中间态当最终态统计。

常见问题

Saga 和两阶段提交有什么区别?

两阶段提交追求的是强一致性,所有参与方要么一起提交要么一起放弃,代价是需要锁定资源等待协调结果,且协调者故障时参与方可能长时间阻塞。Saga 放弃了强一致性,用补偿换取了更好的可用性和更低的资源占用,接受过程中存在不一致的中间态。两者的取舍方向完全不同。

补偿操作失败了怎么办?

必须持续重试直到成功,这是 Saga 设计的基本假设。如果重试多次仍然失败,说明遇到了"补偿无法执行"的情况,需要升级到人工介入处理,并且要把这类案例作为设计缺陷来复盘——理想情况下补偿应该总是可执行的。

协调者需要做到什么级别的高可用?

编排式 Saga 的协调者是关键依赖,它不可用时新的业务流程无法启动、进行中的流程也无法推进。高可用标准应该对齐核心业务服务,并且执行状态必须持久化而非仅存内存,避免重启导致状态丢失。

小规模系统有必要引入 Saga 吗?

多数情况下没必要。如果能把需要一致性保证的数据放在同一个数据库里用本地事务解决,就不要引入 Saga——它的复杂度和长期运维成本(状态持久化、巡检、人工介入通道)都不低,只有在服务边界确实无法合并、且业务对一致性有实质要求时才值得投入。

资料来源

分布式事务领域关于 Saga 模式与补偿事务的公开技术资料,以及微服务架构中关于最终一致性设计的通用工程实践。本文为通用工程说明,仅供参考,具体方案请结合服务边界与一致性要求设计。

相关阅读

网站访问日志留存与安全合规运维要点

为什么要留日志:这是法定要求 《网络安全法》第二十一条明确要求网络运营者"采取监测、记录网络运行状态、网络安全事件的技术措施,并按照规定留存相关的网络日志不少于六个月"。已完成备案、对外提供服务的网站属于网络运营者范畴,日志留存不是可选项,而是基础合规义务。 应留存哪些日志 | 日志类型 | 记录内容 | 主要用途 …

网站新增域名如何补充接入备案

企业在原有网站基础上新增域名,比如启用新的品牌域名或拼音域名指向同一网站时,不能直接绑定使用,而是需要在原备案基础上补充办理新增域名的接入手续。 新增域名前的准备工作 新增域名前,建议先确认该域名已经完成实名认证,可以通过 Whois查询 核对域名的注册信息和实名状态,避免因域名信息未实名导致接入申请被退回。同时确认…

备案信息年度核查该如何配合应对

部分省份的通信管理部门会对辖区内已备案网站开展年度或不定期核查,核查方式包括系统比对、电话回访、短信确认等,目的是确认备案信息与网站实际运营情况是否一致。 核查通常关注哪些内容 年度核查一般围绕主体信息、网站信息、接入信息三个维度展开,具体可以对照下表自查: | 核查维度 | 常见核查点 | | --- | --- …

备案号在网站上的规范展示与使用要求

网站完成备案只是第一步,备案号在页面上的展示方式同样需要长期维护,很多主体正是因为展示细节不规范,在日常巡查或年度核查中被要求整改。 展示位置与基本要求 通常做法是将备案号放置在网站首页底部,文字需清晰可辨、不被图片或广告遮挡,且格式应与下发的备案号文本保持一致,不能随意增减字符或调整顺序。是否需要加超链接指向查询入…

备案注销之后重新申请要注意什么

有些主体在此前因业务调整、接入商变更等原因注销了原有备案,之后又因新的业务需要重新申请备案。这种“二次备案”与首次备案在流程上大体相似,但有几个环节容易被忽略。 重新申请前的自查 重新申请前,建议先用 ICP备案查询 确认原备案是否确实已经完成注销,避免出现原备案未彻底清空、新申请与旧记录冲突的情况。同时检查计划使用…

备案信息变更有没有时效要求

备案不是办理完成后就一劳永逸的事项,主体信息、网站信息或联系方式一旦发生变化,通常需要在信息变化后的一定时间内完成变更提交,具体时限以属地管局要求为准。 哪些变化需要及时申报 常见需要变更的情形包括:主办单位名称或证件信息变化、网站负责人更换、联系电话或邮箱失效、网站域名调整、网站内容服务类型发生实质变化等。这类变更…

公司迁址之后备案地址信息如何更新

企业办公地址或注册地址发生变化后,备案信息中登记的地址项也需要相应更新,尤其是当迁址涉及跨区、跨市甚至跨省时,办理流程会比同城内迁址更复杂一些。 迁址后需要关注的信息 迁址后首先要确认工商登记信息是否已经完成同步变更,备案地址一般以工商登记的最新地址为准。可以先用 ICP备案查询 查看当前登记的主办单位地址,与最新的…

备案预留手机号邮箱变更该如何更新

备案信息中登记的手机号和邮箱,是管局与接入服务商联系网站负责人的主要渠道,用于发送核查通知、验证短信、审核结果等重要信息。这些联系方式一旦更换却未同步更新,容易导致关键通知被漏收。 常见需要更新的场景 负责人更换手机号或离职导致原号码停用; 企业邮箱系统迁移,原邮箱地址不再使用; 备案负责人变更,联系方式随之更换。 …

系统学习