云设计模式之 : 补偿事务模式

1. 缘由

云上运行的应用可能需要频繁修改数据,这些数据可能分布在不同的服务器甚至不同的地域。为了减少资源竞争、提升性能和可用性,应用往往不需要强一致性,而是实现最终一致性。一个业务请求可能分成几步来完成,在这些步骤执行过程中,系统的状态可能不一致,但当属于同一个事务的这些步骤都完成后,系统的状态又变得一致了。

那么在这样的系统中,面临的挑战就是,当事务中的某些或者全部步骤执行失败后,如果回滚?这可能不是简单的将这些步骤修改前的数据还原,因为在这些步骤执行过程中,很可能有其它并发的程序去修改了数据,这样的话如果只是简单将系统还原到该事务之前的状态,就会破坏其它事务对数据的修改。因此,如何回滚,变得非常棘手。

2. 解决方案

补偿事务模式就是为了解决这个问题而提出的,它不仅仅简单地对每一个失败的步骤进行反操作,而是要从整体上考虑,要考虑其它并发应用对数据的修改。因此,补偿事务步骤的正确设计就变得非常重要。一般的做法是使用工作流引擎,每个步骤在执行时都会有记录,并且有对应的回滚工作流以便在事务失败的时候进行状态恢复。

然而也要考虑到补偿事务中的步骤,其本身也可能会执行失败,一般来说这些步骤在失败后应该可以进行重试,因此也就要求在进行补偿事务设计时,补偿事务的每个步骤都是幂等的,简单来说就是多次操作和一次操作的效果一样,支持重试。

3. 需要考虑的问题

有时候不太容易判断最终一致性系统的某个步骤是否失败,因为这些步骤可能不会马上失效,可能被阻塞而已,所以一般最好伴有超时机制。补偿事务的步骤也是根据应用程序的不同而不同,必须有足够的信息才能设计好这些步骤,并且注意这些步骤失败后如何继续恢复系统的问题。如果可以,最好将系统设计成尽可能不需要补偿事务。

4. 具体示例

以一个旅行网站为例,这个网站允许用户预定行程,每个行程包含一系列的步骤,比如:

1) 在飞机F1上预定一个座位,从Seattle到London。

2) 在飞机F2上预定一个座位,从London到Paris。

3) 在飞机F3上预定一个座位,从Paris到Seattle。

4) 在Landon的H1旅馆预定一个房间。

5) 在Paris的H2旅馆预定一个房间。

这五个步骤虽然每一个都是分开的,但是它们要达到最终一致性。对于这样的步骤,补偿事务并不是简单的对每一步进行反操作,下面这张图反映了对预定行程这个长事务的Undo流程,也就是如何产生补偿事务步骤的。

对于图中的每一个步骤,都会有一个事务补偿逻辑。不过在实际中,我们可能并不希望经常执行补偿事务逻辑,而是选择其它的办法。比如说在旅馆H1预定不到房间,那我们可以预定旅馆H3的房间,而不是去执行补偿事务逻辑。我们一般给用户提供多种选择,但具体是否需要取消预定,也就是是否需要执行补偿事务逻辑,还是由用户自己决定。

微信扫码,进入【技术人成长】社群逛逛。