分布式事务/分布式数据一致性
事务是指由一组操作组成的一个工作单元,这个工作单元具有原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。
什么是本地事务?
本地事务就是用关系数据库来控制事务,关系数据库通常都具有ACID特性,传统的单体应用通常会将数据全部存储在一个数据库中,会借助关系数据库来完成事务控制。
什么是分布式事务?
在分布式系统中一次操作由多个系统协同完成,这种一次事务操作涉及多个系统通过网络协同完成的过程称为分布式事务。这里强调的是多个系统通过网络协同完成一个事务的过程,并不强调多个系统访问了不同的数据库,即使多个系统访问的是同一个数据库,也是分布式的事务。另外一种分布式事务的表现是,一个应用程序使用了多个数据源连接了不同的数据库,当一次事务需要操作多个数据源,此时也属于分布式。
CAP原则
1.一致性
2.可用性
3.分区容错性。
在进行分布式系统设计时,同时满足“一致性”、“可用性”和“分区容忍性”三者是几乎不可能的
那么现在流行的分布式事务如何处理上述的问题的呢?下面简单介绍一下在互联网行业中使用比较常见的分布式事务的解决方案(两阶段提交协议(2PC)|事务补偿(TCC)|3PC)
- 2PC
第一阶段:投票阶段 (预提交请求)
具体情况如下:
协调者向所有的参与者发送事务执行请求,并等待参与者反馈事务执行结果。
事务参与者收到请求之后,执行事务但不提交,并记录事务日志。
参与者将自己事务执行情况反馈给协调者,同时阻塞等待协调者的后续指令。
可以理解为:除了提交事务别的事情都做了
第二阶段:事务提交阶段
这一阶段分为3中情况:
1.所有的参与者都回复能够正常执行事务
协调者将向所有的参与者发出提交事务的通知,具体步骤如下:
协调者向各个参与者发送 commit 通知,请求提交事务。
参与者收到事务提交通知之后,执行 commit 操作,然后释放占有的资源。
参与者向协调者返回事务 commit 结果信息
2.一个或多个参与者回复事务执行失败
3.协调者等待超时
对于第二、三种情况,协调者均认为参与者无法成功执行事务,为了整个集群数据的一致性,所以要向各个参与者发
送事务回滚通知,具体步骤如下:
协调者向各个参与者发送事务 rollback 通知,请求回滚事务。
参与者收到事务回滚通知之后,执行 rollback 操作,然后释放占有的资源。
参与者向协调者返回事务 rollback 结果信息。
如果第二阶段提交失败 则不断重试,不管是提交还是回滚事务
2PC 是一种尽量保证强一致性的分布式事务,因此它是同步阻塞的,而同步阻塞就导致长久的资源锁定问题,总体而言效率低,并且存在单点故障问题,在极端条件下存在数据不一致的风险。
2PC存在的缺点:
1.网络抖动导致的数据不一致: 第二阶段中协调者向参与者发送commit命令之后,一旦此时发生网络抖动,导致一部分参与者接收到了commit请求并执行,可其他未接到commit请求的参与者无法执行事务提交。进而导致整个分布式系统出现了数据不一致。
2.超时导致的同步阻塞问题: 2PC中的所有的参与者节点都为事务阻塞型,当某一个参与者节点出现通信超时,其余参与者都会被动阻塞占用资源不能释放。
3.单点故障的风险: 由于严重的依赖协调者,一旦协调者发生故障,而此时参与者还都处于锁定资源的状态,无法完成事务commit操作。虽然协调者出现故障后,会重新选举一个协调者,可无法解决因前一个协调者宕机导致的参与者处于阻塞状态的问题。
- 3PC
1.准备阶段(can_commit)
该阶段协调者会去询问各个参与者是否能够正常执行事务,参与者根据自身情况回复一个预估值,相对于真正的执行事务,
这个过程是轻量的,具体步骤如下:
协调者向各个参与者发送事务询问通知,询问是否可以执行事务操作,并等待回复。
各个参与者依据自身状况回复一个预估值,如果预估自己能够正常执行事务就返回确定信息,并进入预备状态,
否则返回否定信息
2.预备提交阶段(pre_commit)
本阶段协调者会根据第一阶段的询盘结果采取相应操作,
询盘结果主要有三种:
(1.所有的参与者都返回确定信息
(2.一个或多个参与者返回否定信息
(3.协调者等待超时
当结果是第一种情况:协调者向所有的事务参与者发送事务执行通知。
参与者收到通知后,执行事务但不提交。
参与者将事务执行情况返回给客户端。
在上述步骤中,如果参与者等待超时,则会中断事务
针对第二、三种情况:协调者认为事务无法正常执行,
于是向各个参与者发出abort 通知,请求退出预备状态,具体步骤如下:
如果阶段一中有任何一个参与者节点返回的结果是No响应,或者协调者在等待参与者节点反馈的过程中超时(2PC中只有协调者可以超时,参与者没有超时机制)。整个分布式事务就会中断,协调者就会向所有的参与者发送“abort”请求。
3.提交阶段(do_commit)
如果第二阶段事务未中断,那么本阶段协调者将会依据事务执行返回的结果来决定提交或回滚事务,分为三种情况:
1.所有的参与者都能正常执行事务
2.一个或多个参与者执行事务失败
3.协调者等待超时
针对第一种情况,协调者向各个参与者发起事务提交请求,具体步骤如下:
协调者向所有参与者发送事务 commit 通知。
所有参与者在收到通知之后执行 commit 操作,并释放占有的资源。
参与者向协调者反馈事务提交结果。
针对第二、三种情况,协调者认为事务无法成功执行,于是向各个参与者发送事务回滚请求,具体步骤如下:
1.协调者向所有参与者发送事务 rollback 通知。
2.所有参与者在收到通知之后执行 rollback 操作,并释放占有的资源。
3.参与者向协调者反馈事务回滚结果。
TCC
2PC 和 3PC 都是数据库层面的,而 TCC 是业务层面的分布式事务,就像我前面说的分布式事务不仅仅包括数据库的操作,还包括发送短信等,这时候 TCC 就派上用场了!
TCC包含了三个阶段:Try,Confirm,Cancel,因此而得名「TCC」。
Try 指的是预留,即资源的预留和锁定, 注意是预留。
Confirm 指的是确认操作,这一步其实就是真正的执行了。
Cancel 指的是撤销操作,可以理解为把预留阶段的动作撤销了。
本文参照大佬的博客:敖丙大佬
以及YARN_weizai