Paxos 和 Raft 是目前分布式系统领域中两种非常著名的解决一致性问题的共识算法,两者都能解决分布式系统中的一致性问题,但是Paxos的实现与证明非常难以理解,Raft的实现比较简洁并且遵循人的直觉,它的出现就是为了解决 Paxos 难以理解并和难以实现的问题。
Paxos算法
Paxos算法是分布式技术大师Lamport提出的,主要目的是通过这个算法,让参与分布式处理的每个参与者逐步达成一致意见。用好理解的方式来说,就是在一个选举过程中,让不同的选民最终做出一致的决定。
Lamport为了讲述这个算法,假想了一个叫做Paxos的希腊城邦进行选举的情景,这个算法也是因此而得名。在他的假想中,这个城邦要采用民主提议和投票的方式选出一个最终的决议,但由于城邦的居民没有人愿意把全部时间和精力放在这种事情上,所以他们只能不定时的来参加提议,不定时来了解提议、投票进展,不定时的表达自己的投票意见。Paxos算法的目标就是让他们按照少数服从多数的方式,最终达成一致意见。
Paxos算法中的几个基本概念:
Proposer : 提案者,接收client数据,推动协议,协调accpetor接受这个数据
Accpetor : 接受者,即参与投票的人
Learner : 学习最终被选定的值
Proposal:提案,提案由提案号和提案值组成
核心角色:Proposer
Acceptor
Basic Paxos
基础Paxos的解决问题的范围是,在一个分布式环境中,挑选出唯一一个来自各个分布式服务器议题的值,这个被选中的值我们称之为Chosen
,所有系统一次性只能挑选一个唯一值,不会挑选第二个值,也不会改变他的选择,这个过程我们为执行了一次Paxos。
Paxos-Basic 算法分为两个阶段:
第一阶段:Prepare & Promise
主要作用是提交递增的提案号,进行提前申请,确认是否有提交提案的资格。
值得关注的是Promise过程:
- Promise顾名思义承诺,即承诺不再接受更小提案的Prepare
- Promis返回值会带上已经被accepted的最大ProposalId的数据
第二阶段:Accept & Accepted
上一阶段如果拿到大多数投票人的确认,则发起提案的正式申请,即带上提案号和提案值。如果过程中,acceptor有过accept其他值,会将本提案中的值更新为accept过的值。
如果Proposer拿到了大多数人的返回,则会讲改提案通过(Chosen),并同步给Leaner。
为了更直观描述算法细节,画图演示:
示例演示一:以下为一个Proposal无冲突情况下的提交过程
avatar示例演示二:Proposal accepted阶段冲突时的提交过程
1)当提交者Proposer1经过第一阶段Prepare&Promise后,因为分布式环境不稳定的问题,目前对acceptor1提交了accept申请并得到了回复,其他的accept申请还在进行中
avatar2)此时Proposer2开始申请另外一个提案 v2,并得到了acceptor1、acceptor2、acceptor3的promise回复
avatar3)此后Porposer1的accept1再次申请到达accetor2、acceptor3时,acceptor2、acceptor3已经有了更大p2提案号申请,所以p1的申请就会被拒绝,Proposer1的提案(p1,v1)就提交失败了。
此时再说Proposer2,接受到acceptor1,acceptor2,acceptor3的promise后,Proposer2发现acceptor1之前accept了一个(p1,v1)的提案,所以且这是目前最大被acceptor们accept的最大的提案,所以Proposer2就会把自己(p2,v2)中的值替换,提案修改为(p2,v1),最终将v1值通过。
avatar总结:Proposer为什么要把V2替换成V1?主要原因是分布式场景中冲突的情况经常发生,同时存在的提案越多,冲突的情况概率越大,主要目标是快速地将一个提案(值)快速的通过。
示例演示三:Proposal相互冲突的情况
当accept和promise相互交替出现时,会导致整个过程形成一种活锁(LiveLock)。
这种一般活锁可以通过 随机睡眠-重试 的方法解决。
avatarMulti-Paxos
在介绍Multi-Paxos之前,先总结下Basic-Paxos
- 算法有比较严格的Progress,很容易产生冲突需发起新一轮Paxos,严重情况下会产生活锁
- Basic Paxos算法中存在2轮PRC交互(
Prepare
、Accept
),交互繁琐
Multi-Paxos解决方案主要是针对真实场景去优化Basic-Paxos的过程,更像是一个工程。
1)Multi-Paxos提出Leader的概念,同一网络中只存在一个Leader,Proposal只能有Leader进行提议
选举领导者的方法有很多种,Leslie Lamport建议的一种简单方式:
- 通过服务器各自的ID大小判断,ID最大的服务器作为领导者
- 通过心跳检测的方法来向其他服务器发送ID号
大多数系统中往往会有自己的实现方式,实现各异。
2)Multi-Paxos去除了Prepare&Promise的阶段,减少PRC交互。
Multi-Paxos可以通过单个Leader掌握Proposer的权利,来降低冲突,Leader稳定的前提下只需要直接进行Accept阶段,完成信息投票。
Raft算法
Raft是一种用来管理日志复制的一致性算法,本质是Multi-Paxos算法的另一种实现,Raft算法更容易理解,且更容易于工程的构建实现。以下介绍Raft算法核心的两个部分:领导选取(leader selection)、日志复制(log replication)。
Raft节点的三种状态:Follower
、Candidate
、Leader
每一个节点都有一个倒计时器Election Timeout
,时间随机在150ms-300ms之间。
选主 Leader Election
Raft使用心跳触发Leader选举。Leader需要向所有Followers周期性发送heartbeat。如果Follower在选举超时时间内没有收到Leader的heartbeat,就会等待一段随机的时间后发起一次Leader选举。
Raft算法将时间分为一个个的任期(term),每一个term的开始都是Leader选举。在成功选举Leader之后,Leader会在整个term内管理整个集群。如果Leader选举失败,该term就会因为没有Leader而结束。
img以下演示,Raft集群选主的过程:
示例演示一:理想情况下的选主
1)所有的节点初始化为Follower
2)当某个Follower
节点的倒计时机器完成,就会转变身份为Candidate
,并向其他节点发送投票请求
3)如果大多数Follower
返回的同意,则Candidate
升级为Leader
,并向所有的节点发送heartbeat
演示示例二:Leader出现故障,宕机后
1)原Leader
节点发生故障宕机,其他Follower
无法接受到Heartbeat,则当倒计时器timeout时间到达时,会重新将自身节点升级为Candidate
,重新触发Leader选举过程
2)如果后续原Leader
节点恢复后,发现已经有新的Leader
出现,会自动降为Follower
。Raft会记录Leader
是第几轮选举出来的结果,冲突是拥护最新生成的Leader
为唯一Leader
。
演示示例三:多个Candidate选举冲突
1)存在两个Candidate同时发出Vote Request
2)同一轮选举过程中,Follower只能投票一个Candidate,后面的请求将会被拒绝
3)两个Candidate都会受到超过半数的返回,则取消本轮选举,并重置timeout时间
4)当timeout时间到达时,则发起新的一轮Vote Request
5)最终选举出Leader
img日志复制 Log Replication
Raft 在实际应用场景中的一致性更多的是体现在不同节点之间的数据一致性,客户端发送请求到任何一个节点都能收到一致的返回,当一个节点出故障后,其他节点仍然能以已有的数据正常进行。在选主之后的复制日志就是为了达到这个目的。
演示示例一:正常情况下
1)Leader
接收客户端请求 tmp,保存本地状态为Uncommited
2)Leader
同步给Follower
,Follower
也保存本地,状态为Uncommited
3)Leader
接受到大多数的Follower
返回,Leader
将本地tmp状态改为Committed
,并返回给客户端
4)Leader
再将数据状态同步给Follower
,Follower
接收到后也将本地的状态改为Committed
演示示例二:网络脑裂情况
脑裂(Network Partition,指部分节点之间没办法互相通信)情况下,Raft 如何保证在这种情况下数据的一致性。
1)5个机器的集群发生脑裂情况,分别划分为2台和3台
2)3台机器重新选出一个Leader,此刻原整个集群中有两个leader,分别为Leader1、Leader2
3)Leader1已无法提供服务,因为集群内机器已少于一般,及时有数据写入,日志也不能完成Commit
4)Leader2因占大多数机器,服务仍然可用,日志也可以被commit
5)当脑裂恢复后,再将原Leader的日志重新复制给被脑后出去的机器,完成最终同步
img总结
本文涉及到均是一些理论性的知识点,分布式环境下的一致性解决方案绝非如此简单就能轻松描述清楚,即使是Raft也需要有很多细节去深挖了解。若要真正了解分布式环境的共识问题,需要落地下来好好思考下异步的复杂性和同步的性能之间的问题。
参考:
SOF: Question about Paxos implementation
网友评论