分布式事务

分布式事务

     分布式事务用于在分布式系统中保证不同节点之间的数据一致性。分布式事务的实现有很多种,最具有代表性的是由Oracle Tuxedo系统提出的XA分布式事务协议。

     一、XA事务

     1、什么事XA?

     XA是由X/Open组织提出的分布式事务的规范。 XA规范主要定义了(全局)事务管理器(TM)和(局 部)资源管理器(RM)之间的接口。主流的关系型数据库产品都是实现了XA接口的。

     2、XA事务的组成

     XA事务由一个或多个资源管理器、一个事务管理器以及一个应用程序组成。

     资源管理器(Resource Managers):提供访问事务资源的方法。通常一个数据库就是一个资源管理器。

     事务管理器(Transaction Manager):协调参与全局事务中的各个事务。需要和参与全局事务的所有资源管理器进行通信。

     应用程序(Application Program):定义事务的边界,指定全局事务中的操作。

     XA协议包含两阶段提交(2PC)和三阶段提交(3PC)两种实现,后面重点介绍两阶段提交的具体过程。

     二、两阶段提交(two-phase commit)

     1、两阶段提交的实现过程

     第一阶段为准备(prepare)阶段。

     所有参与全局事务的节点都开始准备(PREPARE)并锁住需要的资源,告诉事务管理器它们准备好提交了。

     2、第二阶段为提交阶段(commit)。

     事务管理器告诉资源管理器执行ROLLBACK还是COMMIT。如果任何一个节点显示不能提交,则所有的节点都被告知需要回滚。可见与本地事务不同的是,分布式事务需要多一次的PREPARE操作,待收到所有节点的同意信息后,再进行COMMIT或者ROLLBACK操作。

     3、XA两阶段提交成功情况的处理流程

     第一阶段(prepare phase):

     

     1)作为事务协调者的节点会首先向所有的参与者节点发送Prepare请求。

     2)在接到Prepare请求之后,每一个参与者节点会各自执行与事务有关的数据更新,写入Undo Log和Redo Log。如果参与者执行成功,暂时不提交事务,而是向事务协调节点返回“完成”消息。

     3)当事务协调者接收到了所有参与者的返回消息,整个分布式事务将会进入第二阶段。

     第二阶段(commit phase):

     

     如果事务协调节点在之前所收到都是正向返回,那么它将会向所有事务参与者发出Commit请求。接到Commit请求之后,事务参与者节点会各自进行本地的事务提交,并释放锁资源。当本地事务完成提交后,将会向事务协调者返回“完成”消息。

     当事务协调者接收到所有事务参与者的“完成”反馈,整个分布式事务完成。

     4、XA两阶段提交失败情况的处理流程 

     第一阶段

     

     如果某个事务参与者反馈失败消息,说明该节点的本地事务执行不成功,必须回滚。

     第二阶段

      

      事务协调节点向所有的事务参与者发送Abort请求。接收到Abort请求之后,各个事务参与者节点需要在本地进行事务的回滚操作,回滚操作依照Undo Log来进行。

      5、XA两阶段提交的不足

      1) 性能问题

       XA协议遵循强一致性。在事务执行过程中,各个节点占用着数据库资源,只有当所有节点准备完毕,事务协调者才会通知提交,参与者提交后释放资源。这样的过程有着非常明显的性能问题。

      2)协调者单点故障问题

      事务协调者是整个XA模型的核心,一旦事务协调者节点挂掉,参与者收不到提交或是回滚通知,参与者会一直处于中间状态无法完成事务。

      3)丢失消息导致的不一致问题。

      在XA协议的第二个阶段,如果发生局部网络问题,一部分事务参与者收到了提交消息,另一部分事务参与者没收到提交消息,那么就导致了节点之间数据的不一致。   

      总的来说,XA性能局限性在于效率低下,准备阶段的成本持久,全局事务状态的成本持久,性能与本地事务相差10倍左右;提交前,出现故障难以恢复和隔离问题。

      三、其它分布式事务方案

      如何避免XA两阶段提交的种种问题呢?实际上有许多其他的分布式事务方案可供选择:

      1、三阶段提交(three-phase commit)

      在两阶段提交中,第一个阶段是询问所有参与者是否可以提交事务。在 XA 三阶段提交中,这一阶段被拆分成 CanCommit 阶段和 PreCommit 阶段。

      1)CanCommit 阶段

      协调者向所有参与者发送 CanCommit 消息,询问它们是否可以提交事务。参与者在收到 CanCommit 消息后,会执行一些检查,确保自己的事务可以提交。如果检查通过,参与者会回复 "Yes",表示可以提交;否则,回复 "No",表示不能提交。 

  • 如果在 CanCommit 阶段协调者没有在规定的时间内收到所有参与者的反馈,协调者会启动超时处理。
  • 协调者可以根据具体的实现,在超时后执行不同的动作,例如中断事务、选择性地中断一部分事务等。

      2)PreCommit 阶段 

      如果 CanCommit 阶段的所有参与者都回复 "Yes",那么协调者向所有参与者发送 PreCommit 消息,告诉它们准备好提交事务。参与者在收到 PreCommit 消息后,会在本地执行事务的预提交操作,但不会真正提交。预提交操作可能包括写日志、锁定资源等。 

  • 如果在 PreCommit 阶段发生了超时,协调者可能会认为参与者无法正常提交事务,因此协调者会发送中断事务的请求。
  • 参与者在收到中断请求后,需要进行相应的回滚操作。

      3)DoCommit 阶段和DoAbort 阶段

     如果在 PreCommit 阶段没有发生错误,协调者向所有参与者发送 DoCommit 消息,表示可以最终提交事务。
     如果在 CanCommit 或 PreCommit 阶段的任何时候有参与者回复 "No",或者在规定时间内没有收到某个参与者的回复,协调者会发送 DoAbort 消息,表示事务中止。
     参与者在收到 DoCommit 或 DoAbort 消息后,根据消息执行最终的提交或回滚操作。

     分析:XA三阶段提交在两阶段提交的基础上增加了CanCommit阶段,并且引入了超时机制。一旦事务参与者迟迟没有接到协调者的commit请求,会自动进行本地commit。这样有效解决了协调者单点故障的问题。但是性能问题和不一致的问题仍然没有根本解决。

      2、MQ事务

      本地消息表/可靠消息最终一致性。利用消息中间件来异步完成事务的后一半更新,实现系统的最终一致性。这个方式避免了像XA协议那样的性能问题。

      举个栗子:

      跨行转账可通过本地消息表来实现

      用户 A 向用户 B 发起转账,首先系统会扣掉用户 A 账户中的金额,将该转账消息写入消息表中,如果事务执行失败则转账失败,如果转账成功,系统中会有定时轮询消息表,往 mq 中写入转账消息,失败重试。mq 消息会被实时消费并往用户 B 中账户增加转账金额,执行失败会不断重试。

      

       商城用户订单数据状态变更,会将变更状态记录消息表中,脚本将订单状态消息写入 mq,最终消费 mq 给用户发送邮件、短信、push 等。

      3、TCC事务

      TCC事务是Try、Commit、Cancel三种指令的缩写,其逻辑模式类似于XA两阶段提交,但是实现方式是在代码层面来人为实现。

 

      参考链接:

      https://xiaomi-info.github.io/2020/01/02/distributed-transaction/

      https://blog.csdn.net/bjweimengshu/article/details/79607522

posted @ 2021-09-12 23:00  欢乐豆123  阅读(96)  评论(0编辑  收藏  举报