在分布式系统中,跨服务的长事务无法用传统ACID保证一致性,Saga通过正向操作和补偿操作配对来实现最终一致。本文深入讲解Saga的补偿设计原则、异常处理策略和与TCC及2PC等方案的对比。适合设计高可用分布式系统和处理跨服务事务的架构师。

学习提示

需要学习Saga长事务与补偿,大数据处理(Spark/Flink)本质是分布式计算。本篇涵盖CAP理论、分布式共识、消息队列、高并发,帮助你构建高可用分布式系统。

目录
  1. 可视化演示
  2. AI 应用场景
  3. Python 演示
  4. 常见误区
  5. 面试题

可视化演示

状态—

在分布式系统中,跨服务的长事务无法用传统ACID保证一致性,Saga通过正向操作和补偿操作配对来实现最终一致。本文深入讲解Saga的补偿设计原则、异常处理策略和与TCC及2PC等方案的对比。适合设计高可用分布式系统和处理...

事务困境起源

假设你要把婚礼筹备的所有项目都托付给一家"全能婚庆公司",他们有一个统一的后台系统,所有环节都能在一个数据库里原子完成——这就是本地事务的舒适区。但现实是,你需要分别对接酒店、花店、蛋糕店、印刷厂,它们各自拥有独立的系统和数据库。你试图让它们"协同作战",却发现没有一个总管能同时指挥所有人。

在计算机世界里,这种困境叫做"分布式事务问题"。数据库的ACID特性(原子性、一致性、隔离性、持久性)就像婚庆公司的内部规章,只在自家地盘有效。一旦跨到多个服务,ACID就失效了——不同服务的数据库各自为政,没有共享的锁和日志。更令人头痛的是,事务涉及的步骤越多,整体成功率越低:假设每个步骤的成功率都是90%,10个步骤全部成功的概率就只剩35%。你的婚礼筹备有20个环节,算下来几乎没有一次能从头顺利到尾。

单步成功率p乘以自己n次(n个步骤),就是整个事务的成功率。步骤越多,成功率衰减越厉害。

P(全部成功)=pn\displaystyle P(\text{全部成功}) = p^n
  1. 基底 $p$单个本地事务的成功概率,受网络延迟、服务故障等影响,通常小于1
    p∈(0,1)\displaystyle p \in (0, 1)
  2. 指数 $n$长事务拆分的步骤总数,服务越多 $n$ 越大
    n≥2\displaystyle n \geq 2
  3. 整体成功率 $P$全部 $n$ 步都成功的概率,$p<1$ 时随 $n$ 指数衰减 所以,婚礼筹备不能指望"万事俱备一次成功",而是要提前想好每一步的退路。分布式系统的设计者同样认识到:与其追求不可能完美,不如设计一套"失败也没关系,能恢复就行"的机制,这正是Saga诞生的土壤。
    P=pn\displaystyle P = p^n

Saga核心概念

筹备婚礼时,你最好的策略是什么?把大目标拆成一个个小合约:今天跟酒店签合同,明天跟花店下单,后天定蛋糕——每个合约都可以独立履行,也都有违约条款。这就是Saga的第一层智慧:长事务拆分。

Saga把一个跨服务的长事务拆分成 $n$ 个本地事务 $T_1, T_2, \ldots, T_n$,每个本地事务都在单个服务内独立提交。关键是,每一个正向操作 $T_i$ 都配备一个补偿操作 $C_i$——就像每份合同都附带违约条款。如果某一步失败,就执行前面已成功步骤对应的补偿操作,把业务状态"拉回"起点附近。Saga不要求所有服务"同时成功",它接受暂时的中间状态,只要最终所有步骤要么全部完成、要么全部撤销,就达到了最终一致性。

Saga就是一组"正向操作+补偿操作"的配对列表,每个正向操作都有一个对应的撤销方案。

Saga={(T1,C1),(T2,C2),…,(Tn,Cn)}\displaystyle \text{Saga} = \{(T_1, C_1), (T_2, C_2), \ldots, (T_n, C_n)\}
  1. 正向操作 $T_i$第 $i$ 个本地事务,在单一服务内正常提交并生效
    Ti: 本地原子提交\displaystyle T_i: \text{ 本地原子提交}
  2. 补偿操作 $C_i$与 $T_i$ 配对的逆向业务动作,用于抵消 $T_i$ 带来的影响
    Ci: 业务撤销动作\displaystyle C_i: \text{ 业务撤销动作}
  3. 配对关系每个 $T_i$ 必须有且仅有一个对应的 $C_i$,这是Saga的基本约束 回到婚礼现场,Saga编排器就是你手中的"婚礼筹备总清单"。你每完成一项,就打一个勾;一旦某个环节出了差错,你按清单逆序打电话,一项项取消。每个合同都有取消条款,这就是Saga的本质——用一组精心设计的"退路"来对抗不确定性。
    (Ti,Ci),i=1,2,…,n\displaystyle (T_i, C_i), \quad i = 1, 2, \ldots, n

补偿设计原则

既然补偿是你的"退路",那退路本身要满足什么条件?想象你取消宴会厅预订时,酒店说"可以退,但定金不退";取消鲜花订单时,花店说"已经包好的花束没法退,但可以换成抵扣券"——这些补偿动作并不完美,但确实把损失降到了最低。设计补偿操作时,要遵循三个核心原则。

第一是可逆性:每个正向操作 $T_i$ 必须有一个明确的补偿操作 $C_i$,能大体抵消 $T_i$ 的业务效果。第二是幂等性:补偿操作被重复执行多次,结果必须一致——就像给酒店打两次电话取消,不能扣两次违约金。第三是状态持久化:每一步的执行状态(待执行、已执行、已补偿)必须记录在可靠的存储中,一旦系统崩溃重启,依然知道进行到哪一步。

第一个等式表示"先正向后补偿"能恢复原状;第二个等式表示"补偿再补偿"还是补偿同样效果——这就是幂等性。

Ci(Ti(x))=x,Ci(Ci(x))=Ci(x)\displaystyle C_i(T_i(x)) = x, \quad C_i(C_i(x)) = C_i(x)
  1. 恢复原状 $C_i(T_i(x)) = x$对状态 $x$ 先执行 $T_i$ 再执行 $C_i$,业务状态回到原点(或等效状态)
    Ci∘Ti=Id\displaystyle C_i \circ T_i = \text{Id}
  2. 幂等约束 $C_i(C_i(x)) = C_i(x)$重复执行补偿不改变结果,避免重试引发二次扣款等事故 这就像你给每个供应商下订单时,都确认一遍"如果取消怎么算"。想清楚可逆性,你会提前剔除那些"无法取消"的高风险环节;想清楚幂等性,你在网络抖动重复打电话时也不会慌。好的补偿设计,让Saga在真实世界的各种意外面前依然从容。
    Ci2=Ci\displaystyle C_i^2 = C_i

执行模式

婚礼筹备的推进方式有两种:要么一项接一项地办——先订场地,场地定了再订鲜花,鲜花定了再订蛋糕;要么同时推进多项——一边订场地,一边订鲜花,一边联系蛋糕店。Saga也有这两种执行模式。

串联模式下,$T_1$ 执行完提交后,才开始 $T_2$,以此类推。这种方式逻辑简单,但总耗时长。并列模式则把互不依赖的步骤并行执行,提高吞吐,适合步骤之间没有严格先后顺序的场景。无论哪种模式,都需要一个状态机来管理流程的流转:每个步骤都有"待执行→执行中→完成/失败"的状态迁移,编排器根据当前状态决定下一步是继续正向还是转入逆向补偿。状态机还解决了崩溃恢复问题——如果执行到一半宕机了,重启后从持久化状态中读出"进行到哪一步",就知道该继续还是该补偿。

串联是"一个接一个"的链条;并列是"同时开工"的并联网。

串联: T1→T2→⋯→Tn,并列: T1∥T2∥⋯∥Tn\displaystyle \text{串联: } T_1 \rightarrow T_2 \rightarrow \cdots \rightarrow T_n, \quad \text{并列: } T_1 \parallel T_2 \parallel \cdots \parallel T_n
  1. 串联链 $\rightarrow$严格顺序执行,前序步骤提交后,后续步骤才启动
    Ti→Ti+1\displaystyle T_i \rightarrow T_{i+1}
  2. 并列符 $\parallel$步骤之间无依赖,可同时执行
    Ti∥Tj\displaystyle T_i \parallel T_j
  3. 状态机用有限状态 $S = \{\text{待执行}, \text{执行中}, \text{完成}, \text{补偿中}, \text{已补偿}\}$ 驱动流程 现实中的婚礼筹备往往是混合模式:场地和蛋糕可以并行去谈,但请柬必须等场地确认后才能发出。Saga的编排器就像你的婚礼统筹助理,按照一张"依赖关系图"调度所有任务,并在每一步记录进度。只要状态机正确,无论多么复杂的流程,都能在意外发生后有条不紊地收场。
    Sk+1=f(Sk,事件)\displaystyle S_{k+1} = f(S_k, \text{事件})

异常处理策略

筹备婚礼时,最怕的不是某个供应商拒绝你,而是出了问题不知道找谁、该先撤哪个。Saga的异常处理策略提供了清晰的行动指南。

首先失败定位:编排器必须能准确捕获"第几步抛出了异常"。就像你收到蛋糕店的电话,确认是蛋糕环节出了问题。然后触发逆向补偿:从失败步骤的前一步开始,逆序执行已成功步骤的补偿操作。注意,第 $k$ 步自身如果失败且未提交,它不需要补偿——它的"半成品"状态由本地事务自行回滚。如果第 $k$ 步是"提交了但业务上认为失败"(比如对方扣款了但没返回成功),才需要补偿第 $k$ 步。

超时策略也至关重要:调用某服务长时间无响应时,不能无限等下去,通常在超时后把该步骤标记为失败并触发补偿。最后是人工介入:如果某一补偿操作反复重试仍然失败,就抛出告警,转人工处理——就像你打不通花店的电话,只能亲自跑一趟店里协调。

只要有一个正向步骤失败,Saga就进入补偿流程;只有当所有正向步骤都提交成功,事务才算成功。

终态={成功∀i, Ti 提交补偿∃i, Ti 失败\displaystyle \text{终态} = \begin{cases} \text{成功} & \forall i,\ T_i \text{ 提交} \\ \text{补偿} & \exists i,\ T_i \text{ 失败} \end{cases}
  1. 全称量词 $\forall$所有步骤 $T_i$ 全部提交,才判定Saga成功
    ∀i∈{1,…,n},Ti=成功\displaystyle \forall i \in \{1, \ldots, n\}, T_i = \text{成功}
  2. 存在量词 $\exists$只要有一步失败,触发补偿
    ∃i,Ti=失败⇒执行 Ci−1,…,C1\displaystyle \exists i, T_i = \text{失败} \Rightarrow \text{执行 } C_{i-1}, \ldots, C_1
  3. 补偿范围从 $i-1$ 逆向补偿到 $1$,不含失败的 $T_i$ 自身 这就是Saga在异常面前的三部曲:定位、逆补、兜底。就像婚礼筹备手册里写的应急预案——先冷静确认是谁的问题,再按清单逆序取消,实在搞不定就亲自上门。有了这套策略,你不再害怕意外,因为每一个意外都有预案。
    {Ci−1,Ci−2,…,C1}\displaystyle \{C_{i-1}, C_{i-2}, \ldots, C_1\}

方案对比选型

分布式事务不止Saga一种解决方案。理解它们的差别,就像理解不同婚礼筹备策略的适用场景。

2PC(两阶段提交)像一场"全体确认会议":先问所有供应商"能不能做",大家都说"能",才统一正式下单;只要有一家犹豫,所有人都等着。优点是强一致,缺点是阻塞——如果有一家一直不回复,其他所有人的资源都被锁住。TCC(补偿事务)像"先占坑再确认":Try阶段把所有资源预留好(占住场地、锁住鲜花库存),Confirm阶段真正使用,Cancel阶段释放预留。它比2PC灵活,但业务方要实现Try/Confirm/Cancel三套逻辑,成本高。Saga则是"先做了再说,不行就撤",不锁资源,吞吐最高,但一致性是最终的而非即时的。

选型的关键看业务容忍度:账务扣减这种强一致场景,用2PC或TCC;电商下单这种可以接受短暂不一致、更看重可用性的场景,用Saga最合适。这里的一致性强度与资源阻塞成反比——强一致通常意味着高阻塞,柔性一致则带来高可用。

三种方案在"阻塞时间"和"一致性强度"上的排序完全一致,选型就是在两者之间找一个平衡点。

资源阻塞: 2PC≫TCC>Saga,实时一致性: 2PC>TCC>Saga\displaystyle \text{资源阻塞: } 2PC \gg TCC > Saga, \quad \text{实时一致性: } 2PC > TCC > Saga
  1. 2PC 阻塞协调者等所有参与者回执期间,资源全部锁定
    阻塞2PC=max⁡i(等待i)\displaystyle \text{阻塞}_{2PC} = \max_i(\text{等待}_i)
  2. TCC 预留Try不真正执行,只锁定资源,Confirm才执行
    Try→Confirm/Cancel\displaystyle \text{Try} \rightarrow \text{Confirm/Cancel}
  3. Saga 无锁正向直接提交,失败后异步补偿,锁等待趋于零 给你的婚礼选方案:如果新娘说"所有项目必须全部确认,不许有半点含糊",那就用2PC,代价是所有人陪着等;如果预算宽松、想优柔寡断,TCC能让你先把好资源都占住;如果崇尚"先办起来,有问题再调整",Saga就是你的最佳拍档。理解了排序,选型就不再纠结。
    阻塞Saga≈0\displaystyle \text{阻塞}_{Saga} \approx 0

工程实践落地

设计好Saga的理论框架只是第一步,真正的挑战在于把它落地到生产环境。这里有几个最常见的工程坑。

幂等控制:补偿操作在网络重试下可能被执行多次,因此每个正向和补偿操作都要用全局唯一事务ID做幂等校验——就像给每个订单加上唯一编号,重复打电话取消时,系统识别出"这个订单已经取消过了",直接返回成功,不再重复退费。状态存续:Saga的状态机不能只存内存,要持久化到数据库,这样即使编排器宕机重启,也能从断点恢复。监控告警:为每个Saga实例建立监控指标(执行时长、成功/失败率、补偿链深度),在失败率突增时发出告警。容错演练:像消防演习一样,定期人为注入故障(比如随机让某步失败),验证补偿链路的完整性。

单次补偿成功率为 $p_c$,最多重试 $k$ 次,最终至少成功一次的概率就是 $P_{\text{恢复}}$。

P恢复=1−(1−pc)k+1\displaystyle P_{\text{恢复}} = 1 - (1 - p_c)^{k+1}
  1. 单次补偿成功率 $p_c$一次补偿操作成功的概率
    0<pc<1\displaystyle 0 < p_c < 1
  2. 重试次数 $k$补偿失败后允许重试的最大次数
    k∈N\displaystyle k \in \mathbb{N}
  3. 最终恢复率 $P_{\text{恢复}}$连试 $k+1$ 次,至少成功一次的概率,$k$ 越大越接近 1 这些实践听起来像"婚礼筹备的后勤手册":所有合同存档(状态存续)、电话确认有录音(幂等控制)、定期模拟取消流程(容错演练)。正是这些不起眼的工程细节,让Saga从纸面上的漂亮模型变成生产环境中真正可靠的架构方案。
    lim⁡k→∞P恢复=1\displaystyle \lim_{k \to \infty} P_{\text{恢复}} = 1

AI 应用场景

电商订单全链路

阶段:系统架构设计

解决的问题:传统下单链路涉及订单服务、库存服务、支付服务、积分服务,任何一个环节失败都会导致数据不一致。用2PC会锁库存导致大促时吞吐暴跌;用Saga将下单拆分为"创建订单→扣库存→扣款→加积分"四个本地事务,每个都配备补偿操作,任一步失败即逆向撤销。AI预测模型可分析历史失败模式,动态调整各步骤的超时阈值与重试策略。

具体案例:某头部电商大促期间,下单成功率从98.2%提升至99.6%,补偿触发时平均在800ms内完成逆向撤销,库存积压误差低于0.01%。

相关角色:分布式系统架构师、后端技术专家

云平台资源开通

阶段:资源编排自动化

解决的问题:开通一台云主机需要依次完成"创建VM→分配公网IP→挂载云盘→配置安全组"。若在配置安全组时失败,前面创建的VM和IP就变成孤儿资源。Saga将所有步骤封装为正向+补偿,一旦失败自动释放VM、回收IP、卸载云盘。AI运维系统实时监控Saga执行轨迹,对补偿失败项智能判断是否需要人工介入。

具体案例:某云计算厂商将资源开通失败率从1.2%降至0.3%,由补偿自动回收的闲置资源每月节省成本约15%。

相关角色:云平台研发工程师、AIOps平台工程师

Python 演示

python69 行
class SagaTransaction:    ""“Saga步骤:一个正向操作 + 一个补偿操作”""     def init(self, name, forward_fn, compensate_fn):        self.name = name        self.forward_fn = forward_fn        self.compensate_fn = compensate_fn  class SagaOrchestrator:    ""“Saga编排器:顺序执行正向操作,失败时逆向补偿”""     def init(self):        self.steps = []        self.done_steps = []        self.compensated_steps = []     def add_step(self, transaction):        self.steps.append(transaction)     def run(self):        for tx in self.steps:            try:                print(f“[正向] {tx.name}”)                tx.forward_fn()                self.done_steps.append(tx)            except Exception as exc:                print(f“[失败] {tx.name}: {exc}”)                self._rollback(tx)                return False        print(“[成功] 所有步骤完成”)        return True     def _rollback(self, failed_tx):        print(f“[回滚] 失败步骤:{failed_tx.name},开始逆向补偿”)        for tx in reversed(self.done_steps):            try:                print(f“[补偿] {tx.name}”)                tx.compensate_fn()                self.compensated_steps.append(tx)            except Exception as exc:                print(f“[补偿失败] {tx.name}: {exc},需人工介入”)  def book_venue():    print(“   宴会厅预定成功”) def cancel_venue():    print(“   宴会厅已取消,退回定金”) def book_florist():    print(“   鲜花预订成功”) def cancel_florist():    print(“   鲜花订单已取消”) def book_cake():    raise RuntimeError(“蛋糕店已满单”) def cancel_cake():    print(“   蛋糕订单已取消”)  if name == "main":    saga = SagaOrchestrator()    saga.add_step(SagaTransaction(“预订宴会厅”, book_venue, cancel_venue))    saga.add_step(SagaTransaction(“预订鲜花”, book_florist, cancel_florist))    saga.add_step(SagaTransaction(“预订蛋糕”, book_cake, cancel_cake))    saga.run()

常见误区

误区我用了Saga,事务失败时直接调用所有数据库的rollback(回滚)命令,把数据改回原样就行了,跟本地事务一样的逻辑。

正解补偿是业务层的逆向操作,不是数据库回滚。已提交的本地事务无法rollback,只能通过发起一个新的业务动作(比如"取消订单""退款")来抵消之前操作的影响。数据库rollback针对未提交事务,而补偿针对已提交但需要撤销的业务效果。

为何常见:本地事务的"回滚"概念深入人心,初学者容易把Saga的补偿和数据库回滚混为一谈。

误区补偿操作能把系统状态完全恢复到事务开始之前的样子,所以可以放心大胆地使用Saga。

正解补偿是"尽力而为"的逆向操作,不一定能完全恢复。比如已经发出的邮件无法撤回、已扣除的违约金无法追回、已消耗的资源无法还原。Saga保证的是"业务上可接受的最终状态",而不是"物理上的原始状态"。

为何常见:把补偿与数据库事务的"原子回滚"语义混淆,忽略了真实业务中逆向操作的局限性。

误区Saga执行到第k步失败了,应该先补偿第k步(把它的半成品效果也撤销掉),然后再依次补偿前面的步骤。

正解如果第k步是"未提交"的失败(抛异常未入库),其本地事务已自行回滚,无需补偿;需要补偿的是第1到第k-1步这些已成功提交的事务。但如果第k步是"提交后才发现业务异常"(比如对方处理成功但响应超时),则第k步也需要纳入补偿。

为何常见:混淆了"本地事务失败"和"Saga步骤失败"两个不同层面的概念。

误区既然Saga是分布式事务的通用方案,任何跨服务的写操作都可以用Saga来保证一致性。

正解Saga擅长的是"最终一致性"可接受的场景,如订单、预订、审批流。对于要求强一致性的场景(如银行转账的扣款与入账必须实时相等),Saga的中间不一致窗口不可接受,应选择2PC或TCC。选型必须基于业务的一致性要求。

为何常见:只看到Saga实现简单、性能高的优点,忽略了一致性强度这个关键约束。

误区只要补偿逻辑写对了,调用一次就会成功,不需要处理重复调用的问题。

正解分布式环境下,网络超时、消费重试、编排器宕机恢复都会导致同一个补偿操作被执行多次。如果补偿操作不幂等,重复取消订单可能重复扣违约金、重复退款、重复发通知。必须用事务ID做去重。

为何常见:本地开发环境网络稳定、流程可预期,很难自然意识到分布式环境的"重复"问题。

面试题

Q1. Saga长事务的核心思想是什么?

单选题 · easy

  • A.通过分布式锁保证强一致性
  • B.拆分成本地事务并配补偿操作← 正确答案
  • C.使用全局事务管理器统一协调
  • D.通过消息队列异步复制所有数据

答案:B。Saga的核心是把长事务拆分成多个可独立提交的本地事务,并为每个正向操作配备补偿操作,失败时逆向补偿,实现最终一致。它不是锁方案、不是全局事务,也不依赖异步数据复制。

Q2. 补偿操作的基本要求是什么?

单选题 · easy

  • A.比正向操作的执行速度更快
  • B.能够抵消正向操作带来的业务影响← 正确答案
  • C.必须操作同一个数据库
  • D.需要获取分布式锁才能执行

答案:B。补偿操作是业务层的逆向动作,用来抵消已提交正向操作的效果,比如"取消订单""退回定金"。它不要求速度更快,也不要求在同一个数据库执行,更不需要分布式锁。可逆性是补偿设计的首要原则。

Q3. 以下哪个场景最适合使用Saga事务?

单选题 · easy

  • A.单库内的一次账户转账
  • B.电商下单跨订单库存支付多服务← 正确答案
  • C.本地缓存的一次键值更新
  • D.日志系统的一次追加写入

答案:B。Saga适用于跨多个服务、需要最终一致的业务链路。单库转账用本地事务,缓存更新和日志写入连事务都不需要。电商下单跨订单、库存、支付等多服务,是Saga的经典场景。

Q4. 2PC和Saga最本质的区别是什么?

单选题 · mid

  • A.2PC支持更多的事务操作类型
  • B.2PC是强一致且阻塞资源而Saga最终一致← 正确答案
  • C.Saga要求必须使用消息队列
  • D.2PC不需要协调者角色参与

答案:B。2PC通过协调者让所有参与者同时提交或回滚,期间锁住资源,实现强一致;Saga则让每个本地事务独立提交,失败后异步补偿,不阻塞资源,实现最终一致。两者一致性模型根本不同。

Q5. 为什么补偿操作必须设计成幂等的?

单选题 · mid

  • A.因为正向操作天然不是幂等的
  • B.因为网络重试可能导致补偿执行多次← 正确答案
  • C.为了减少代码实现的工作量
  • D.因为幂等可以提升操作执行速度

答案:B。分布式环境下,网络超时触发重试、编排器崩溃后恢复、消息重复投递,都可能导致同一个补偿操作被多次执行。若补偿不幂等,就会产生重复退款、重复扣违约金等事故。幂等保证重复执行和单次执行结果一致。

Q6. 串联模式下第k个步骤失败,补偿操作的执行顺序是什么?

单选题 · mid

  • A.从第k个开始向后逐个补偿
  • B.从第k-1个开始逆序往前补偿← 正确答案
  • C.从第1个开始顺序重新执行
  • D.从第n个开始逆序往前来补偿

答案:B。第k步失败且未提交,其本地事务已自行回滚,无需补偿。需要补偿的是第1到第k-1个已提交的步骤,且要按逆序(先撤销最后成功的)。从第n个开始不对,因为第k步之后的步骤根本还没执行。

Q7. TCC与Saga在补偿设计上的关键差异是什么?

单选题 · hard

  • A.TCC在Try阶段预留资源而Saga不预占← 正确答案
  • B.Saga的每个步骤必须是数据库本地事务
  • C.TCC方案中不需要记录状态信息
  • D.Saga不支持正向操作与补偿操作配对

答案:A。TCC由Try/Confirm/Cancel三阶段构成,Try阶段会预占资源(如冻结库存),Cancel阶段释放;Saga则直接正向执行并提交,失败后再补偿,不在执行前预留资源。Saga的步骤不强制要求是数据库事务,TCC的状态也必须记录,因此B、C、D均错。

Q8. 以下哪些属于Saga补偿设计的关键原则?

多选题 · mid

  • A.每个正向操作必须配备对应补偿操作← 正确答案
  • B.补偿操作需要进行幂等设计← 正确答案
  • C.所有事务必须保证强一致性
  • D.步骤执行状态需要持久化记录← 正确答案

答案:ABD。补偿设计的原则包括:可逆性(每步配补偿)、幂等性(重复执行结果一致)、状态持久化(崩溃可恢复)。Saga追求最终一致而非强一致,C选项恰与Saga的特性相反。

Q9. 关于Saga的异常处理策略,以下说法正确的是?

多选题 · hard

  • A.补偿操作失败后应自动重试或转人工← 正确答案
  • B.步骤超时后必须一直等待直到成功← 正确答案
  • C.正向步骤失败且未提交时无需补偿该步骤← 正确答案
  • D.所有异常情况都只能通过人工处理
  • E.2PC会阻塞资源且存在协调者单点风险
  • F.TCC需要业务方实现Try/Confirm/Cancel三方法
  • G.Saga的补偿操作比TCC的Cancel更宽松灵活
  • H.三者都要求锁定资源直到事务结束

答案:ABC。2PC强一致但会阻塞参与方,协调者若故障则全局卡死,A正确;TCC强制要求业务实现三个方法,B正确;Saga的补偿只需尽力抵消业务影响,不像TCC的Cancel要求精确释放预留资源,C正确;Saga全程不锁定资源,D错误。