分布式微服务的事务不一致性(金融产品):2阶段提交协议的劣势

2022-10-01  本文已影响0人  robot_test_boy

一名客户想卖出一些股票,涉及如下操作:用户创建订单、应用验证和预定股票仓位、应用向用户收取手续费以及应用将订单提交到市场上。

从客户的角度看,卖股票的操作看起来是原子性的:交手续费、股票预定和创建订单是同一时间发生的,用户不能卖自己没有的股票,也不能把自己的同一份股票连续买两次。

在许多单体应用中,这种需求很容易满足:可以将数据库操作封装在一个ACID的事务中,然后就高枕无忧了。因为开发者知道,如果中间出错,系统中的非法状态会被回滚回去。

相比之下,在微服务应用中,每个操作都是由不同的服务来执行的,每个服务负责一部分应用状态。数据所有权的去中心化能有助于确保服务的独立性和松耦合,但是这也使得我们不得不在系统层面上提供一套机制来维护整体数据的一致性

比如,order服务负责处理卖股票的流程。它会调用account transaction服务来预定股票,然后再调用fee服务来交费。但是这个收费事务出故障了。

此时,系统处于一种不一致的状态:股票已经预留了,订单也已经创建了,但是公司没有收到客户的手续费。我们不能就这样撒手不管了——所以,order服务需要开始修正,它会指示account transaction服务弥补并取消预留的股票。这可能看起来很简单,但是当牵涉的服务越来越多、事务的执行时间越来越长或者操作还会进一步交叉触发下游新的事务时,一切都变得越来越复杂了。


面对上面的问题,第一个念头可能是要设计一个能够在多个服务间实现事务保证的系统。一种常见的方案是使用二阶段提交(two phase commit,2PC)协议,系统使用一个事务管理器(transaction manager)来将多个资源(resource)的操作分成两个阶段:准备(prepare)和提交(commit)。

遗憾的是这个方案有缺陷的。

首先,2PC意味着事务管理器和资源方之间采用了同步的通信机制。如果某个资源方不可用,事务就不能提交而必须回滚。这反过来会增加重试的次数并且降低整个系统的可用性。如果想要支持异步服务交互,就需要在这些服务之间增加一个消息层,然后和这些服务一起来支持2PC,而这会限制我们的技术选型。

将重要的编配职责交给事务管理器同样违背了微服务的核心原则:服务自治。最糟糕的情况下,我们的服务都只是默默地对数据进行CRUD增删改查操作,系统中最有意义的功能反而完全是由事务管理者来封装完成的。

最后,分布式事务通过给处于事务中的资源添加锁来确保隔离性的。这使得分布式事务不适合于那些耗时较长的操作,因为这会增加竞争和死锁的风险。


总结,看到案例终于明白了,2阶段提交的必要性,之前理论阶段看的一知半解。除了2阶段提交还有更好的方法吗?敬请期待。

摘取自 摩根·布鲁斯和保罗·A.佩雷拉的《微服务实战》

上一篇 下一篇

猜你喜欢

热点阅读