一、前言
前面我们介绍了为解决分布式事务而提出来的的二阶段协议,本文首先来讲解二阶段的不足,然后阐述三阶段协议,三阶段协议也是一个标准的协议,也并没有说具体如何实现。
二、二阶段协议存在的问题
主要是同步阻塞问题,在二阶段的第一阶段所有参与者接受到事务协调器的事务准备请求后,会在本地开启并执行事务,但是没有提交事务。所有参与者等待第二阶段事务协调器发出事务提交或者回滚后才会提交或者回滚事务。而在这期间所有参与者开启的本地事务一直存在,也就是一直把相应的资源锁定了(比如本地事务要更新一行数据,则在开启事务后,事务提交或者回滚之前都一直通过行锁锁定了这行数据),导致其他需要访问这行数据的事务阻塞等待。
假如在第一阶段事务协调器给10个参与者发送准备请求,其中9个参与者正确接受了,并开启了本地事务锁定了具体的资源,而剩下一个参与者或者由于网络问题没有收到准备请求,或者接受到了但是本事事务执行失败,或者执行正常,但是给事务协调器的回执由于网络原因没有被协调器收到等,则事务协调器发现其中一个参与者返回准备失败或者等待超时后还没收到那一个参与者的回执则会通知所有的参与者执行回滚操作。也就是在具体回滚前,其他9个参与者白白的锁定了本地资源,成功的阻止了在开启事务和回滚之前其他事务访问锁定的资源,这显然很浪费。
三、三阶段协议
三阶段协议把二阶段的第一阶段在细分为2阶段,具体内容如下:
- 第一阶段canCommit
事务发起方发起事务后,事务协调器会给所有的事务参与者发起canCommit?的请求,参与者收到后根据自己的情况判断是否可以执行提交,如果可以则回执OK,否者返回fail,并不开启本地事务并执行。具体参与者是如何判断本地是否可以执行提交协议并没有具体规定,需要协议实现者自己规定,比如可能判断参与者是否存在(网络是否OK)或者本地数据库连接是否可用来判断(YY)。
如果协调器发现有些发起方返回fail或者等待超时后参与者还没返回则给所有事务参与者发起中断操作,具体中断操作做什么协议也没有具体规定。如果协调器发现所有参与者返回可以提交,则进入第二阶段。 - 第二阶段preCommit
事务协调器向所有参与者发起准备事务请求,参与者接受到后,开启本地事务并执行,但是不提交。剩下的与二阶段的一阶段一致。 - 第三阶段doCommit
与二阶段中的二阶段一致。
四、总结
三阶段与二阶段最大不同在于三阶段协议把二阶段的第一阶段拆分为了两个阶段,其中第一阶段并不锁定资源,而是询问参与者是否可以提交,等所有参与者回复OK后在具体执行第二阶段锁定资源。理论上如果第一阶段返回都OK,则第二阶段和三阶段执行成功的概率就很大,另外如果第一阶段有些参与者返回了fail,由于这时候其他参与者还没有锁定资源,所以不会造成资源的阻塞。
最后
想了解JDK NIO和更多Netty基础的可以单击我
想了解更多关于粘包半包问题单击我
更多关于分布式系统中服务降级策略的知识可以单击 单击我
想系统学dubbo的单击我
想学并发的童鞋可以 单击我
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/66209.html