您现在访问的是微软AZURE全睃版技术文档网站,若需覝访问由世纪互蝔违蝥的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

补偿事务模式

撤消一系列步骤执行的工作,当一个或多个步骤失败时,这些步骤会共同定义最终一致的操作。 遵循最终一致性模型的操作常见于实现复杂业务流程和工作流的云托管应用程序中。

上下文和问题

云中运行的应用程序经常修改数据。 该数据可能在不同的地理位置中的多个数据源间传播。 为避免争用和提高分布式环境中的性能,应用程序不应提供事务强一致性。 相反,应用程序应实现最终一致性。 在此模型中,典型的业务操作包含一系列单独的步骤。 虽然在执行这些步骤的期间,系统状态的总体视图可能会不一致,但操作完成且所有的步骤执行后,系统会再次变得一致。

Data Consistency Primer(数据一致性入门)提供了分布式事务缩放性不佳的原因以及有关最终一致性模型原则的信息。

最终一致性模型中的一个难题是如何处理失败步骤。 这种情况下,可能需要撤销此操作中先前步骤已完成的所有工作。 然而,数据不能回滚,因为应用程序的其他并发实例可能已更改了数据。 即使在数据并未被并发实例更改的情况下,撤销步骤也可能不仅仅是还原原始状态。 可能需要应用多种业务特定规则(参阅示例部分中所述的旅行网站)。

如果实现最终一致性的操作跨多个异类数据存储,则撤销操作中的步骤需要依次访问每个数据存储。 必须以可靠方式撤销每个数据存储中执行的工作,以此防止系统保持不一致。

并非所有受实现最终一致性操作影响的数据都可能保留在数据库中。 在面向服务的体系结构 (SOA) 环境中,操作可能会调用服务中的操作,并导致该服务的状态发生更改。 若要撤消该操作,则也必须撤消该状态更改。 这可能涉及到再次调用服务和再执行一个撤销第一次操作效果的操作。

解决方案

解决方案是实现补偿事务。 补偿事务中的步骤必须撤销原始操作中步骤的效果。 补偿事务可能无法仅将当前状态替换为此操作开始时系统所处的状态,因为此方法可能会覆盖由应用程序其他并发实例所作的更改。 相反,必须是一个智能过程,该智能过程会考虑到并发实例执行的所有工作。 该过程通常特定于应用程序,由原始操作执行的工作的性质驱动。

常见方法是使用工作流来实现需要补偿的最终一致操作。 原始操作进行期间,系统会记录每个步骤以及如何可撤销相应步骤执行的操作的相关信息。 如果操作在任何时刻失败,则工作流会回退已完成的步骤,并撤销每个步骤。 请注意,补偿事务可能并非必须按照原始操作的逆序来撤销工作,其可能会并行执行部分撤销步骤。

这种方法类似于 Clemens Vasters 博客中所述的 Sagas 策略。

补偿事务也是最终一致操作,并且也可能会失败。 系统应能够在失败时恢复补偿事务,然后继续。 可能需要重复已失败的步骤,因此补偿事务中的步骤应定义为幂等命令。 有关详细信息,请参阅 Jonathan Oliver 博客中的 Idempotency Patterns(幂等模式)。

某些情况下,除非手动干预,否则可能无法恢复已失败的步骤。 这类情况下,系统应会发出警报,并会提供尽可能多的有关失败原因的信息。

问题和注意事项

在决定如何实现此模式时,请考虑以下几点:

确定实现最终一致性的操作中的步骤何时失败并非易事。 步骤可能不会立即失败,相反,其可能会阻止。 可能需要实现某种形式的超时机制。

—归纳补偿逻辑并不可行。 补偿事务特定于应用程序。 它依赖于具有足够信息的应用程序,从而能够撤消失败的操作中每个步骤的效果。

应将补偿事务中的步骤定义为幂等命令。 这样,补偿事务自身失败时可重复步骤。

处理该原始操作中步骤的基础结构和补偿事务必须具有复原性。 其不得丢失补偿失败步骤所需信息,且必须能够可靠地监视补偿逻辑的进程。

补偿事务不一定会将系统中的数据返回到原始操作开始时其所处的状态。 相反,它补偿操作失败前由已成功完成的步骤所执行的工作。

补偿事务中步骤的顺序不一定与原始操作中步骤的顺序完全相反。 例如,一个数据存储可能比另一个数据存储对不一致性更加敏感,因而补偿事务中撤销对此存储的更改的步骤应该会首先发生。

对完成操作所需的每个资源采用短期的基于超时的锁并预先获取这些资源,这样有助于增加总体活动成功的可能性。 仅在获取所有资源后才应执行工作。 锁过期之前必须完成所有操作。

考虑使用包容性更强的重试逻辑来尽可能避免会触发补偿事务的失败。 如果实现最终一致性操作中的步骤失败,请尝试会失败处理为暂时异常,然后重复相应步骤。 仅在步骤出现反复失败或不可恢复性失败时停止操作并启动补偿事务。

实现补偿事务的许多难题与实现最终一致性中的难题相同。 有关详细信息,请参阅 Data Consistency Primer(数据一致性入门)中的“实现最终一致性注意事项”部分。

何时使用此模式

仅对失败时必须撤销的操作使用此模式。 如果可能,请设计相关解决方案来避免需要补偿事务所带来的麻烦。

示例

旅行网站让客户订购旅行路线。 单个路线可能包含一系列航班和酒店。 一位先从西雅图到伦敦再到巴黎的客户在创建路线时,可执行以下步骤:

  1. 订购从西雅图到伦敦的 F1 航班机票。
  2. 订购从伦敦到巴黎的 F2 航班机票。
  3. 订购从巴黎到西雅图的 F3 航班机票。
  4. 预定伦敦 H1 酒店房间。
  5. 预定巴黎 H2 酒店房间。

虽然每个步骤为单独操作,但这些步骤会构成一个最终一致操作。 因此,除执行这些步骤外,系统也必须记录撤销每个步骤所需的对立操作,以处理客户取消路线的情况。 之后,执行对立操作所需的步骤可作为补偿事务运行。

请注意,补偿事务中的步骤与原始步骤的顺序可能会不正好相反,且补偿事务中每个步骤中的逻辑必须要考虑到特定于业务的规则。 例如,如果取消航班机票订购,客户可能不会享有已支付金额的全额退款。 该图介绍了生成补偿事务来撤销长时间运行的事务,从而来订购旅行路线。

生成补偿事务来撤销长时间运行的事务,从而来订购旅行路线

备注

补偿事务中的步骤可能会并行执行,具体取决于每个步骤的补偿逻辑的设计方式。

在许多业务解决方案中,单个步骤失败并不始终要求通过使用补偿事务回滚系统。 例如,如果—在旅行网站上预订航班 F1、F2 和 F3 后—,客户无法预订 H1 酒店的房间,则首选方案是为客户提供该市另一家酒店的房间,而不是取消航班。 客户仍可决定取消(这种情况下,会运行补偿事务并撤销 F1、F2 和 F3 航班预订),但应由客户而不是系统作出此决定。

实施此模式时,可能也会与以下模式和指南相关:

  • 数据一致性 Primer。 补偿事务模式通常用于撤消实现最终一致性模型的操作。 该入门指导提供了有关最终一致性优点和不足的信息。

  • Scheduler-Agent-Supervisor 模式。 介绍如何实现弹性系统,这些弹性系统执行使用分布式服务和资源的业务操作。 有时,可能需要使用补偿事务来撤销操作执行的工作。

  • 重试模式。 补偿事务执行成本比较高,因此可按照重试模式,通过实现有效的重试失败策略来尽可能少地使用补偿事务。