徐书海
摘 要:所谓分布式,就是将要处理的业务进行拆分,然后将拆分的子服务部署到不同的服务器上进行处理。在分布式中,我们必须要解决服务可用性和数据一致性问题,然而根据CAP定理知道,两者是互相矛盾的,本文主要介绍分布式数据一致性的概念与解决一致性问题的协议和算法。
关键词:Paxos算法;分布式;数据一致性
1 分布式数据一致性
分布式服务就是将一个大的服务拆分成若干个子服务,我们将拆分的子服务部署到不同的服务器上运行。在分布式设计中,为了数据可扩展性,我们将数据放在不同的分布式节点上,必然遇到可用性和数据一致性的矛盾问题。举个例子,我们把某个班级作为整个分布式服务,而班里的所有学生作为各个子服务。某日,学生张三和李四因为矛盾打架了,这个消息被班里的小明知道了,于是迅速在班里传播开来。在消息传播过程中你询问班里的某个学生,如果他回答“不知道”,则说明整个班级里出现了数据不一致,(因为小明是知道的);如果某个学生直接没有回答你,(为了保持数据一致性,需要班里所有的同学都知道了才可以服务),在“写数据”过程中,无法提供服务,这就是可用性问题。在“秒杀”服务中,下订单和增积分两个服务的数据表在不同的机器上,完成下订单后必须要进行增积分,所以要保证两边的数据的一致性。
2 数据一致性协议
2.1 2PC(两阶段提交)
两阶段提交协议是一种简单的保证分布式数据一致性的协议。它的主要思想是在分布式服务中,所有的服务的数据操作要么都成功,要么都失败,也就是分布式数据操作必须具有原子性。
该协议分为两个阶段,其中涉及了两个角色,即协调者和参与者。
第一阶段,当要执行一个分布式事务时,事务发起者向协调者发送请求,然后协调者会向所有的参与者发送prepare请求(其中包含事务内容),告诉参与者要执行事务了,如果能执行发送的事务就先执行但不提交,执行完后回复协调者。然后参与者执行事务但不提交,并将 Undo 和 Redo 信息记入事务日志中,之后参与者向协调者回复消息。
第二阶段是协调者根据参与者的回复决定接下来是否进行事务的提交操作。这里可能做事务的提交操作或者做回滚操作。如果所有的参与者都返回了准备好消息,这个时候协调者向所有的参与者发送commit请求,参与者接到commit请求会将前面执行的事务进行提交操作,提交完成后给协调者发送提交成功确认消息。而不是所有的参与者都返回了准备好消息,这个时候协调者会向所有的参与者发送回滚事务的请求,参与者接收到这个请求之后将回滚前面所做的事务处理,然后向协调者发送回滚的处理情况,最后协调者向事务发起者发送事务处理失败的回复。
2.2 3PC(三阶段提交)
2PC不能跟上解决一致性问题,而且存在严重的阻塞问题。引入3PC(三阶段提交解决阻塞问题)。
第一阶段,协调者向所有的参与者发送CanCommit请求,参与者接到CanCommit请求以后查看自己是否可以执行事务,如果可以则回复yes,否则回复no。
第二阶段,如果第一阶段所有的参与者返回了yes,则协调者向所有的参与者发送PreCommit预提交请求,所有参与者接到PreCommit请求后,进行事务的执行,执行完以后不进行提交,并将Undo和Redo信息记入事务日志中,返回执行成功的信息。如果在第一阶段有参与者返回了no或者是有参与者没有返回消息,则协调者会向所有的参与者发送中断事务的请求,所有参与者收到中断请求后则进行中断事务的操作。如果在一定时间内,协调者没有发送PreCommit请求,所有的参与者也会执行中断事务的操作。
第三阶段,如果第二阶段所有的参与者返回了对PreCommit预提交请求的yes回复,那么协调者会向所有的参与者发送DoCommit请求,请求所有的参与者进行提交操作。所有参与者收到DoCommit请求之后进行提交操作,之后返回响应,协调者收到所有的参与者的提交完成消息后,事务执行完成。如果协调者收到了第二阶段PreCommit预提交请求的no回复或者有参与者没有对PreCommit预提交请求回复,则协调者会向所有的参与者发送中断事务的请求,参与者收到中断请求后则按照事务日志记录进行事务的回滚操作,并向协调者会送回滚操作情况,协调者收到参与者的回滚情况后中断事务。
3 Paxos算法
Paxos算法是一种基于消息传递的一致性算法。该算法中一共有三种角色。
3.1 第一阶段(prepare阶段)
Proposer负责提出Proposal,获取一个全局性、唯一的、递增的变量N。然后把N赋予提案,然后向所有的Acceptor发送编号为N的Prepare请求。记为Pareper(N)。
Acceptor收到一个编号为N的Prepare请求,它会将编号为N记录在本地,这样在每个Acceptor中已经被接受的请求编号中有一个最大的记为maxN。如果N小于Acceptor已经响应过的请求,则拒绝,不予回应或回复error。若N大于该Acceptor已经响应过的所有Prepare请求的最大编号(maxN),那么它就会将它已经接受过(已经经过第二阶段accept的提案)的编号最大的提案(如果还没有的accept提案的话返回{id,null,null})作为响应反馈给Proposer,同时该Acceptor承诺不再接受任何编号小于N的提案。
3.2 第二階段(accept阶段)
如果Proposer收到半数以上Acceptor对其发出的编号为N的Prepare请求的yes响应,那么它就会发送一个包含内容和编号的提案给半数以上的Acceptor。
如果Acceptor收到一个针对编号为N的提案的Accept请求,如果Acceptor收到一个针对编号为N的提案的Accept请求,只要该 Acceptor没有对编号大于N的Prepare请求做出过响应,它就接受该提案(此时执行提案内容但不提交),随后将情况返回给Proposer。如果不满足则不回应或者返回NO。如果N小于Acceptor已经响应过的prepare请求编号,则拒绝,不给回应或回复error。当proposer没有收到过半的回应,那么他会重新进入第一阶段,递增提案号,重新提出prepare请求。
上边描述的过程只有半数以上的Acceptor接受并执行了提案,还有Acceptor没有执行提案。所以这个时候需要向未批准的acceptor发送提案内容和提案编号并让它无条件执行和提交,而对于前面已经批准过该提案的acceptor来说仅仅需要发送该提案的编号,让 acceptor执行提交就行了。
4 结束语
上面的2PC、3PC操作都是在安全可靠的信道上进行传递消息来保证数据一致性的。其中3PC操作解决了消息阻塞带来的资源占用问题,而Paxos算法解决了网络中节点故障引起的数据不一致问题,从根本上解决了一致性问题。
参考文献
[1]倪超.从Paxos到ZooKeeper分布式一致性原理与实践[M].北京:电子工业出版社,2015.2.
[2]柳伟卫.分布式一致性算法开发实战大型互联网架构实战[M].北京:北京出版社,2020.5.
[3]赵辰.分布式一致性算法开发实战[M].北京:北京大学出版社,2020.5.