2PC、3PC、TCC

导语:看完《软件架构设计-大型网站技术架构与业务架构融合之道》这本书之后,一股脑灌到脑子里很多关于事务一致性的概念,比如说2PC、TCC。但是似乎只是留下了一个模糊的印象,对他们使用的场景,有什么区别没有清晰的概念,所以想借这篇文章,捋捋清楚。

数据库事务

对于数据库来说,事务就是一个“代码块”,这个代码块要么不执行,要么全部执行,事务要操作数据(数据库里的表),事务与事务之间会存在并发冲突,就好比在多线程编程中,不同的线程操作同一份数据,存在线程间的并发是一个道理。

数据库事务的四个特性ACID:
Atomicity(原子性): 事务是一个不可分割的整体,所有操作要么全做,要么全不做;只要事务中有一个操作出错,那么之前执行过的操作要全部回滚到事务开始前的状态
Consistency(一致性): 事务执行前后,事务从一个状态到另一个状态必须是一致的,比如A向B转账(A、B的总金额就是一个一致性状态),不能出现A扣了钱,但是B没有收到的情况发生
Isolation(隔离性): 多个并发事务之间相互隔离,不能互相干扰。这里的并发事务是指两个事务操作了同一份数据的情况;而对于并发事务操作同一份数据的隔离性问题,则是要求不能出现脏读、幻读的情况。
Durability(持久性): 事务完成(提交)后,对数据库的更改是永久保存的,不能再回滚

那么事务的并发就会导致如下的几类问题:

问题描述
脏读 (未提交读)事务A读取了一条记录的值,然后基于这个值做业务逻辑,在事务A提交之前,事务B回滚了该记录,导致事务A读到了一条脏数据
不可重复读(已提交读)在同一个事务里,两次读取同一行记录,但结果不一样。因为有别的事务在期间对这条数据进行了修改并且提交了
幻读在同一个事务里,同样的select语句,执行两次,返回的记录条数不一样。因为再次期间有别的事务进行了insert/delete操作
丢失更新两个事务同时修改同一条记录,事务A的修改被事务B覆盖了。举个例子,x=5,事务A、B同时把x读取出来,减1之后再写回,得到x=4,其实x正确的值应该等于3

针对上述的几类问题,数据库设置了不同的隔离级别,接下来以mysql为例,分析隔离级别是如何定义的:

名称解决问题
RU (Read Uncommited)相当于什么都没有做,上面的四个问题一个都没有解决,所以实际中这个隔离级别不会被采用
RC (Read Commited)解决了脏读问题,事务只能读到别的事务已经提交的数据
RR (Repeatable Read)解决了脏读、不可重复读、幻读问题,是innodb默认的隔离级别
Serialization序列化(串行化)解决全部问题

分布式事务

首先要抛出的一定是概念,什么是分布式事务?分布式事务和数据库事务从本质上看是相同的概念,它也需要满足事务的四大特性ACID。只不过分布式事务相对于本地事务而言表现形式有很大不同。数据库事务更多是在同一个数据库里通过加锁或者其他方式实现的,而分布式事务是指在多个不同的数据库中的事务。以一个典型的分布式事务问题–“转账”为例,如下图
在这里插入图片描述
如上图的例子,如果在支付宝余额扣减成功,但是通知余额宝失败,或者余额宝接到通知后执行余额增加时操作失败,因为两份(支付宝余额和余额宝)数据不在同一个数据库里,单纯的数据库事务就没有办法解决了。这个时候就出现了分布式事务问题。
所以简单总结来说,分布式事务和数据库事务的区别就在于,操作的是否是同一个数据库

2PC

两阶段提交又称为2PC(two-phase commit protocol),2PC是一个非常经典的强一致、中心化的原子提交协议。2PC中有两类角色,协调者和参与者,具体到数据库的实现来说,每一个数据库就是一个参与者,调用方就是协调者。

第一阶段:准备阶段
在这里插入图片描述
协调者向各个参与者发起询问,参与者收到询问请求后,一般会打开本地数据库事务,然后开始执行数据库本地事务,但在执行完成后刽立马提交事务,而是向协调者恢复yes或者no,当然也有超时的情况存在。
第二阶段:提交阶段
在这里插入图片描述
如果第一阶段所有参与者均回复了yes,则协调者向所有参与者发起事务提交操作,所有参与者各自执行事务,然后回复ack。如果第一阶段有参与者回复了no或者超时了,那么这个时候第二阶段协调者就要发起回滚操作,让参与者均回到初始状态。

2PC 的问题

  1. 性能问题,在阶段1,资源锁定之后,要等所有参与者都返回之后,才能一起进入第二个阶段,不能很好的应对高并发场景。
  2. 阶段1完成之后,阶段2执行的过程中事务的协调者宕机,这个时候所有的参与者都收不到commit或者rollback的指令,将处于“悬而不决”的状态
  3. 阶段1完成之后,在阶段2,事务协调者向所有参与者发送了commit指令,但其中一个参与者超时或者出错了,那么此时其他参与者是提交呢还是回滚呢,也不能确定

3PC

三阶段提交又称为3PC,他在2PC的基础上增加了can commit阶段,并引入了超时机制。一旦参与者迟迟没有收到协调者的commit请求,就会自动进行本地commit,这样相对有效的解决了协调者的单点故障问题

在这里插入图片描述
相对2PC而言,3PC给协调者和参与者都设置了超时机制,这点避免了由于协调者宕机而造成的资源浪费。但是3PC似乎加重了性能问题,也没有解决数据一致性问题。

TCC

2PC、3PC 通常用来解决两个数据库之间的分布式事务问题。但是现在企业采用的是各种各样的SOA服务,更需要解决两个服务之间的分布式事务问题。为了解决SOA系统中分布式事务的问题,支付宝提出了TCC。TCC(Try Confirm Cancel),他是一个应用层面的的2PC协议,confirm对应2PC的commit操作,cancel对应rollback操作。
第一阶段:准备阶段
调用调用所有服务方提供的try接口,这个阶段各调用方做资源检查和资源锁定,为接下来的阶段2做准备。
第二阶段:确定/取消阶段
如果所有服务方都返回yes,则进入提交阶段,调用方调用各个服务方的confirm接口,各服务方进行事务提交。如果有一个服务在第一阶段返回no或者超时了,则调用方调用各服务方的cancel接口。
在这里插入图片描述
这里有个问题,TCC既然借鉴了2PC的思路,那么他是如何解决2PC的问题的呢?也就是说,在阶段2,调用方发生宕机,或者某个服务超时了,他是如何处理的?答案是:不断重试,不管是confirm失败了还是cancel失败了,都不断重试。这就要求confirm和cancel操作都必须支持幂等操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值