当前位置: 首页 > 科技观察

详解分布式事务XA实现数据一致性的协议和原理--2PC和3PC

时间:2023-03-21 19:14:45 科技观察

概述大型业务系统具有用户多、并发高的特点,在这方面,中心化数据库的性能(单机数据库)困难因此,主流互联网公司往往采用分布式(架构)数据库,物理上使用更多低端设备,逻辑上横向拆分大表来支持业务需求。虽然分布式数据库可以解决性能问题,但是事务一致性(Consistency)问题在分布式数据库上很难解决。数据一致性?一致性问题,“万恶之源”是数据冗余和分布,网络交互+网络异常是常态。1、数据一致性的情况。主库、从库和缓存数据一致性,同数据冗余,关系型数据库,为保证数据库的高可用和高性能,一般采用主从(备)架构,并引入缓存。其中,数据不一致存在于数据冗余的时间窗口。常见的解决方案可以参考网上常见的数据库架构方案。数据多副本之间的数据一致性,同一个数据副本,大数据领域,一条数据会有多个副本,存储在不同的节点上。客户端可以访问任意节点进行读写操作。常用的解决方案是基于Paxos、ZAB、Raft、Quorum、Gossip等开源实现。分布式服务之间的数据一致性,相关数据分布,分布式服务,不同的服务操作不同的库(表),库(表)必须始终如一。一种常用的解决方案是分布式事务一致性解决方案。2.数据一致性的概念强一致性弱一致性最终一致性3.数据一致性原理ACIDCAPBASE4.数据一致性协议二阶段提交协议三阶段提交协议TCC协议Paxos协议ZAB协议Raft协议Quorum协议Gossip协议分布式事务XA实现数据一致性所谓分布式服务就是将通过本地接口交互的模块拆分成分离应用独立部署,通过RPC和MQ交互。以物流中的订单和库存为例(如果添加订单记录,则库存为-1)。在集中式架构中,为了保证订单表和库存表的一致性,只需要一个本地事务(ACID)就可以保证在分布式架构中,订单表由orderservice操作,库存表由orderservice操作由库存服务。为了保证订单表和库存表的一致性,需要保证订单服务对订单表的操作和库存服务对库存表的操作同时成功。之前的本地事务变成了分布式事务。由于服务通过网络交互是正常+网络异常,所以会出现服务间数据不一致的情况。这就涉及到一个分布式事务一致性的问题。如何保证分布式事务的ACID,业界也有比较成熟的解决方案,一般是2阶段提交2PC协议或者是3阶段提交3PC协议的改进版本,下面简单介绍一下。2PC协议也变成了2-stagecommit,1preparestage,2commitstage。所谓两个阶段是指:第一阶段:准备阶段(投票阶段)和第二阶段:提交阶段(执行阶段)。在准备阶段,事务协调器(事务管理器)向每个参与者(资源管理器)发送Prepare消息,每个参与者要么直接返回失败(如权限验证失败),要么在本地执行事务,写入本地redo和Undo日志,但不提交,达到“万事俱备,只欠东风”的状态。准备阶段又可以分为以下三个步骤:1)协调节点询问所有参与节点是否可以执行提交操作(投票),并开始等待各参与节点的响应。2)参与节点执行所有事务操作,直到发起查询,并将Undo信息和Redo信息写入日志。(注:如果成功,这里的每个参与者实际上都执行了事务操作)3)每个参与者节点响应协调节点发起的查询。如果参与节点的交易操作实际执行成功,则返回“同意”消息;如果参与者节点的事务操作确实失败,则返回“中止”消息。在提交阶段,如果协调器收到某个参与者的失败消息或超时,则直接向每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据协调者的指令执行提交或回滚操作,以释放事务处理过程中使用的所有锁资源。(注意:final阶段一定要释放锁资源)接下来分两种情况讨论提交阶段的流程。当协调节点从所有参与节点获得的相应消息为“同意”时:1)协调节点向所有参与节点发送“提交”请求。2)参与节点正式完成操作,释放整个交易周期占用的资源。3)参与节点向协调节点发送“完成”消息。4)协调节点收到所有参与节点反馈的“完成”消息后,完成交易。如果第一阶段任一参与节点返回的响应消息为“abort”,或者协调节点无法在第一阶段查询超时前获取到所有参与节点的响应消息:1)协调节点发送消息给所有参与者主节点发送“回滚操作(rollback)”请求。2)参与节点利用之前写入的Undo信息进行回滚,释放整个交易周期占用的资源。3)参与节点向协调节点发送“回滚完成”消息。4)协调节点收到所有参与节点反馈的“回滚完成”消息后取消交易。无论最终结果如何,第二阶段结束当前交易。两阶段提交似乎可以提供原子操作,但不幸的是,两阶段提交仍然有几个缺点:1.同步阻塞问题。在执行过程中,所有参与节点都是事务阻塞。当参与者占用公共资源时,其他第三方节点访问公共资源时必须被阻止。2.单点故障。由于协调器的重要性,一旦协调器失效。参与者将永远被阻止。尤其是在第二阶段,如果协调器失效,所有参与者仍处于锁定事务资源的状态,无法继续完成事务操作。(如果协调器挂了,可以重新选举一个协调器,但是不能解决因为协调器宕机导致参与者阻塞的问题)3.数据不一致。在双阶段提交的第二阶段,协调器向参与者发送提交请求后,在发送提交请求的过程中发生本地网络异常或协调器失败,导致只有部分参与者收到提交请求.这些参与者收到提交请求后,将执行提交操作。但是,其他没有收到提交请求的机器是不能进行事务提交的。从而导致整个分布式系统存在数据一致性的现象。4、第二阶段无法解决的问题:coordinator发送commit消息后宕机,唯一收到消息的参与者也同时宕机。那么即使协调者通过选举协议产生了新的协调者,这个事务的状态也是不确定的,没有人知道这个事务是否已经提交。由于两阶段提交存在同步阻塞、单点问题、脑裂等缺陷,因此在两阶段提交的基础上进行了改进,提出了三阶段提交。PC三阶段提交(Three-phasecommit),也称为三阶段提交协议(Three-phasecommitprotocol),是两阶段提交(2PC)的改进版本。与两阶段提交不同,三阶段提交有两个变化点。1.引入超时机制。同时在协调者和参与者中都引入了超时机制。2.在第一阶段和第二阶段之间插入一个准备阶段。保证每个参与节点的状态在最终提交阶段之前是一致的。也就是说,3PC除了引入超时机制外,将2PC的准备阶段再次一分为二,这样三阶段提交就有了三个阶段:CanCommit、PreCommit、DoCommit。CanCommit阶段3PC的CanCommit阶段其实和2PC的准备阶段非常相似。协调者向参与者发送提交请求,参与者如果可以提交则返回Yes响应,否则返回No响应。1.交易查询协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。2、响应反馈参与者收到CanCommit请求后,一般情况下,如果认为交易可以顺利执行,就会返回Yes响应,进入就绪状态。否则,反馈NoPreCommit阶段协调器根据参与者的响应决定是否记住事务的PreCommit操作。根据响应,有两种可能性。如果协调者得到所有参与者的Yes响应,则将执行事务的预执行。1.发送Precommit请求Coordinator向参与者发送PreCommit请求,进入Prepared阶段。2.事务预提交参与者收到PreCommit请求后,将执行事务操作,并在事务日志中记录undo和redo信息。3.响应反馈如果参与者成功执行交易操作,将返回ACK响应并开始等待最终命令。如果任何参与者向协调器发送No响应,或者等待超时后,协调器没有收到参与者的响应,则事务中断。1.发送中止请求协调器向所有参与者发送中止请求。2.中断事务参与者收到协调器的中止请求后(或超时后,尚未收到协调器的请求),中断事务。doCommit阶段,在这个阶段进行真正的事务提交,也可以分为以下两种情况。执行提交1.发送提交请求Coordination收到参与者发送的ACK响应,则他将从预提交状态进入提交状态。并向所有参与者发送doCommit请求。2.交易提交参与者收到doCommit请求后,执行正式的交易提交。并在完成事务提交后释放所有事务资源。3.响应反馈事务提交后,向协调器发送Ack响应。4.完成交易协调器收到所有参与者的ack响应后,交易完成。中断事务如果协调器没有收到参与者发送的ACK响应(可能是接收方没有发送ACK响应,或者响应超时),那么就会执行中断事务。在doCommit阶段,如果参与者没有及时收到协调者的doCommit或rebort请求,则等待超时后继续提交事务。(其实这个应该是根据概率来判断的,当进入到第三阶段,就意味着参与者已经收到了第二阶段的PreCommit请求,所以协调者产生PreCommit请求的前提是他收到了PreCommit在第二阶段开始前请求,CanCommit对所有参与者的响应都是Yes。(一旦参与者收到PreCommit,就意味着他知道大家实际上已经同意修改了。)所以,一句话,当进入第三阶段时,由于网络超时等原因,虽然参与者没有收到commit或abort响应,但他有理由相信提交成功的概率很高。)