分布式系统漫谈【玖】_分布式事务一致性:协议支持

 

上篇文章:分布式系统漫谈【捌】_分布式事务一致性:理论基础

 

上文介绍了关于分布式事务的理论基础,下面我们总结下几个分布式事务一致性协议。

 

 

两阶段提交协议


两阶段提交协议(2PC)把分布式事务分为两个阶段,一个是准备阶段,另一个是提交阶段。准备阶段和提交阶段都是由事务管理器发起的。事务管理器是两阶段提交引入的一个第三方角色,它本身不参加事务的提交,只是作为一个协调者存在于事务处理流程中。两阶段提交的流程可总结如下:

 

准备阶段:协调者向参与者发起指令,参与者评估自己的状态,如果参与者一评估指令可以完成,则会写redo或者undo日志(Write-Ahead Log的一种,然后锁定资源,执行操作,但是并不提交。

 

提交阶段:如果每个参与者明确返回准备成功,也就是预留资源和执行操作成功,则协调者向参与者发起提交指令,参与者提交资源变更的事务,释放锁定的资源:如果了任何一个参与者明确返回准备失败,也就是预留资源或者执行操作失败,则协调者向参与者发起中止指令,参与者取消已经变更的事务,执行undo日志,释放锁定的资源。


 

两阶段提交存在的问题


阻塞:对于任何一次指令都必须收到明确的响应,才会继续进行下一步,否则处于阻塞状态,占用的资源被一直锁定,不会被释放。

 

单点故障:如果协调者宕机,参与者没有协调者指挥,则会一直阻塞,尽管可以通过选举新的协调者件代原有协调者,但是如果协调者在发送一个提交指令后宕机,而提交指令仅仅被一个参与者接收,并且参与者接收后也宕机,则新上任的协调者无法处理这种情祝。

 

脑裂:协调者发送提交指令,有的参与者接收到并执行了事务,有的参与者没有接收到事务就没有执行事务,多个参与者之间是不一致的。

 

为了解决这些问题,后面又提出了三阶段提交协议。

 

三阶段提交协议

 

三阶段提交协议是两阶段提交协议的改进版本。它通过超时机制解决了阻塞的问题,并且把两个阶段增加为以下三个阶段。

 

询问阶段:协调者询问参与者是否可以完成指令,协调者只需要回答是或不是,而不需要做真正的操作,这个阶段超时会导致中止。

 

准备阶段:如果在询问阶段所有参与者都返回可以执行操作,则协调者向参与者发送预执行请求,然后参与者写redo和undo日志,执行操作但是不提交操作;如果在询问阶段任意参与者返回不能执行操作的结果,则协调者向参与者发送终止请求,这里的逻辑与两阶段提交协议的准备阶段是相似的。

 

提交阶段:如果每个参与者在准备阶段返回准备成功,也就是说预留资源和执行操作成功,则协调者向参与者发起提交指令,参与者提交资源变更的事务,释放锁定的资源;如果任何参与者返回准备失败,也就是说预留资源或者执行操作失败,则协调者向参与者发起中止指令,参与者取消已经变更的事务,执行Undo日志,释放锁定的资源,这里的逻辑与两阶段提交协议的提交阶段一致。

 

两阶段提交和三阶段提交的区别


1.增加了1个询问阶段,询问阶段可以确保尽可能早地发现无法执行操作而需要中止的行为,但是它并不能发现所有这种行为,只会减少这种情况的发生;

 

2.在准备阶段以后,协调者和参与者执行的任务中都增加了超时,一以超时,则协调者和参与者都会继续提交事务,默认为成功,这也是根据概率统计超时后默认为成功的正确性最大。
 

 

两阶段及三阶段方案中都包含多个参与者、多个阶段实现一个事务,实现复杂,性能也是个很大的问题,因此,在互联网的高并发系统中,鲜有使用两阶段提交和三阶段提交协议的场景。相比前两者而言,有一个更轻量级的实现一致性的协议,就是Paxos协议。

 

Paxos协议

 

Paxos协议的使用有一个前提,就是不存在拜占庭将军问题。拜占庭位于土耳其的伊斯坦布尔,是东罗马帝国的首都。当年拜占庭帝国军队外出征战时,必须军队内所有将军和副官达成共识,才可以决定是否出站。但是因为军队中可能有叛徒和敌军的简单存在,因此他们决定出的结果可能并不能代表大多数人的意见。因此如何排除叛徒的影响而达成一致的协议,这就是拜占庭将军问题。

 

Paxos协议中包含三种角色,分别为Proposers、Acceptors和Learners。其中Proposers是提出议案者;Acceptors是收到议案后进行判断的角色;Learners是对通过的议案进行观察的角色。

 

议案(Proposal)是由一个编号和决议(Value)对组成。决议只有在被Proposers提出后才能被批准,一个Acceptor只能批准(Chosen)一个决议(Value),Learners只能获得被批准(Chosen)的决议(Value)。

 

Paxos协议完整的投票流程描述如下:

 

1>议员p生成一个比LastTried[p]【p发起的最大表决编号】还大的表决编号b,设置LastTried[p]的值为b,然后将NextBallot(b)【下一个表决编号】消息发送给一些议员;

 

2>议员q收到这个b大于NextBallot[q]【q的下一个表决编号】的NextBallot[b]消息后,议员q将NextBallot[q]设置为b,然后发送一个lastVote(b,v)【最新的议案】给p,其中v等于PreviousVote[q]【q投票过的所有表决中编号最大的投票】;

 

3>在某个多数集合Q中的每个成员都收到一个lastVote(b,v)消息后,议员p发起一个编号为b、法定人数集为Q、议案为d的新表决。给Q中的每个议员发送一个beginBallot(b,d)消息;

 

4>在收到一个b=NextBallot[q]的BeginBallot(b,d)消息后,议员q在编号为b的表决中投票,设置PreviousVote[q]【q投票过的所有表决中编号最大的投票】为这一票,然后向p发送Voted(b,q);

 

5>p收到Q中每个q的Voted(b,q)消息后,将d记录到本地,然后发哦少年宫一条Success(d)消息给每个q;

 

6>每个q收到Success(d)消息后,将决议d记录到本地;

 

流程图如下:

 

 

整个流程是实现还是比较复杂的,这里需要好好理解。了解整个流程后会发现一个问题:如果系统中同时有人提议案的话,可能会出现碰撞失败,然后双方都需要增加议案的编号再提交,而在此提交仍可能存在编号冲突,因此双方再增加编号提交...这就产生了活锁。

 

解决办法可以是在集群中设置一个leader,每次议案都由这个leader来提交。同时也要保证leader失效后可能进行leader选举。ZooKeeper的ZAB协议就是以此设计的,这个有机会我们后面再详说。

 

TCC协议

 

阿里提出了TCC协议,TCC协议将一个任务拆分成Try, Confirm, Cancel三个步骤,正常的流程会先执行Try,如果执行没有问题,则再执行Confirm,如果执行过程中出了问题,则执行操作的逆操作Cancel。从正常的流程上讲,这仍然是一个两阶段提交协议,但是在执行出现问题时有一定的自我修复能力,如果任何参与者一出现了问题,则协调者通过执行操作的逆操作来Cancel之前的操作,达到最终的一致状态。

可以看出,从时序上来说,如果遇到极端情况,则TCC会有很多问题,例如,如果在取消时一些参与者收到指令,而另一些参与者没有收到指令,则整个系统仍然是不一致的。对于这种复杂的情况,系统首先会通过补偿的方式尝试自动修复,如果系统无法修复,则必须人工参与解决。

从TCC的逻辑上看,可以说TCC是简化版的三阶段提交协议,解决了两阶段提交协议的阻塞问题,但是没有解决极端情况下会出现不一致脑裂的问题。然而,TCC通过自动化补偿手段,将需要人工处理的不一致情况降到最少,也是种非常有用的解决方案。阿里内部的一些中间件上实现了TCC模式。
 

 

本篇文章中介绍了分布式一致性的一些协议,那么针对生产环境的具体场景我们应该如何使用呢?下文见分晓。

 

 

分布式系统漫谈【壹】_发展历程

分布式系统漫谈【贰】_分布式系统带来的问题

分布式系统漫谈【叁】_负载层技术:Nginx

分布式系统漫谈【肆】_负载层技术:CDN

分布式系统漫谈【伍】_远程调用

分布式系统漫谈【陆】_SOA和微服务

分布式系统漫谈【柒】_微服务的挑战和解决方案

分布式系统漫谈【捌】_分布式事务一致性:理论基础

分布式系统漫谈【玖】_分布式事务一致性:协议支持

分布式系统漫谈【拾】_分布式事务一致性:阿里方案

分布式系统漫谈【拾壹】_分布式事务一致性:秒杀实现

分布式系统漫谈【拾贰】_分库分表带来的问题和解决方案

分布式系统漫谈【拾叁】_缓存带来的问题和解决方案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值