1.1 什么是事务mysql
数据库事务(简称:事务,Transaction)是指数据库执行过程当中的一个逻辑单位,由一个有限的数据库操做序列构成。sql
事务拥有如下四个特性,习惯上被称为ACID特性:数据库
1.2 本地事务编程
起初,事务仅限于对单一数据库资源的访问控制:架构
架构服务化之后,事务的概念延伸到了服务中。假若将一个单一的服务操做做为一个事务,那么整个服务操做只能涉及一个单一的数据库资源:并发
这类基于单个服务单一数据库资源访问的事务,被称为本地事务(Local Transaction)。框架
本地事务主要限制在单个会话内,不涉及多个数据库资源。可是在基于SOA(Service-Oriented Architecture,面向服务架构)的分布式应用环境下,愈来愈多的应用要求对多个数据库资源,多个服务的访问都能归入到同一个事务当中,分布式事务应运而生。nosql
最先的分布式事务应用架构很简单,不涉及服务间的访问调用,仅仅是服务内操做涉及到对多个数据库资源的访问。分布式
当一个服务操做访问不一样的数据库资源,又但愿对它们的访问具备事务特性时,就须要采用分布式事务来协调全部的事务参与者。高并发
对于上面介绍的分布式事务应用架构,尽管一个服务操做会访问多个数据库资源,可是毕竟整个事务仍是控制在单一服务的内部。若是一个服务操做须要调用另一个服务,这时的事务就须要跨越多个服务了。在这种状况下,起始于某个服务的事务在调用另一个服务的时候,须要以某种机制流转到另一个服务,从而使被调用的服务访问的资源也自动加入到该事务当中来。下图反映了这样一个跨越多个服务的分布式事务:
若是将上面这两种场景(一个服务能够调用多个数据库资源,也能够调用其余服务)结合在一块儿,对此进行延伸,整个分布式事务的参与者将会组成以下图所示的树形拓扑结构。在一个跨服务的分布式事务中,事务的发起者和提交均系同一个,它能够是整个调用的客户端,也能够是客户端最早调用的那个服务。
较之基于单一数据库资源访问的本地事务,分布式事务的应用架构更为复杂。
在不一样的分布式应用架构下,实现一个分布式事务要考虑的问题并不彻底同样,好比对多资源的协调、事务的跨服务传播等,实现机制也是复杂多变。尽管有这么多工程细节须要考虑,但分布式事务最核心的仍是其 ACID 特性。所以,想要了解一个分布式事务,就先从了解它是怎么实现事务 ACID 特性开始。
下文将从两个最多见的分布式事务模型入手,着重分析分布式事务的基础共通点,即如何保证分布式事务的 ACID 特性。
1.基于XA协议的两阶段提交
XA是一个分布式事务协议,由Tuxedo提出。XA中大体分为两部分:事务管理器和本地资源管理器。其中本地资源管理器每每由数据库实现,好比Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器做为全局的调度者,负责各个本地资源的提交和回滚。XA实现分布式事务的原理以下:
总的来讲,XA协议比较简单,并且一旦商业数据库实现了XA协议,使用分布式事务的成本也比较低。可是,XA也有致命的缺点,那就是性能不理想,特别是在交易下单链路,每每并发量很高,XA没法知足高并发场景。XA目前在商业数据库支持的比较理想,在mysql数据库中支持的不太理想,mysql的XA实现,没有记录prepare阶段日志,主备切换回致使主库与备库数据不一致。许多nosql也没有支持XA,这让XA的应用场景变得很是狭隘。
2.消息事务+最终一致性
所谓的消息事务就是基于消息中间件的两阶段提交,本质上是对消息中间件的一种特殊利用,它是将本地事务和发消息放在了一个分布式事务里,保证要么本地操做成功成功而且对外发消息成功,要么二者都失败,开源的RocketMQ就支持这一特性,具体原理以下:
一、A系统向消息中间件发送一条预备消息
二、消息中间件保存预备消息并返回成功
三、A执行本地事务
四、A发送提交消息给消息中间件
经过以上4步完成了一个消息事务。对于以上的4个步骤,每一个步骤均可能产生错误,下面一一分析:
基于消息中间件的两阶段提交每每用在高并发场景下,将一个分布式事务拆成一个消息事务(A系统的本地操做+发消息)+B系统的本地操做,其中B系统的操做由消息驱动,只要消息事务成功,那么A操做必定成功,消息也必定发出来了,这时候B会收到消息去执行本地操做,若是本地操做失败,消息会重投,直到B操做成功,这样就变相地实现了A与B的分布式事务。原理以下:
虽然上面的方案可以完成A和B的操做,可是A和B并非严格一致的,而是最终一致的,咱们在这里牺牲了一致性,换来了性能的大幅度提高。固然,这种玩法也是有风险的,若是B一直执行不成功,那么一致性会被破坏,具体要不要玩,仍是得看业务可以承担多少风险。
3.TCC 模型
TCC(Try-Confirm-Cancel)分布式事务模型相对于 XA 等传统模型,其特征在于它不依赖资源管理器(RM)对分布式事务的支持,而是经过对业务逻辑的分解来实现分布式事务。
TCC 模型认为对于业务系统中一个特定的业务逻辑,其对外提供服务时,必须接受一些不肯定性,即对业务逻辑初步操做的调用仅是一个临时性操做,调用它的主业务服务保留了后续的取消权。若是主业务服务认为全局事务应该回滚,它会要求取消以前的临时性操做,这就对应从业务服务的取消操做。而当主业务服务认为全局事务应该提交时,它会放弃以前临时性操做的取消权,这对应从业务服务的确认操做。每个初步操做,最终都会被确认或取消。
所以,针对一个具体的业务服务,TCC 分布式事务模型须要业务系统提供三段业务逻辑:
初步操做 Try:完成全部业务检查,预留必须的业务资源。
确认操做 Confirm:真正执行的业务逻辑,不做任何业务检查,只使用 Try 阶段预留的业务资源。所以,只要 Try 操做成功,Confirm 必须能成功。另外,Confirm 操做需知足幂等性,保证一笔分布式事务有且只能成功一次。
取消操做 Cancel:释放 Try 阶段预留的业务资源。一样的,Cancel 操做也须要知足幂等性。
TCC 分布式事务模型包括三部分:
1.主业务服务:主业务服务为整个业务活动的发起方,服务的编排者,负责发起并完成整个业务活动。
2.从业务服务:从业务服务是整个业务活动的参与方,负责提供 TCC 业务操做,实现初步操做(Try)、确认操做(Confirm)、取消操做(Cancel)三个接口,供主业务服务调用。
3.业务活动管理器:业务活动管理器管理控制整个业务活动,包括记录维护 TCC 全局事务的事务状态和每一个从业务服务的子事务状态,并在业务活动提交时调用全部从业务服务的 Confirm 操做,在业务活动取消时调用全部从业务服务的 Cancel 操做。
一个完整的 TCC 分布式事务流程以下:
TCC模型小结
所谓的TCC编程模式,也是两阶段提交的一个变种。TCC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操做。以在线下单为例,Try阶段会去扣库存,Confirm阶段则是去更新订单状态,若是更新订单失败,则进入Cancel阶段,会去恢复库存。总之,TCC就是经过代码人为实现了两阶段提交,不一样的业务场景所写的代码都不同,复杂度也不同,所以,这种模式并不能很好地被复用。
分布式事务,本质上是对多个数据库的事务进行统一控制,按照控制力度能够分为:不控制、部分控制和彻底控制。不控制就是不引入分布式事务,部分控制就是各类变种的两阶段提交,包括上面提到的消息事务+最终一致性、TCC模式,而彻底控制就是彻底实现两阶段提交。部分控制的好处是并发量和性能很好,缺点是数据一致性减弱了,彻底控制则是牺牲了性能,保障了一致性,具体用哪一种方式,最终仍是取决于业务场景。做为技术人员,必定不能忘了技术是为业务服务的,不要为了技术而技术,针对不一样业务进行技术选型也是一种很重要的能力!