你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
当一个或多个步骤在最终一致的操作中失败时,使用此模式撤消工作。 实现复杂业务流程和工作流的云托管应用程序通常使用遵循最终一致性模型的操作。
上下文和问题
云应用程序经常修改分布在不同地理位置的各种数据源中的数据。 为了避免争用并提高分布式环境中的性能,应用程序应实现最终一致性,而不是强事务一致性。 在最终一致性模型中,典型的业务操作包含一系列单独的步骤。 在这些步骤中,系统状态的总体视图可能不一致。 但是,在完成所有步骤时,系统应再次保持一致。
处理步骤失败在最终一致性模型中提出了一个关键挑战。 失败后,可能需要从已完成的操作步骤中撤消工作。 但是,无法始终回滚数据,因为其他并发应用程序实例可能会更改数据。 即使并发实例不更改数据,撤消步骤比还原原始状态要复杂得多。 可能需要应用特定于业务的规则。 有关示例,请参阅 旅行网站示例。
实现最终一致性的操作跨越多个数据存储时,必须访问每个数据存储来撤消更改。 若要防止系统保持不一致,必须在每个数据存储中可靠地撤消工作。
实现最终一致性的操作并不总是将其受影响的数据存储在数据库中。 例如,在面向服务的体系结构(SOA)环境中,操作可以调用服务中的操作并更改服务保留的状态。 若要撤消操作,还必须撤消此状态更改,这可以涉及再次调用服务来扭转第一个操作的效果。
解决方案
实现补偿事务,以撤消原始操作中已完成步骤的影响。 你可能认为,你可以简单地将系统还原到其原始状态,但此方法可以覆盖来自其他并发应用程序实例的更改。 相反,补偿事务必须灵活地考虑并发工作。 此过程通常特定于应用程序,具体取决于原始操作。
可以使用工作流来实现一个需要补偿的最终一致性操作。 当原始操作运行时,系统会记录有关每个步骤的信息以及如何撤消该操作。 如果操作失败,工作流会回溯已完成的步骤,并对每个步骤进行逆转。
虽然每个步骤都是一个单独的操作,但它们共同构成了最终一致的操作。 系统必须为每个步骤执行步骤和相应的撤消操作。 如果客户取消,这些撤消操作可以作为补偿性事务运行。
单步失败并不总是要求使用补偿事务回滚整个系统。 例如,在旅行网站方案中,客户预订 F1、F2 和 F3 航班,但未能在 H1 酒店预订房间。 给客户提供其他酒店的房间比取消航班更好。 客户仍可以选择取消,这会触发补偿交易以撤消航班预订。 但是,客户应做出此决定,而不是系统。 当决策具有很高的影响或难以可靠地自动执行时,请在决策过程中包括人员。
请考虑以下要点:
补偿性事务可能不需要严格按照原操作的相反顺序来撤销工作。
你可能能够并行执行一些撤消步骤。
可能需要应用特定于业务的规则。 例如,如果取消航班预订,客户可能无法获得全额退款。
此方法类似于 Saga 分布式事务模式。
补偿事务最终是一致的操作,可能会失败。 系统应记录进度,以便它可以从故障点恢复补偿事务。 重试时,步骤可能会多次运行,因此将每个步骤设计为 幂等命令。
有时,手动干预是从失败的步骤中恢复的唯一方法。 在这些情况下,系统应引发一个警报,其中包含有关失败原因的详细信息。
问题和注意事项
在决定如何实现此模式时,请考虑以下几点:
确定实现最终一致性的操作中的步骤何时失败并非易事。 步骤可能不会立即失败,而是被阻止。 可能需要实现超时机制。
通用化补偿逻辑并非易事。 补偿事务特定于应用程序。 它依赖于应用程序有足够的信息来撤消失败操作中每个步骤的影响。
补偿事务并不总是起作用。 将补偿事务中的步骤定义为幂等命令,以便在补偿事务本身失败时重复这些步骤。
处理这些步骤的基础结构必须满足以下条件:
它在原始操作和补偿事务中都具有很强的复原能力。
它不会丢失补偿失败步骤所需的信息。
它可靠地监视补偿逻辑进度。 补偿事务在原始操作提交后运行,其他事务可能会更改中间状态。 因此,请确保可以关联和审核原始操作及其补偿端到端。
补偿事务不一定会将系统数据返回到原始操作开始时的状态。 相反,事务会补偿操作在失败之前成功完成的工作。
补偿事务步骤不一定总是按完全相反的顺序逆转原始操作。 例如,如果一个数据存储比另外一个数据存储更容易受到不一致性的影响,请首先撤消对该存储的更改。
某些度量值可帮助你提高成功率。 可以对每个完成操作所需的资源设置一个带有超时功能的短期锁。 可以提前获取这些资源,然后仅在获取所有资源后才能执行工作。 在锁过期之前完成所有操作。
将更多错误视为暂时性的重试逻辑有助于最大程度地减少触发补偿事务的故障。 当实现最终一致性的操作中的步骤失败时,请将其作为暂时性异常进行处理,然后重试该步骤。 仅当步骤重复失败或无法恢复时,才停止操作并触发补偿。 有关重试策略的详细信息,请参阅 暂时性故障处理。
实现补偿事务时,会遇到许多类似于实现最终一致性的挑战。 有关详细信息,请参阅 最小化协调。
定义 无返回 和不可逆步骤的明确点。 在复杂的工作流中,无法安全或有意义的撤消某些操作,例如外部副作用或法律绑定操作。 确定可补偿与不可逆的步骤。 设计工作流,以便仅在所有关键验证成功后才会执行不可逆的步骤。
何时使用此模式
在以下情况下使用此模式:
业务操作跨越多个步骤、服务或数据存储,如果后续步骤失败,则必须撤消该操作。 此方案通常发生在长时间运行的工作流中,这些工作流遵循最终一致性模型,并且不能依赖于原子事务。
故障恢复通常需要特定于域的逻辑,而不是简单的数据回滚。 撤消工作时使用补偿操作,要求应用业务规则,例如取消预留或发放部分退款。
在以下情况下,此模式可能不适用:
可以安全地重试操作,大多数故障都是暂时性的。 在这些情况下,重试逻辑本身通常就足够,补偿事务只会添加不必要的复杂性。
系统不能容忍临时不一致,或者补偿无法可靠地还原有效状态。 请改用所有步骤中的强一致性机制或原子事务。
工作负载设计
评估如何在工作负载设计中使用补偿性事务来解决Azure Well-Architected Framework支柱中涵盖的目标和原则。 下表提供有关此模式如何支持每个支柱目标的指南。
| 支柱 | 此模式如何支持支柱目标 |
|---|---|
| 可靠性 设计决策有助于工作负荷在发生故障后 复原 ,并确保它在发生故障后 恢复到 正常运行状态。 | 补偿操作通过使用直接回滚数据更改、解除事务锁定,甚至运行系统的原生行为以逆转影响,来应对关键工作负荷路径中的故障。 - RE:02 关键流程 - RE:09 灾难恢复 |
如果此模式在某个支柱中引入权衡取舍,请将它们与其他支柱的目标进行对比。
示例
下图显示了补偿事务模式的实际Azure实现。 其他实现也可能适用于您的工作负荷要求。 在Azure Container Apps中运行的业务流程协调程序通过Azure Service Bus发送命令来协调长时间运行的工作流的每个步骤。 随着每个向前步骤的成功,业务流程协调程序在Azure Cosmos DB中记录执行状态和相应的补偿操作,以便可以恢复、关联和审核工作流。
此模型首先使用重试机制以保证持续推进。 如果步骤失败,业务流程协调程序会针对暂时性故障应用重试逻辑,并尝试继续执行原始操作。 只有当前进变得不可能时(例如重试已用尽或故障被归类为非暂时性时),才会调用补偿。
特定业务规则还可以优先考虑推进而非立即补偿。 如果步骤失败,业务流程协调程序可以选择替代路径,例如替换等效服务或回退选项,而不是回滚工作流。 对于高影响或模棱两可的情况,可以在决定是否继续执行替代路径或触发补偿之前暂停工作流进行人工评审。 此方法将补偿视为最后手段,并允许域规则驱动恢复决策。
在典型的序列中,业务流程协调程序通过Service Bus(步骤 1 和步骤 2)发送步骤消息,接收成功的结果,并将转发和补偿元数据存储在Azure Cosmos DB中。
可以通过两种方式触发补偿:
当同一任务中的后续步骤失败时,您必须撤回之前已成功的步骤。 这种补偿可能会在以下情况下立即进行:当某个步骤返回业务错误(例如,规则验证失败)时,或者在技术重试已耗尽且消息被移动到死信队列之后。
当后续客户端显式请求取消已完成的操作时。
在任一情况下,业务流程协调程序都读取存储的补偿记录,并将补偿命令发送到相应的服务。 如果补偿步骤暂时失败,Service Bus重试可以在不升级事件的情况下完成。
如果重复重试仍然失败,Service Bus将消息移动到死信队列并保留失败详细信息。 业务流程协调程序(或专用死信处理器)引发警报,并发出结构化的遥测数据(包括故障原因和关联 ID),将其发送到 Azure Monitor 和 Log Analytics,这些数据可以在 Application Insights 中展示。 此操作路径可帮助团队诊断故障、确定手动干预的需求,并在整个原始流和补偿流中保持可追溯性。
在条件明确且风险较低的情况下,工作流可以自动启动补偿;而当情况不明确、影响很大或需要手动决策时,则会暂停以供人工审核。
在组件之间使用托管标识和基于Microsoft Entra ID的授权,以避免共享机密并强制实施最低特权访问。 创建简化的引用关系图时,将这些标识和授权控制视为基线实现问题,而不是显式流步骤。 使图表侧重于编排、重试、补偿和故障处理。
相关资源
微服务的数据注意事项:了解分布式系统中固有的最终一致性和部分故障的原因。 补偿事务模式提供了一种具体机制,用于在操作跨越多个服务时处理这些故障。
Azure Cosmos DB 中的事务性出站模式:当需要补偿事务以可靠地发布事件或命令时,使用此模式。 它有助于确保状态更改和消息以原子方式记录,从而防止消息丢失。
自我修复设计:使用补偿事务作为应用程序的自我修复方法的一部分。
计划程序代理监督器模式:使用此模式实现可复原的系统,这些系统跨分布式服务和资源执行业务操作。 这些系统有时需要补偿事务才能撤销操作。
重试模式:使用此模式处理暂时性故障,并最大程度地减少补偿事务的需求。
Saga 分布式事务模式:使用此模式管理分布式事务中微服务之间的数据一致性。 Saga 使用补偿事务进行故障恢复。
管道和筛选器模式:将复杂任务分解为可重用步骤时,将此模式与补偿事务模式结合使用作为分布式事务的替代方法。