微服务架构中分布式事务实现方案怎样何取舍

提起微服务架构,不可避免的两个话题就是服务治理和分布式事务。数据库和业务模块的垂直拆分为咱们带来了系统性能、稳定性和开发效率的提高的同时也引入了一些更复杂的问题,例如在数据一致性问题上,咱们再也不可以依赖数据库的本地事务,对于一系列的跨库写入操做,如何保证其原子性,是微服务架构下不得不面对的问题。算法

1 分布式事务解决方案数据库

针对分布式系统的特色,基于不一样的一致性需求产生了不一样的分布式事务解决方案,追求强一致的两阶段提交、追求最终一致性的柔性事务和事务消息等等。各类方案没有绝对的好坏,抛开具体场景咱们没法评价,更没法能作出合理选择。在选择分布式事务方案时,须要咱们充分了解各类解决方案的原理和设计初衷,再结合实际的业务场景,从而作出科学合理的选择。架构

2 强一致解决方案并发

2.1 两阶段提交分布式

两阶段提交算法中有两种角色:事务协调者和事务参与者,一个事务通常会涉及多个事务参与者,具体的两阶段过程以下图所示:ide

第一阶段:写库操做完成后协调者向全部参与者发送Prepare消息,询问各参与者的本地事务是否能够提交,参与者根据自身状况向协调者返回能够或不能够;微服务

第二阶段:协调者收到全部参与者的反馈后,若是所有返回的是能够提交则向全部参与者发送提交事务命令。只要有一个参与者返回的是不能提交,则向全部参与者发送回滚命令。以下图所示:高并发

微服务架构中分布式事务实现方案怎样何取舍

图1 两阶段提交性能

在上述的两阶段模型中,事务提交过程当中有可能出现协调者或个别参与者宕机的状况,但多数状况下参与事务的节点能够经过询问其余节点得知事务状态,作出正确的操做。但在极端状况下事务有可能处于未知状态。咱们分析下下面这个场景:当协调者发送提交指令后宕机,而惟一收到提交指令的参与者完成提交后也宕机了,此时没有节点知道事务应该提交仍是回滚,事务处于未知状态,因此在这种极端状况下可能形成数据的不一致。针对两阶段的缺陷,又提出了三阶段提交协议。设计

2.2 三阶段提交

三阶段提交是将第二阶段拆分红预提交和确认提交两个阶段。这样在事务提交过程当中,不管哪一个节点宕机,只要有一个存活节点处于预提交或是提交状态咱们均可以肯定事务是能够提交的(第一阶段已经确认事务能够提交),反之若是没有处于这两种状态的节点,则回滚事务。

微服务架构中分布式事务实现方案怎样何取舍

图2 三阶段提交

从上面的分析能够看到,不管是两阶段仍是三阶段最后的“提交”都是一个耗时极短的操做,即便在分布式系统中失败的几率也是很是小的,因此咱们能够认为两阶段提交基本可以保证分布式事务原子性。

3 落地方案

上面介绍的只是理论基础,XA规范就是基于两阶段提交的理论模型提出的分布式事务规范,规范中的资源管理器至关于事务参与者;事务管理器至关于事务协调者,目前不少主流的关系数据库都实现了XA接口。

落地到实际应用中咱们会发现两阶段提交存在的一些问题:

  1. 数据库产品要保证数据完成性,写入须要加锁,因此在整个分布式事务协调过程当中可能形成数据库资源锁定时间过长,不适合并发高以及子事务生命周期较长的业务场景;

  2. XA规范要求事务管理器本地记录事务执行状态,因此事务管理器做为有状态服务不支持事务异地恢复;

XA可以最大程度保证数据的一致性,但在高并发场景下性能衰减很是严重,因此在数据一致性需求上若是不是“强一致”,不建议使用。

3.1 最终一致性解决方案

在咱们大多数的业务场景中,追求的都是数据的最终一致性,业界也提出了不少柔性事务的解决方案,能够很大程度上保证数据的一致性,咱们能够根据实际场景来权衡使用。具体的解决方案有不少,总结其设计思路能够分为下面3种模型:

3.1.1 TCC(Try-Confirm-Cancel)

TCC将事务分为Try,Confirm,Cancel三个阶段。

  1. Try阶段:尝试执行业务,预留资源;

  2. Confirm阶段:确认执行业务,使用Try阶段资源;

  3. Cancel阶段:取消执行业务,释放Try阶段预留的资源;

咱们用一个转帐汇款的业务场景,说明下TCC的具体过程。例如:张三给李四转帐100元,一次转帐业务由两个本地事务组成:一、张三帐户扣减100元;二、李四帐户增长100元。

事务成功处理流程如图3:

微服务架构中分布式事务实现方案怎样何取舍
图3 Try-Confirm事务成功处理流程

事务失败处理流程如图4:

微服务架构中分布式事务实现方案怎样何取舍
图4 Try-Cancel事务成功处理流程

Try阶段:

一、检查张三帐户,知足要求帐户扣减100元,记录扣减事件(预留资源);

二、检查李四帐户有效性;

Confirm:

若是Try成功,李四帐户增长100元,事务完成;

Cancel:

若是Try失败,张三帐户增长100元,删除扣减事件记录(释放预留资源),事务取消。

从性能角度分析,TCC过程没有对资源加锁,对系统并发性能几乎没有影响,只是会有些额外辅助操做。须要注意,在这个模型中要保证数据一致性有两个技术难点须要解决:

  1. 须要有相似事务管理器的角色保证TCC过程的完整性;

  2. Confirm和Cancel方法须要保证幂等(因为不可避免的重试操做必需要保证幂等);

TCC对业务侵入很是大,对RD同窗十分不友好,业务改形成本至关高。

3.1.2 SAGA模型

SAGA模型把一个分布式事务拆分为多个本地事务,每一个本地事务都有相应的执行模块和补偿模块,当事务中任意一个本地事务出错时,能够经过调用对应的补偿方法恢复以前的事务,从而达到数据的最终的一致性。SAGA的事务管理器负责在事务失败时执行补偿逻辑,能够经过调用执行模块的逆向操做(例如执行子事务时同时生成逆向SQL)或调用业务开发人员提供的补偿方法(须要保证补偿的幂等性)来实现。

能够看到,SAGA虽然对业务形成必定的侵入,但当相对TCC已经有好不少了,并且,事务管理器理论上能够作到向后补偿(撤销全部已完成操做,恢复到事务开始状态)或向前补偿(继续完成未完成事务,使业务请求获得成功处理,更符合业务预期)。

3.1.3 MQ事务消息

MQ事务消息对分布式事务模型进行了简化,重点再也不是保证全部子事务的原子性,而是保证本地事务和发送MQ消息的原子性,咱们能够利用这一特色,将分布式事务转化成本地事务和若干发送MQ消息的操做,而后要求消费方确保消费成功。利用MQ事务消息,在系统中去掉了TCC和SAGA方案中的事务管理器角色,简化了分布式事务模型,同时这也是对业务侵入最低最友好的方案(不用提供补偿接口)。

固然这里也有两个基本前提:

  1. MQ系统保证消息能不丢失;

  2. 消费方确保消费幂等(保证不丢失,就很难避免重复消费)。

须要注意的是,MQ事务消息简化了事务模型、下降了业务侵入,因此对数据一致性的保证保障也就相对比较低了。

  1. 总结

柔性事务解决方案中,虽然SAGA和TCC看上去能够保证数据的最终一致性,但分布式系统的成产环境复杂多变,某些状况是能够致使柔性事务机制失效的,因此不管使用那种方案,都须要最终的兜底策略,人工校验,修复数据。

咱们综合对比下几种分布式事务解决方案:

一致性保证:XA > TCC = SAGA > 事务消息

业务友好性:XA > 事务消息 > SAGA > TCC

性 能 损 耗:XA > TCC > SAGA = 事务消息

最后,在设计系统时咱们必定要结合业务自身的一致性需求,选择恰当的方案。能够看到对数据一致性保障越高的方案其开发成本、维护难度和系统性能损耗就越大,必定不要一味的追求高大上的方案,对系统过分设计。

更多免费技术资料及视频
微服务架构中分布式事务实现方案怎样何取舍

相关文章
相关标签/搜索