首页 > 代码库 > 云计算设计模式翻译(三):Compensating Transaction Pattern(事务修正模式)

云计算设计模式翻译(三):Compensating Transaction Pattern(事务修正模式)

先说明一下:这个模式的中文我一直找不到一个比较恰当的中文来表述,姑且在本文中称之为事务修正模式吧,如果各位觉得有更合适的称呼欢迎提出。

    这个模式指的是对于一个由一系列步骤组成、并遵循最终一致性的操作来说,如果一个或多个中间步骤发生错误,那么就必须要对这次操作的步骤进行撤销。对于一个实现了复杂业务逻辑和工作流的云端应用来说,遵循最终一致性的操作随处可见,所以本模式应用场景还是比较多得。

Context and Problem

    运行在云端的应用程序通常会频繁地修改数据,而这些数据通常会在分布在不同物理节点上的数据源上传播。在一个分布式系统中,为了避免资源竞争并提高系统性能,应用程序一般来说不应该保持强事务一致性,而应该实现最终一致性。在最终一致性模型下,一个典型的业务由一系列独立的步骤组成。虽然在这些步骤执行过程中可能存在不一致,但业务逻辑执行完成、所有步骤运行完毕后,系统会再次恢复一致性。

    对于最终一致性模型来说,一个难点是当业务执行过程中如果发生了不可恢复的错误后应该如何处理。在这种情况下,也许应该对业务的整个流程进行重做(包括那些在出错步骤之前已经成功完成的步骤),但是虽然逻辑步骤可以进行重做,期间所操作的数据却不能简单地进行回滚,这是因为其他一些并行执行的应用可能已经对这部分数据进行了修改。即使在这个过程中可以确保数据不会其他应用修改,重做整个逻辑也不只是重设一下状态那么简单,在此过程中还必须考虑到不同的业务规则和特性。

    如果是在多个异构的数据源之上实现了一个最终一致性操作,那么对这个操作中的步骤进行撤销必须轮流访问所有不同的数据源。在所有数据源上的操作必须并成功撤销以保证系统能成功回归到一致性的状态。

    一个实现了最终一致性的操作中不是所有的步骤对数据产生的影响都会被反映到数据库里。在一个SOA环境中(面向服务架构),一个操作可能会调用服务中的某个action,而这个调用会引起服务状态的变更(这点我翻译过程中有点觉得不恰当,不是说一个标准的SOA服务应该是无状态的么),在这种情况下如果对操作要进行撤销则必须要将该服务的状态也置回去,即在撤销的过程中也需要调用一下这个服务的某个action,这可能又会反过来影响到第一次调用的action。

Solution

    那么这个解决方案就是对上面说的情形实现事务修正。在一次事务修正过程中的步骤必须消除之前操作所带来的影响。做一次事务修正并不是简单地将系统状态置成错误操作发生前的状态就行了,应当能在修正过程中考虑到对其他与之并行的应用的操作结果,否则修正动作可能会覆盖掉其他并行操作对系统的改变。这个过程通常需要结合应用特性,由原始操作的特点来定制。

    基于工作流来实现一个需要包含修正流程的最终一致性操作是比较通用的做法。当操作正常执行时,系统会记录每个步骤的执行信息以及对应的修正方法。当任意一个步骤发生错误时,工作流就会倒回,反过来一步一步执行之前已经成功步骤所对应的撤销方法。注意,修正过程也没有必要严格地按照正常操作执行流程镜像地进行回退,有些情况下甚至多个修正步骤能够并发地执行。

    一个事务修正流程本身也是一个遵循最终一致性模型的操作,也存在中间过程发生失败的可能。在这种情况下系统应该能够进行恢复并继续运行。当事务修正流程出现失败的情景时进行重试是非常有必要的,这就意味着事务修正流程中的步骤都具有幂等性。

    另外,对于某一些情况来说,可能只能通过人工干预的方法来进行恢复。所以这种情景下系统应当能够报警,被为系统管理员尽可能多地提供失败信息。

Issues AND Considerations

在考虑如何实现这个模式时需要注意一下几点:

1.一次操作中的步骤有些可能是快速失败的,但有些可能是阻塞的,所以对操作中的步骤来说很有必要实现一种超时机制。

2.修正逻辑是很难进行泛化的(通用化),是与应用本身紧密依赖的,在实现过程中需要应用本身的各个特点和信息来对每个操作步骤实现撤销逻辑。

3.在一个错误修正流程中每个步骤都必须是幂等的,这是为了保证当错误修正流程本身发生异常时能够进行重试。

4.事务修正过程中的步骤没有必要以一种与原有操作步骤镜像的方式排列,。

5.在一次操作中,在所需要用到的资源上加一个短周期的时间锁,在执行操作之前先预先获取这些资源,这将有助于提高操作的成功概率。(在这种情形下)每次操作只在完全获取到所有需要的资源后才开始执行,并在时间锁到期之前释放资源。

6.使用重试机制比使用事务修正机制更加具有宽容性。如果一个遵循最终一致性的操作中的步骤失败了,首先请把这个失败当做是一个暂时性的异常并进行重试,只有当连续多次重试都失败或者失败不可恢复时才开始启动事务修正流程。



云计算设计模式翻译(三):Compensating Transaction Pattern(事务修正模式)