分布式事务初步探索
部分描述转载其他大神文段,请多多包涵,本文只是为了大概介绍分布式事务,让团队小伙伴一起学习探索。
在了解分布式事务之前我们先了解下数据库本地事务,这有助于我们了解分布式事务以及设计思路。
数据库本地事务
数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。必须满足以下四个条件:
Atomic(原子性):指整个数据库事务是不可分割的工作单位。只有数据库中所有的操作执行成功,才算整个事务成功;事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该退回到执行事务前的状态。
Consistency(一致性):指数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。
Isolation(隔离性):指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。
Durability(持久性):指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。
其中隔离性有四种级别:
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读 | 可能 | 可能 | 可能 |
已提交读 | 不可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 可能 |
可串行化 | 不可能 | 不可能 | 不可能 |
脏读:一个事务T1修改了某个数据项在尚未提交情况下被另一个事务T2读取到,这个T1事务回滚的话T2就会读取到没有实际存在数据。
不可重复读:事务T1读取数据项,事务T2对这个数据项操作成功后,若T1再读取这个数据项就有可能两次同样条件下读取不一致的结果
幻读:事务T1读取记录时事务2增加了记录并提交,事务T1再次读取时可以看到事务2新增的记录;
InnoDB 实现原理
事务的 ACID 是通过 InnoDB 日志和锁来保证。事务的隔离性是通过数据库锁的机制实现的,持久性通过 Redo Log(重做日志)来实现,原子性和一致性通过 Undo Log 来实现。Undo Log 的原理很简单,为了满足事务的原子性,在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为 Undo Log)。然后进行数据的修改。如果出现了错误或者用户执行了 Rollback 语句,系统可以利用 Undo Log 中的备份将数据恢复到事务开始之前的状态。 和 Undo Log 相反,Redo Log 记录的是新数据的备份。在事务提交前,只要将 Redo Log 持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是 Redo Log 已经持久化。系统可以根据 Redo Log 的内容,将所有数据恢复到最新的状态。对具体实现过程有兴趣的同学可以去自行搜索扩展。
分布式事务
随着互联网快速发展,越来越多的公司开始选择微服务等服务架构模式,将一个单机服务拆分成多个服务应用,分别对应不同的数据源,原本数据库本地事务已经无法再满足我们的分布式模式,无法保证业务内部数据的一致性,分布式事务随着微服务话应运而生。
目前主流分布式事务解决分案:基于XA协议方案、基于可靠消息的最终一致性方案、TCC、Saga
1、基于XA协议方案:XA是一个分布式事务协议,大致分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。
优点:对业务0侵入性
缺点:严重依赖底层数据库支持XA协议,性能低、使用范围狭窄
2、基于可靠消息的最终一致性方案、TCC(TCC-Transaction )、Saga等方案就不做一一讲解了。
优点:避免对数据库底层资源依赖
缺点:对业务侵入性高
重点对比下XA和TCC两种方案:
都属于2PC算法,TCC方案是在业务层对资源操作,XA方案是在数据资源方面操作
阿里开源框架——Fescar
一个分布式事务理解成一个包含了若干 分支事务的全局事务。全局事务的职责是协调其下管辖的分支事务达成一致,要么一起成功提交,要么一起失败回滚。此外,通常 分支事务 本身就是一个满足 ACID 的 本地事务。
fescar定义了三个组件:
Transaction Coordinator (TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
Transaction Manager ™: 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
Resource Manager (RM): 控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。
大致流程图如下:
1、开始开启全局事务,创建TM组件
2、TM向TC申请一个全局事务,全局事务创建成功后生成一个全局唯一XID
3、RM先将回滚日志写入本地事务中
4、RM向TC注册分支事务,将其纳入XID对应全局事务管辖
5、本地业务提交
6、不管成功还是失败对TC进行汇报结果
若出现某个分支异常:
7、TM向TC发起针对XID全局回滚决议,TC循环请求每个分支进行回滚操作
若没有任何异常:
7、TM向TC发起针对XID全局提交决议,TC循环请求每个分支进行回滚日志清除
fescar相对其他解决方案优点
1、fescar与XA区别:
XA 方案的 RM 实际上是在数据库层,RM 本质上就是数据库自身(通过提供支持 XA 的驱动程序来供应用使用)。而 Fescar 的 RM 是以二方包的形式作为中间件层部署在应用程序这一侧的,不依赖与数据库本身对协议的支持。
两阶段层次:
在两阶段提交上,fescar相对于XA方案90%以上提高效率,少了阶段2的持锁时间
2、fescar对业务零侵入性
引入fescar分布式事务,不需要针对业务代码做任何改动,fescar是如何做到无侵入呢?
1、通过注解方式对方法进行拦截,开启全局分布式事务
2、fescar重写了数据源,在本地事务的提交过程中做了一系列操作,业务逻辑是无感知的,只需要配置数据源时使用fescar代理数据源即可。
fescar目前版本存在的问题
fescar目前最新版本是0.2.2,存在问题如下:
1、暂不支持springcloud微服务框架,需要等待0.5版本
2、TC事务协调器目前不是高可用,全局锁存在内存中,需要等待0.5版本支持高可用集群
3、一个非fescar本地事务在fescar全局事务期间触发,所造成的影响,例如读取到脏数据、写数据冲突等,处理版本未知。
如果以上这几个严重问题能够解决,个人觉得fescar可以在非核心业务逐渐使用起来。