分布式事务 解决方案、原理

事务

1.1 什么是事务mysql

数据库事务(简称:事务,Transaction)是指数据库执行过程当中的一个逻辑单位,由一个有限的数据库操做序列构成。sql

事务拥有如下四个特性,习惯上被称为ACID特性:数据库

  • 原子性(Atomicity):事务做为一个总体被执行,包含在其中的对数据库的操做要么所有被执行,要么都不执行。
  • 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另外一个一致状态。一致状态是指数据库中的数据应知足完整性约束。除此以外,一致性还有另一层语义,就是事务的中间状态不能被观察到(这层语义也有说应该属于原子性)。
  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不该影响其余事务的执行,如同只有这一个操做在被数据库所执行同样。
  • 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。在事务结束时,此操做将不可逆转。

1.2 本地事务编程

起初,事务仅限于对单一数据库资源的访问控制:架构


阿里P8架构师谈:分布式事务的特征、原理、以及常见3种解决方案


架构服务化之后,事务的概念延伸到了服务中。假若将一个单一的服务操做做为一个事务,那么整个服务操做只能涉及一个单一的数据库资源:并发


阿里P8架构师谈:分布式事务的特征、原理、以及常见3种解决方案


这类基于单个服务单一数据库资源访问的事务,被称为本地事务(Local Transaction)。框架

分布式事务

本地事务主要限制在单个会话内,不涉及多个数据库资源。可是在基于SOA(Service-Oriented Architecture,面向服务架构)的分布式应用环境下,愈来愈多的应用要求对多个数据库资源,多个服务的访问都能归入到同一个事务当中,分布式事务应运而生。nosql

最先的分布式事务应用架构很简单,不涉及服务间的访问调用,仅仅是服务内操做涉及到对多个数据库资源的访问。分布式


阿里P8架构师谈:分布式事务的特征、原理、以及常见3种解决方案


当一个服务操做访问不一样的数据库资源,又但愿对它们的访问具备事务特性时,就须要采用分布式事务来协调全部的事务参与者。高并发

对于上面介绍的分布式事务应用架构,尽管一个服务操做会访问多个数据库资源,可是毕竟整个事务仍是控制在单一服务的内部。若是一个服务操做须要调用另一个服务,这时的事务就须要跨越多个服务了。在这种状况下,起始于某个服务的事务在调用另一个服务的时候,须要以某种机制流转到另一个服务,从而使被调用的服务访问的资源也自动加入到该事务当中来。下图反映了这样一个跨越多个服务的分布式事务:


阿里P8架构师谈:分布式事务的特征、原理、以及常见3种解决方案


若是将上面这两种场景(一个服务能够调用多个数据库资源,也能够调用其余服务)结合在一块儿,对此进行延伸,整个分布式事务的参与者将会组成以下图所示的树形拓扑结构。在一个跨服务的分布式事务中,事务的发起者和提交均系同一个,它能够是整个调用的客户端,也能够是客户端最早调用的那个服务。


阿里P8架构师谈:分布式事务的特征、原理、以及常见3种解决方案


较之基于单一数据库资源访问的本地事务,分布式事务的应用架构更为复杂。

在不一样的分布式应用架构下,实现一个分布式事务要考虑的问题并不彻底同样,好比对多资源的协调、事务的跨服务传播等,实现机制也是复杂多变。尽管有这么多工程细节须要考虑,但分布式事务最核心的仍是其 ACID 特性。所以,想要了解一个分布式事务,就先从了解它是怎么实现事务 ACID 特性开始。

下文将从两个最多见的分布式事务模型入手,着重分析分布式事务的基础共通点,即如何保证分布式事务的 ACID 特性。

常见的分布式事务解决方案

1.基于XA协议的两阶段提交

XA是一个分布式事务协议,由Tuxedo提出。XA中大体分为两部分:事务管理器和本地资源管理器。其中本地资源管理器每每由数据库实现,好比Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器做为全局的调度者,负责各个本地资源的提交和回滚。XA实现分布式事务的原理以下:

阿里P8架构师谈:分布式事务的特征、原理、以及常见3种解决方案

总的来讲,XA协议比较简单,并且一旦商业数据库实现了XA协议,使用分布式事务的成本也比较低。可是,XA也有致命的缺点,那就是性能不理想,特别是在交易下单链路,每每并发量很高,XA没法知足高并发场景。XA目前在商业数据库支持的比较理想,在mysql数据库中支持的不太理想,mysql的XA实现,没有记录prepare阶段日志,主备切换回致使主库与备库数据不一致。许多nosql也没有支持XA,这让XA的应用场景变得很是狭隘。

2.消息事务+最终一致性

所谓的消息事务就是基于消息中间件的两阶段提交,本质上是对消息中间件的一种特殊利用,它是将本地事务和发消息放在了一个分布式事务里,保证要么本地操做成功成功而且对外发消息成功,要么二者都失败,开源的RocketMQ就支持这一特性,具体原理以下:

阿里P8架构师谈:分布式事务的特征、原理、以及常见3种解决方案

一、A系统向消息中间件发送一条预备消息

二、消息中间件保存预备消息并返回成功

三、A执行本地事务

四、A发送提交消息给消息中间件

经过以上4步完成了一个消息事务。对于以上的4个步骤,每一个步骤均可能产生错误,下面一一分析:

  • 步骤一出错,则整个事务失败,不会执行A的本地操做
  • 步骤二出错,则整个事务失败,不会执行A的本地操做
  • 步骤三出错,这时候须要回滚预备消息,怎么回滚?答案是A系统实现一个消息中间件的回调接口,消息中间件会去不断执行回调接口,检查A事务执行是否执行成功,若是失败则回滚预备消息
  • 步骤四出错,这时候A的本地事务是成功的,那么消息中间件要回滚A吗?答案是不须要,其实经过回调接口,消息中间件可以检查到A执行成功了,这时候其实不须要A发提交消息了,消息中间件能够本身对消息进行提交,从而完成整个消息事务

基于消息中间件的两阶段提交每每用在高并发场景下,将一个分布式事务拆成一个消息事务(A系统的本地操做+发消息)+B系统的本地操做,其中B系统的操做由消息驱动,只要消息事务成功,那么A操做必定成功,消息也必定发出来了,这时候B会收到消息去执行本地操做,若是本地操做失败,消息会重投,直到B操做成功,这样就变相地实现了A与B的分布式事务。原理以下:

阿里P8架构师谈:分布式事务的特征、原理、以及常见3种解决方案

虽然上面的方案可以完成A和B的操做,可是A和B并非严格一致的,而是最终一致的,咱们在这里牺牲了一致性,换来了性能的大幅度提高。固然,这种玩法也是有风险的,若是B一直执行不成功,那么一致性会被破坏,具体要不要玩,仍是得看业务可以承担多少风险。

3.TCC 模型

TCC(Try-Confirm-Cancel)分布式事务模型相对于 XA 等传统模型,其特征在于它不依赖资源管理器(RM)对分布式事务的支持,而是经过对业务逻辑的分解来实现分布式事务。

TCC 模型认为对于业务系统中一个特定的业务逻辑,其对外提供服务时,必须接受一些不肯定性,即对业务逻辑初步操做的调用仅是一个临时性操做,调用它的主业务服务保留了后续的取消权。若是主业务服务认为全局事务应该回滚,它会要求取消以前的临时性操做,这就对应从业务服务的取消操做。而当主业务服务认为全局事务应该提交时,它会放弃以前临时性操做的取消权,这对应从业务服务的确认操做。每个初步操做,最终都会被确认或取消。

所以,针对一个具体的业务服务,TCC 分布式事务模型须要业务系统提供三段业务逻辑:

初步操做 Try:完成全部业务检查,预留必须的业务资源。

确认操做 Confirm:真正执行的业务逻辑,不做任何业务检查,只使用 Try 阶段预留的业务资源。所以,只要 Try 操做成功,Confirm 必须能成功。另外,Confirm 操做需知足幂等性,保证一笔分布式事务有且只能成功一次。

取消操做 Cancel:释放 Try 阶段预留的业务资源。一样的,Cancel 操做也须要知足幂等性。


阿里P8架构师谈:分布式事务的特征、原理、以及常见3种解决方案


TCC 分布式事务模型包括三部分:

1.主业务服务:主业务服务为整个业务活动的发起方,服务的编排者,负责发起并完成整个业务活动。

2.从业务服务:从业务服务是整个业务活动的参与方,负责提供 TCC 业务操做,实现初步操做(Try)、确认操做(Confirm)、取消操做(Cancel)三个接口,供主业务服务调用。

3.业务活动管理器:业务活动管理器管理控制整个业务活动,包括记录维护 TCC 全局事务的事务状态和每一个从业务服务的子事务状态,并在业务活动提交时调用全部从业务服务的 Confirm 操做,在业务活动取消时调用全部从业务服务的 Cancel 操做。

一个完整的 TCC 分布式事务流程以下:

  1. 主业务服务首先开启本地事务;
  2. 主业务服务向业务活动管理器申请启动分布式事务主业务活动;
  3. 而后针对要调用的从业务服务,主业务活动先向业务活动管理器注册从业务活动,而后调用从业务服务的 Try 接口;
  4. 当全部从业务服务的 Try 接口调用成功,主业务服务提交本地事务;若调用失败,主业务服务回滚本地事务;
  5. 若主业务服务提交本地事务,则 TCC 模型分别调用全部从业务服务的 Confirm 接口;若主业务服务回滚本地事务,则分别调用 Cancel 接口;
  6. 全部从业务服务的 Confirm 或 Cancel 操做完成后,全局事务结束。

TCC模型小结

所谓的TCC编程模式,也是两阶段提交的一个变种。TCC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操做。以在线下单为例,Try阶段会去扣库存,Confirm阶段则是去更新订单状态,若是更新订单失败,则进入Cancel阶段,会去恢复库存。总之,TCC就是经过代码人为实现了两阶段提交,不一样的业务场景所写的代码都不同,复杂度也不同,所以,这种模式并不能很好地被复用。

分布式事务总结

分布式事务,本质上是对多个数据库的事务进行统一控制,按照控制力度能够分为:不控制、部分控制和彻底控制。不控制就是不引入分布式事务,部分控制就是各类变种的两阶段提交,包括上面提到的消息事务+最终一致性、TCC模式,而彻底控制就是彻底实现两阶段提交。部分控制的好处是并发量和性能很好,缺点是数据一致性减弱了,彻底控制则是牺牲了性能,保障了一致性,具体用哪一种方式,最终仍是取决于业务场景。做为技术人员,必定不能忘了技术是为业务服务的,不要为了技术而技术,针对不一样业务进行技术选型也是一种很重要的能力!

相关文章
相关标签/搜索