《我想进大厂》之分布式事务篇(一)

wg204wg
发布于 2022-6-9 16:42
浏览
0收藏

 

对于分布式事务,相信所有人都应该很了解,为什么会有分布式事务?无论是数据量导致的分库,还是现在微服务盛行的场景都是他出现的原因。

这一篇内容还是避免不了俗套,主要的范围无非是XA、2PC、3PC、TCC,再最后到Seata。

但是,我认为这东西,只是适用于面试和理论的了解,你真要说这些方案实际生产中有人用吗?

有,但是会实现的更简单,不会套用理论来实现,大厂有大厂的解决方案,中小公司用框架或者压根就不存在分布式事务的问题。

那,为什么还要写这个?

为了你面试八股文啊,小可爱。

事务

要说分布式事务,首先还是从事务的基本特征说起。

A原子性:在事务的执行过程中,要么全部执行成功,要么都不成功。

C一致性:事务在执行前后,不能破坏数据的完整性。一致性更多的说的是通过AID来达到目的,数据应该符合预先的定义和约束,由应用层面来保证,还有的说法是C是强行为了ACID凑出来的。

I隔离性:多个事务之间是互相隔离的,事务之间不能互相干扰,涉及到不同事务的隔离级别的问题。

D持久性:一旦事务提交,数据库中数据的状态就应该是永久性的。

XA

XA(eXtended Architecture)是指由X/Open 组织提出的分布式事务处理的规范,他是一个规范或者说是协议,定义了事务管理器TM(Transaction Manager),资源管理器RM(Resource Manager),和应用程序。

事务管理器TM就是事务的协调者,资源管理器RM可以认为就是一个数据库。

 《我想进大厂》之分布式事务篇(一)-鸿蒙开发者社区
2PC

XA定义了规范,那么2PC和3PC就是他的具体实现方式。

2PC叫做二阶段提交,分为投票阶段和执行阶段两个阶段。

投票阶段

TM向所有的参与者发送prepare请求,询问是否可以执行事务,等待各个参与者的响应。

这个阶段可以认为只是执行了事务的SQL语句,但是还没有提交。

如果都执行成功了就返回YES,否则返回NO。

 《我想进大厂》之分布式事务篇(一)-鸿蒙开发者社区
执行阶段

执行阶段就是真正的事务提交的阶段,但是要考虑到失败的情况。

如果所有的参与者都返回YES,那么就执行发送commit命令,参与者收到之后执行提交事务。

反之,只要有任意一个参与者返回的是NO的话,就发送rollback命令,然后执行回滚的操作。

 《我想进大厂》之分布式事务篇(一)-鸿蒙开发者社区
2PC的缺陷

  1. 同步阻塞,可以看到,在执行事务的过程当中,所有数据库的资源都被锁定,如果这时候有其他人来访问这些资源,将会被阻塞,这是一个很大的性能问题。
  2. TM单点问题,只要一个TM,一旦TM宕机,那么整个流程无法继续完成。
  3. 数据不一致,如果在执行阶段,参与者脑裂或者其他故障导致没有收到commit请求,部分提交事务,部分未提交,那么数据不一致的问题就产生了。

3PC

既然2PC有这么多问题,所以就衍生出了3PC的概念,也叫做三阶段提交,他把整个流程分成了CanCommit、PreCommit、DoCommit三个步骤,相比2PC,增加的就是CanCommit阶段。

CanCommit

这个阶段就是先询问数据库是否执行事务,发送一个canCommit的请求去询问,如果可以的话就返回YES,反之返回NO。

 《我想进大厂》之分布式事务篇(一)-鸿蒙开发者社区
PreCommit

这个阶段就等同于2PC的投票阶段了,发送preCommit命令,然后去执行SQL事务,成功就返回YES,反之返回NO。

 《我想进大厂》之分布式事务篇(一)-鸿蒙开发者社区
但是,这个地方的区别在于参与者有了超时机制,如果参与者超时未收到doCommit命令的话,将会默认去提交事务。

DoCommit

DoCommit阶段对应到2PC的执行阶段,如果上一个阶段都是收到YES的话,那么就发送doCommit命令去提交事务,反之则会发送abort命令去中断事务的执行。

 《我想进大厂》之分布式事务篇(一)-鸿蒙开发者社区
相比2PC的改进

对于2PC的同步阻塞的问题,我们可以看到因为3PC加入了参与者的超时机制,所以原来2PC的如果某个参与者故障导致的同步阻塞的问题时间缩短了,这是一个优化,但是并没有完全避免。

第二个单点故障的问题,同样因为超时机制的引入,一定程度上也算是优化了。

但是数据不一致的问题,这个始终没有得到解决。

举个栗子:

在PreCommit阶段,某个参与者发生脑裂,无法收到TM的请求,这时候其他参与者执行abort事务回滚,而脑裂的参与者超时之后继续提交事务,还是有可能发生数据不一致的问题。

那么,为什么要加入DoCommit这个阶段呢?就是为了引入超时机制,事先我们先确认数据库是否都可以执行事务,如果都OK,那么才会进入后面的步骤,所以既然都可以执行,那么超时之后说明发生了问题,就自动提交事务。

TCC

TCC的模式叫做Try、Confirm、Cancel,实际上也就是2PC的一个变种而已。

实现这个模式,一个事务的接口需要拆分成3个,也就是Try预占、Confirm确认提交、最后Cancel回滚。

对于TCC来说,实际生产我基本上就没看见过有人用,考虑到原因,首先是程序员的本身素质参差不齐,多个团队协作你很难去约束别人按照你的规则来实现,另外一点就是太过于复杂。

如果说有简单的应用的话,库存的应用或许可以算做是一个。

一般库存的操作,很多实现方案里面都会会在下单的时候先预占库存,下单成功之后再实际去扣减库存,最终如果发生了异常再回退。

 《我想进大厂》之分布式事务篇(一)-鸿蒙开发者社区
冻结、预占库存就是2PC的准备阶段,真正下单成功去扣减库存就是2PC的提交阶段,回滚就是某个发生异常的回滚操作,只不过在应用层面来实现了2PC的机制而已。

 

文章转自公众号:艾小仙

分类
标签
已于2022-6-9 16:42:02修改
收藏
回复
举报
回复
    相关推荐