Azure设计模式之补偿事务模式

补偿事务模式


如果一个或多个步骤失败,则需要撤消这个步骤相关的一系列步骤,它们一起定义了事务的最终一致性。通常包含复杂业务流程和工作流的云应用都遵循最终一致性。


问题背景
在云环境的应用程序经常需要修改数据。这些数据可能会分布在不同地理位置的数据源中。为了避免分布式环境中的资源争用以提高性能,应用程序不应提供事务的强一致性。相反,应用程序应该实现最终一致性。在这个模型中,业务操作由一系列单独的步骤组成。在执行这些步骤时,系统状态的总体视图可能不一致,但当操作完成且所有步骤都已执行时,系统状态保持一致。


在数据一致性入门(https://msdn.microsoft.com/library/dn589800.aspx)中阐述了为什么分布式事务不易扩展, 以及最终一致性模型的实现原则。


最终一致性模型中的一个挑战是如何处理失败的步骤。在这种情况下,可能需要撤消此操作之前的所有步骤。但是,数据回滚不是那么容易的,因为应用程序的其他并发实例可能已对其进行了更改。即使在数据尚未被并发实例更改的情况下,撤消步骤也可能不仅仅是恢复原始状态的问题。可能需要应用一些业务规则 (参见旅游网站示例)。


如果实现了最终一致性的操作跨越了多个异构数据存储区,则撤消该操作中的步骤将需要依次访问每个数据存储区。在每个数据存储中执行的工作必须可靠地撤消,以防止系统状态不一致。


并非所有受实现最终一致性操作影响的数据都在数据库中。在面向服务的体系结构(SOA)环境中,可能由于对服务的调用,导致了该服务的状态发生了更改。要撤消该操作,还必须撤消对此状态的更改。这可能需要再次调用服务,以撤销上一次调用对系统状态带来的影响。


解决方案
实现补偿事务。补偿事务中的步骤用于撤消原始操作中的步骤的效果。补偿事务可能无法简单地将系统当前状态替换为在操作开始前系统所处的状态,因为该方法可能会覆盖应用程序中其他并发实例所做的状态更改。相反,它必须是一个智能的过程,它需要考虑到并发实例所做的任何工作。此过程通常是特定于应用程序中的业务,由原始操作所执行的业务而定。


一种常见的方法是使用工作流来实现需要补偿的最终一致操作。当原始操作进行时,系统记录有关每个步骤的信息,以及该步骤执行的工作该如何被撤消。如果操作在某步骤失败,则工作流执行反转每个步骤的工作。注意,补偿事务可能不必以原始操作的相反顺序撤消工作, 也可能并行执行某些撤消步骤。


这种方法类似于在Clemens Vasters 的博客中讨论的策略.(http://vasters.com/clemensv/2012/09/01/Sagas.aspx)


补偿事务也是最终的一致操作,它也可能失败。系统应能够在故障点恢复并继续执行补偿事务。可能需要对失败的步骤重复执行,因此补偿事务中的步骤必须是幂等的。有关详细信息,请参阅乔纳森.奥利弗的博客上的幂等模式。


在某些情况下,可能无法从已失败的步骤中恢复,除非通过人工干预。在这些情况下,系统应提高警报, 并尽可能多地提供有关失败原因的信息。


问题和注意事项
在考虑实现此模式时,请考虑以下几点:
在实现了最终一致性的操作中的步骤,确定何时失败可能并不容易。步骤可能不会立即失败,并可能会阻塞。可能需要超时机制。


补偿逻辑不易泛化。补偿事务是特定于应用程序中业务的。它依赖于应用程序的信息, 才能够在失败的操作中撤消每个步骤。


应将补偿事务中的步骤定义为幂等命令。这样,如果补偿事务失败,就可以重复执行该步骤。


处理原操作中步骤的基础架构以及补偿事务必须是具有弹性的。它不能缺失补偿失败步骤所需的信息,并能够可靠地监视补偿逻辑的进度。补偿事务未必需要将系统中的数据返回到原操作开始时的状态。相反,它对操作失败前成功完成的步骤所做的工作进行补偿。


补偿事务中的步骤顺序不一定与原操作中的步骤正好相反。例如,数据存储可能对不一致的情况很敏感,因此,应首先撤消对数据存储的更改进行补偿。将短期超时锁放在用于完成操作所需的每个资源上,并提前获取这些资源,可以帮助提高补偿事务成功的可能性。只有在获得所有资源之后,才应执行补偿操作。所有操作必须在锁过期之前完成。


考虑使用比通常更宽容的重试逻辑以最小化对补偿事务的触发。如果实现了最终一致性的操作中步骤失败,可尝试将失败作为瞬态异常处理并重复该步骤。只有当失败操作可重现或不可恢复时,才停止执行并启动补偿事务。


实施补偿事务的许多挑战与实现最终一致性相同。可以参照一致性入门中实现最终一致性一文(https://msdn.microsoft.com/library/dn589800.aspx) 了解更多信息。


何时使用这个模式
仅对必须在失败时撤消的操作使用此模式。如果可能,设计解决方案时要考虑到并尽量避免补偿模式所带来的复杂度。


例如
客户在某旅游网站预订行程。一个行程可能包括一系列的航班和酒店。从西雅图到伦敦,然后再到巴黎的客户可以在创建行程时执行以下步骤:
预订从西雅图到伦敦的 F1 航班的座位。
预订从伦敦到巴黎的 F2 航班的座位。
预订从巴黎飞往西雅图的 F3 航班的座位。
在伦敦 H1 酒店预订房间。
预订在巴黎的 H2 酒店的客房。


这些步骤合起来构成了最终一致性操作,尽管每个步骤是单独的操作。因此,除了执行这些步骤,系统还必须记录撤消每个步骤所需的操作,以便客户决定取消行程时调用。执行撤销操作所需的步骤可以看作是补偿事务。


注意,补偿事务中的步骤顺序不一定要与原始步骤一一对应,并且补偿事务中的每个步骤中的逻辑都必须考虑到特定的业务规则。例如,取消预订飞机上的座位可能不会保证客户被全额退款。下图演示了如何使用补偿事务对长时间运行的旅行行程预订事务进行撤销的过程。



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


在许多业务解决方案中,单步失败并不总是需要使用补偿事务对系统状态进行回滚。例如,如果在旅行网站上预订了F1、F2和F3的航班,客户无法在H1酒店预订房间,最好在同一城市的不同酒店为客户提供一个房间,而不是取消航班。如果客户仍可决定取消(在这种情况下,补偿操作将被执行以撤消在F1、F2和F3航班上进行的预订),但此决定权是在客户手里。


相关的模式和建议
在实现此模式时, 以下模式也可能是相关的:
数据一致性入门 (https://msdn.microsoft.com/library/dn589800.aspx)。补偿事务模式通常用于撤消实现了最终一致性的操作。此文作为入门阐释了使用最终一致性的好处和弊端。


计划-代理-主管模式 (https://docs.microsoft.com/en-us/azure/architecture/patterns/scheduler-agent-supervisor)。描述了如何使分布式环境的业务操作变得有弹性。有时,需要通过使用补偿事务来对执行了的工作进行撤销。


重试模式 (https://docs.microsoft.com/en-us/azure/architecture/patterns/retry)。补偿事务的执行成本可能很高,而重试模式是通过实施一种有效的重试失败操作的策略, 以最大程度的降低补偿事务触发的几率。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值