分布式事务

一、分布式事务

1 简介

        分布式事务用于在
分布式系统中保证不同节点之间的数据一致性,分布式事务是指不是在单个服务或单个数据库架构下,产生的事务,例如:

  • 跨数据源的分布式事务

  • 跨服务的分布式事务

  • 综合情况

2 问题引入

        在数据库水平拆分、服务垂直拆分之后,一个业务操作通常要跨多个数据库、服务才能完成。例如电商行业中比较常见的下单付款案例,包括下面几个行为:

  • 创建新订单

  • 扣减商品库存

  • 从用户账户余额扣除金额

完成上面的操作需要访问三个不同的微服务和三个不同的数据库。

        订单的创建、库存的扣减、账户扣款在每一个服务和数据库内是一个本地事务,可以保证ACID原则。

        但是当我们把三件事情看做一个"业务",要满足保证“业务”的原子性,要么所有操作全部成功,要么全部失败,不允许出现部分成功部分失败的现象,这就是分布式系统下的事务了。

        此时ACID难以满足,这是分布式事务要解决的问题。

二、 XA分布式事务协议

1. 两阶段提交(2PC)

在XA协议中包含着两个角色:事务协调者事务参与者。让我们来看一看他们之间的交互流程:

1.1 两阶段提交(2PC)成功情况下的流程

第一阶段:

在XA分布式事务的第一阶段,作为事务协调者的节点会首先向所有的参与者节点发送Prepare请求。

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

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

第二阶段:

在XA分布式事务的第二阶段,如果事务协调节点在之前所收到都是正向返回,那么它将会向所有事务参与者发出Commit请求。

接到Commit请求之后,事务参与者节点会各自进行本地的事务提交,并释放锁资源。当本地事务完成提交后,将会向事务协调者返回“完成”消息。

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

1.2 两阶段提交(2PC)失败情况下的流程

第一阶段发生异常

在XA的第一阶段,如果某个事务参与者反馈失败消息,说明该节点的本地事务执行不成功,必须回滚。
于是在第二阶段,事务协调节点向所有的事务参与者发送Abort请求而不是commit请求。接收到Abort请求之后,各个事务参与者节点需要在本地进行事务的回滚操作,回滚操作依照Undo Log来进行。流程如下:

第一阶段:

第二阶段:

1.3. XA两阶段提交的不足

XA两阶段提交究竟有哪些不足呢?

1.性能问题

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

这样的过程有着非常明显的性能问题,即事务的执行时间会比较长。

2.协调者单点故障问题

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

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

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

4.没有完善的容错机制。

太过保守 ,任意一个节点失败就会导致整个事务失败,没有完善的容错机制。

2. 三阶段提交(3PC)

XA三阶段提交在两阶段提交的基础上增加了CanCommit阶段,并且引入了超时机制。

一旦事物参与者迟迟没有接到协调者的commit请求,会自动进行本地commit。这样有效解决了协调者单点故障的问题。

三阶段提交协议是2PC的改进版本,将2PC的提交事务阶段一分为二,这样就变成了三阶段:CanCommit,PreCommit,DoCommit三个阶段。

2.1 三阶段提交流程

三阶段提交流程如下:

  • CanCommit阶段

1.事务询问: 协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。
2.响应反馈: 参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No

注意:如果区间双方任何一方发生超时,则abort.

  • PreCommit阶段(如果成功会进行资源的锁定)

协调者根据参与者的反应情况来决定是否可以进行事务的PreCommit操作。根据响应情况,有以下两种可能。

第一种:假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行

1.发送预提交请求: 协调者向参与者发送PreCommit请求,并进入Prepared阶段。
2.事务预提交 :参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。
3.响应反馈: 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令:提交(Commit)或中止(abort)。

第二种:假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。当然如果协调者没有收到预提交请求也会abort。

1.发送中断请求 协调者向所有参与者发送abort请求。

 2.中断事务 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。

  • doCommit阶段

该阶段进行真正的事务提交。也可以分为以下两种情况。

第一种:执行提交

1.发送提交请求: 协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求。
2.事务提交: 参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
3.响应反馈: 事务提交完之后,向协调者发送Ack响应。
4.完成事务: 协调者接收到所有参与者的ack响应之后,完成事务。

第二种:中断事务

协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。

利用参与者二阶段记录的undo信息来执行事务回滚,并向协调者发送ACK消息,协调者收到ACK消息后执行事务中断。

1.发送中断请求 协调者向所有参与者发送abort请求

2.事务回滚 参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。

3.反馈结果 参与者完成事务回滚之后,向协调者发送ACK消息

4.中断事务 协调者接收到参与者反馈的ACK消息之后,执行事务的中断

2.2 三阶段提交的不足

1.一致性问题未解决

一致性问题没有解决的原因:

由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间短时间内存在数据不一致的情况。

2.性能问题未完全解决

事务开启后,要等到commit区间还是占用很长的时间。但对比2PC已经有了较大的性能提升

通过以上分析发现,2PC和3PC都无法彻底解决分布式的一致性问题,接下来会分析最为行之有效的Paxos算法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值