1、聊聊事务原理
一句话来说,要么胜利,要么失败,不能有两头态
1.1、回顾一下ACID
- Atomic:原子性,就是一堆SQL,要么一起胜利,要么都别执行,不容许某个SQL胜利了,某个SQL失败了,这就是扯淡么
- Consistency:一致性,这个是针对数据一致性来说的,就是一组SQL执行之前,数据必须是精确的,执行之后,数据也必须是精确的。别搞了半天,执行完了SQL,后果SQL对应的数据批改没给你执行,这不是坑爹么
- Isolation:隔离性,这个就是说多个事务在跑的时候不能相互烦扰,别事务A操作个数据,弄到一半儿还没弄好呢,后果事务B来改了这个数据,导致事务A的操作出错了,那不就搞笑了么
- Durability:持久性,事务胜利了,就必须永恒对数据的批改是无效的,别过了一会儿数据本人没了,不见了,那就好玩儿了
1.2、陈词滥调的事务隔离级别
- 读未提交(Read Uncommitted):这个很坑爹,就是说某个事务还没提交的时候,批改的数据,就让别的事务给读到了,这就恶心了,很容易导致出错的。这个也叫做脏读
- 读已提交(Read Committed)又叫做不可反复读:这个比下面那个略微好一点,然而一样比拟难堪,就是说事务A在跑的时候, 先查问了一个数据是值1,而后过了段时间,事务B把那个数据给批改了一下还提交了,此时事务A再次查问这个数据就成了值2了,这是读了人家事务提交的数据啊,所以是读已提交。这个也叫做不可反复读,就是所谓的一个事务内对一个数据两次读,可能会读到不一样的值
- 可反复读(Read Repeatable):这个就是比下面那个再好点儿,就是说事务A在执行过程中,对某个数据的值,无论读多少次都是值1;哪怕这个过程中事务B批改了数据的值还提交了,然而事务A读到的还是本人事务开始时这个数据的值
- 串行化:幻读,不可反复读和可反复读都是针对两个事务同时对某条数据在批改,然而幻读针对的是插入,比方某个事务把所有行的某个字段都批改为了2,后果另外一个事务插入了一条数据,那个字段的值是1,而后就难堪了。第一个事务会忽然发现多进去一条数据,那个数据的字段是1。如果要解决幻读,就须要应用串行化级别的隔离级别,所有事务都串行起来,不容许多个事务并行操作
2、MySQL的事务隔离级别分析一下
2.1、InnoDB存储引擎架构设计
2.2、MySQL是怎么实现RR事务隔离的
2.2.1、Redo Log日志理解一下
2.2.2、MVC Undo Log日志链条
- 事务A,插入了一条数据
- 接着有一个事务B跑来批改了一下这条数据
- 接着假如事务C又来批改了一下这个值为C
2.2.3、 MySQL RR readview + undo log日志链
- 首先假如有一条数据是事务id=50的一个事务插入,之后有事务A和事务B同时在运行
- 事务A发动一个查问,他就是第一次查问就会生成一个ReadView,此时ReadView里的creator_trx_id是60,min_trx_id是60,max_trx_id=71,m_ids=[60,70]
- 这个时候事务A基于这个ReadView去查问这条数据,会发现这条数据的trx_id=50,是小于ReadView里的min_trx_id的,
阐明他发动查问之前,早就有事务插入这条数据了还提交了所以此时能够查到这条原始数据 - 接着事务B此时更新了这条数据的值为B,此时会批改trx_id=70,同时生成一个undo log,而且此时事务B还提交了,也就是说事务B曾经完结了
- 这个时候有一个问题,ReadView中的m_ids此时还会是60和70吗?
那是必然的,因为ReadView一旦生成就不会扭转了,这个时候尽管事务B曾经完结了,然而事务A的ReadView里,还是会有60和70两个事务id,意思就是说,你在事务A开启的时候,事务B过后是在运行的
那好,接着此时事务A去查问这条数据的值,他会诧异的发现此时数据的trx_id是70了,70一方面是在ReadView的min_trx_id和max_trx_id的范畴区间的,同时还在m_ids列表中
阐明起码是事务A开启查问的时候,id=70的这个事务B还是在运行的,而后由这个事务B更新了这条数据,此时事务A是不能查问到事务B的这个值的,因而这个时候只能顺着指针往历史版本链条下来找
接着事务顺着指针找到上面一条数据,trx_id为50,是小于ReadView的min_trx_id的,阐明在他开启查找之前,就曾经提交这个事务了,所以事务A是能够查问到这个值的,此时事务A查到的是原始值
你事务A屡次读同一个数据,每次读到的都是一样的值,除非是他本人批改了值,否则读到的都是一样的值,不论别的事务如何批改数据,事务A的ReadView始终是不变的,他基于这个ReadView始终看到的值是一样的 - 接着此时事务A再次查问,此时发现符合条件有2条数据,一条是原始值的那个数据,一条是事务C插入的那条数据,然而事务C插入的那条数据的trx_id是80,这个80是大于本人的ReadView的max_trx_id的,阐明是本人发动查问之后,这个事务才启动的,所以此时这条数据是不能查问的,所以MySQL RR防止了幻读
3、XA标准理解一下
X/Open的组织定义了分布式事务的模型,这外面有几个角色,就是AP(Application,应用程序),TM(Transaction Manager,事务管理器),RM(Resource Manager,资源管理器),CRM(Communication Resource Manager,通信资源管理器)
TM的话就是一个在零碎里嵌入的一个专门治理横跨多个数据库的事务的一个组件,RM的话说白了就是数据库(比方MySQL),CRM能够是消息中间件(然而也能够不必这个货色)
那么XA是啥呢?说白了,就是定义好的那个TM与RM之间的接口标准,就是治理分布式事务的那个组件跟各个数据库之间通信的一个接口
这个XA仅仅是个标准,具体的实现是数据库产商来提供的,比如说MySQL就会提供XA标准的接口函数和类库实现
JTA(Java Transaction API),是J2EE的编程接口标准,它是XA协定的JAVA实现,例如Atomikos, bitronix都提供了jar包形式的JTA实现框架。这样咱们就可能在Tomcat或者Jetty之类的服务器上运行应用JTA实现事务的利用零碎,个别是单机跨多库状况下,然而在微服务的明天,个别都是一个服务一个库,个别都不会这么干了
3.1、2PC是啥?
X/Open组织定义的一套分布式事务的模型,还是比拟虚的,还没方法落地,而且XA接口标准也是一个比拟务实的一个货色,还是没法落地的
2PC说白了就是基于XA标准搞的一套分布式事务的实践,也能够叫做一套标准,或者是协定
毛病:
1、同步阻塞:在阶段一里执行prepare操作会占用资源,始终到整个分布式事务实现,才会开释资源,这个过程中,如果有其他人要拜访这个资源,就会被阻塞住
2、单点故障:TM是个单点,一旦挂掉就完蛋了
3、事务状态失落:即便把TM做成一个双机热备的,一个TM挂了主动选举其余的TM进去,然而如果TM挂掉的同时,接管到commit音讯的某个库也挂了,此时即便从新选举了其余的TM,压根儿不晓得这个分布式事务以后的状态,因为不晓得哪个库接管过commit音讯,那个接管过commit音讯的库也挂了
4、脑裂问题:在阶段二中,如果产生了脑裂问题,那么就会导致某些数据库没有接管到commit音讯,那就完蛋了,有些库收到了commit音讯,后果有些库没有收到,这咋整呢,那必定完蛋了
3.1、3PC是啥?
如果人家TM在DoCommit阶段发送了abort音讯给各个库,后果因为脑裂问题,某个库没接管到abort音讯,本人还执行了commit操作,不是也不对么
4、TCC是个什么原理(柔性事务)
try、confirm和cancel
4.1、容许空回滚
事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会呈现因为丢包而导致的网络超时,此时事务管理器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作,而 Cancel 操作调用未呈现超时
TCC 服务在未收到 Try 申请的状况下收到 Cancel 申请,这种场景被称为空回滚;空回滚在生产环境经常出现,用户在实现TCC服务时,应容许容许空回滚的执行,即收到空回滚时返回胜利
4.2、防悬挂管制
事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会呈现因网络拥挤而导致的超时,此时事务管理器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作,Cancel 调用未超时;在此之后,拥挤在网络上的一阶段 Try 数据包被 TCC 服务收到,呈现了二阶段 Cancel 申请比一阶段 Try 申请先执行的状况,此 TCC 服务在执行完到的 Try 之后,将永远不会再收到二阶段的 Confirm 或者 Cancel ,造成 TCC 服务悬挂。
用户在实现 TCC 服务时,要容许空回滚,然而要拒绝执行空回滚之后 Try 申请,要避免出现悬挂
4.3、TCC vs 2PC
2PC:是资源层面的分布式事务,始终会持有资源的锁。 如果跨十几个库,一下锁这么多数据库,会导致,极度浪费资源。升高了吞吐量
TCC:在业务层面的分布式事务,最终一致性,不会始终持有锁。将锁的粒度变小,每操作完一个库,就开释了锁。然而须要本来一个接口要拆三个接口,比拟麻烦
用2PC 比 TCC 要性能高。因为tcc多了屡次接口调用。而此时的2PC 不怕占用资源,反正就一个调用。高并发场景下TCC 劣势要大
4.4、异步确保型TCC技术计划
如果要接入到一个TCC分布式事务中来,从业务服务必须革新本人的接口,原本就是一个接口,当初要新增两个接口,try接口,cancel接口。革新起来比拟麻烦
这个大略来说就是把之前的通用型TCC计划给革新了一下,就是在主业务服务和从业务服务之间加了一个可靠消息服务,然而这个可靠消息服务可不是在申请什么MQ之类的货色,而是将音讯放在数据库里的
4.5、补偿性TCC解决方案
弥补型 TCC 解决方案与通用型 TCC 解决方案的构造类似,其从业务服务也须要参加到主业务服务的流动决策当中。但不一样的是,前者的从业务服务只须要提供 Do 和 Compensate 两个接口,而后者须要提供三个接口
Do 接口间接执行真正的残缺业务逻辑,实现业务解决,业务执行后果内部可见;Compensate 操作用于业务弥补,对消或局部对消正向业务操作的业务后果,Compensate操作需满足幂等性。
与通用型解决方案相比,弥补型解决方案的从业务服务不须要革新原有业务逻辑,只须要额定减少一个弥补回滚逻辑即可,业务革新量较小。但要留神的是,业务在一阶段就执行残缺个业务逻辑,无奈做到无效的事务隔离,当须要回滚时,可能存在弥补失败的状况,还须要额定的异样解决机制,比方人工染指