分布式选举协议:Paxos

一 CAP 理论

对于一个分布式系统,不能同时满足以下三点:

一致性,可用性和分区容错性

一致性:指的是分布式中数据需要保持一致。

一致性是指数据在多个副本之间是否能够保持一致的特性。当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处于一致的状态

可用性:指的是分布式系统中,可以对外提供服务

可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果

分区容错性:即分布式系统在遇到任何网络分区或者分裂故障的时候,仍然需要能够保证对外提供满足一致性和可用性的服务

当前的网络因为区域分成2个部分,比如有5台服务器,2台在中国,3台在美国,但是中美海底电缆线断了,导致中国和美国联系不上。

一般不能同时满足:

如果发生分区,我们只能保证可用性和一致性中的一种,如果要确保数据一致性,我们必须停止服务,即牺牲可用性,即可用性不能满足;如果我们要希望继续对外提供服务,即满足可用性,但是另一部分分区的数据的一致性满足不了,所以就会牺牲一致性。

二 一致性模型

2.1 弱一致性

所谓的弱一致性,即最终一致性。DNS协议,Gossip协议就是弱一致性协议

2.2 强一致性

2.3.1 主从同步

# 主负责写数据

# 主负责将日志复制到从

# 主等待,直到所有的从返回

如果一个节点失败,Master阻塞,导致整个集群不可用,保证了一致性,但是可用性降低了。

2.3.2 多数派

基本思想:每一次都保证写入大于N/2各节点,每一次保证可以从大N/2个节点中读取。

三 Paxos算法

3.1 Paxos算法简介

Paxos算法是一个具有容错特性的一致性算法,主要的目的是解决分布式系统中,如何就某一个值(决议)达成一致的问题。

它主要涉及到以下几个角色:

# Proposer: 提议发起者。接受客户端请求,向Acceptor提出提议。允许有多个Proposer。

# Acceptor: 提议接收者。接收来自Proposer的提议,一般只有超半数的Acceptor接收就认为被接受。允许有多个Acceptor

# Learner: 提议学习者

一般在分布式系统中,每一个节点实例是一个Proposer,也是一个Acceptor,也是Learner.

另外还有一些名词:

Proposal Number: 提议的版本号,有的也叫作epoch. 代表每一轮提议的版本。

Proposal Value: 提议的值,或者说需要提交的值或者更新的值等等,即提议内容。

3.2 Basic Paxos

3.2.1 Proposer的处理

Proposer阶段一: 向Acceptor发出prepare请求

Proposer选择一个提案编号为epoch,向Acceptor集群中的成员发送请求

Proposer阶段二:根据Acceptor响应结果进行处理

#1: Proposer选定epoch,向Acceptor集群获取epoch的访问权和对应的提案值(Proposal Value)

#2 Proposer根据Acceptor集群响应结果进行不同处理

第一:如果收到超过半数Acceptor的响应,且不存在提案值,则Proposer创建<epoch,V> 提案,向Acceptor集群提交

第二:如果收到超过半数Acceptor的响应,且存在提案值V,则认同Acceptor返回的提案值V

第三:如果没有收到半数半数以上Acceptor的响应,且存在提案值,则Proposer创建<epoch,V> 提案,向Acceptor集群提交

3.2.2 Acceptor的处理

Acceptor第一阶段: 处理Proposer的prepare请求

#1: Acceptor集群向Proposer保证不再批准任何编号小于epoch的提案

#2:如果Acceptor集群已经批准过提案,那么就向Proposer返回当前已经批准的提案的值或者内容(Proposal Value);如果还没有批准过,则返回null

Acceptor第二阶段: 验证Proposer提交的提案编号epoch(Proposer Number),并更新提案值Proposal Value

#1 验证提交的提案编号是否等于现在最大的(或者最新的)提案编号epoch

#2 如果是,则设置提案值V,即<accepted_epoch,accepted_value>

3.2.3 Learner的处理

只要超半数的Acceptor批准了提案之后,就需要将提案发送给所有的Learner

3.2.4 Basic Paxos处理流程

常见的图示:

部分Acceptor节点失败,但是仍然满足大多数节点

3.2.5 Basic Paxos算法流程演示

Proposer1以prepare_epoch=1,向Acceptor集群发起Prepare请求

Acceptor集群校验lastet_epoch(最新的提案编号),如果大于lastet_epoch,则重置lastest_epoch,并且向Proposer1返回accept_value(接受的提案值)

这个时候,另外一个Proposer2也开始向Acceptor集群发起Prepare请求,请求的提案编号是epoch=2(prepare_epoch=2)

Acceptor集群校验lastet_epoch(最新的提案编号),如果大于lastet_epoch,则重置lastest_epoch,并且向Proposer1返回accept_value(接受的提案值).在这里因为prepare_epoch =2 > lastet_epoch,所以重置lastet_epoch=2

Proposer1 开始向Acceptor集群发起accept请求,提交<prepare_epoch,V1>

Acceptor集群校验lastest_epoch,发现提交的epoch=1 < lastest_epoch, 因为Proposer2提交了一个编号更大的提案。所以返回错误,表示Proposer1的提案失败

Proposer2 开始向Acceptor集群发起accept请求,提交<prepare_epoch,V2>

Acceptor集群校验lastest_epoch,发现提交的epoch=2 = lastest_epoch, 所以更新accept_epoch=2, accept_value=V2.

Proposer3向以prepare_epoch=3向Acceptor集群发起prepare请求

Acceptor集群校验lastet_epoch,因为latest_epoch < prepare_epoch,所以更新Acceptor的latest_epoch=3;并且返回当前Acceptor的accept_value,即V2

Proposer3 因为获取到了半数以上的Acceptor的响应,并且获取到了Acceptor已经接受的值V2. 此时Proposer认同Acceptor返回的已经接受的值V2

3.2.6 Basic Paxos算法优化

3.2.6.1 Learner优化

我们知道,超半数Acceptor批准提案之后,就需要将提案发送给所有的Learner,这样可以尽快让Learner获取被选定的提案,但是需要每一个Acceptor和每一个Learner通信,通信次数为:批准的Acceptor个数 * Learner个数

所以我们对此进行改进,让Learner选取一个主Learner,然后让所有批准的Acceptor提案发送给主Learner, 然后由主Learner将获取的提案,发送给其他Learner,这样Acceptor和Learner之间只需要批准的Acceptor个数次通信。但是这里主Learner随时可能发生故障

所以我们可以在Learner中选择几个作为一个集合,然后让批准的Acceptor向选定的Learner集合,集合中每一个Leaner都可以在一个提案获取之后通知其他Learner。 相当于在前面两个方案做了一个折中。

3.2.6.2 Proposer优化,解决死循环(活锁),即Multi Paxos可以解决的问题

针对在Basic Paxos,如果遇到以下场景:

Proposer1 向Acceptor集群发送prepare请求,Acceptor更改了提案编号1,并且向Proposer1返回;

Proposer1 还没有发送accept请求,Proposer2向向Acceptor集群发送prepare请求,Acceptor更改提案编号2,并且向Proposer1返回;

此时Proposer1向Acceptor集群发送accept请求,因为现在Acceptor集群中的最新的提案编号是2,大于Proposer1的提案编号1,所以Proposer1的提案没有被批准。Proposer1开始重试,选定提案编号3,然后向Acceptor集群发送prepare请求,Acceptor更改了提案编号3,并且向Proposer1返回;


此时Proposer2向Acceptor集群发送accept请求,因为现在Acceptor集群中的最新的提案编号是3,大于Proposer1的提案编号2,所以Proposer2的提案没有被批准。Proposer2开始重试,选定提案编号4,然后向Acceptor集群发送prepare请求,Acceptor更改了提案编号4,并且向Proposer1返回;

所以,循环如此,就一直处于死循环状态。

为了避免活锁的问题,我们可以只让一个Proposer进行提案,和Acceptor集群进行交互。即从多个Proposer中选择一个Proposer作为Leader,然后只有Leader Proposer才能进行提案,这样就避免了活锁的问题。

3.2.8 缺点

复杂,难以实现;需要2轮RPC,效率低;存在活锁问题。

3.3 Multi Paxos

我们知道Basic Paxos,存在一些问题,诸如复杂,难以实现;需要2轮RPC,效率低;存在活锁问题。

所以,后面就有了Multi Paxos和Fast Paxos的变异版。Fast Paxos 不坐介绍,主要特点就是需要3N+1个节点,即一个宕机,还需要三个节点可用;另外一个减少了消息交互次数,以前需要三次,现在需要2次。

3.3.1 Multi Paxos未简化版本

第一: 第一次的请求流程

# Proposer不管Client是否有请求,都会向Acceptor集群发出一个prepare请求,竞选Leader,以后由这个Leader跟Acceptor提出提案;如果Leader挂掉了,再由其他Proposer来竞选新的Leader.

# Leader Proposer来确定第一次的提案编号和提案值,然后提交交给Acceptor集群

# 如果这个提案值没有确定,则设置这个值;如果已经确定了提案值,则确认这个提案值

# Acceptor集群将提案发送给Learner

第二:后续的客户端请求流程

# 后续的客户端请求到来,直接交给Leader Proposer来处理,由Leader Proposer来处理提案的提交的顺序

# 不再需要向Acceptor集群发送prepare请求,直接确定提案编号和提案值,向Acceptor集群发送accept请求,提交提案

# 如果这个提案值没有确定,则Acceptor设置这个值;如果已经确定了提案值,则确认这个提案值

# Acceptor集群将提案发送给Learner

3.3.2 Multi Paxos简化版本

简化版本将Proposer,Acceptor和Learner

第一次请求:

# 服务器端第一次接收客户端请求,服务器会向所有服务器发送prepare请求,竞选Leader;获取大多数票数以后,则表示竞选成功

# 该服务器处理客户端的第一次请求,确定提案编号和提案值,向所有服务器提交提案

# 超半数的服务器响应成功,则提交成功

# 服务器向客户端响应结果

后续请求:

# 后续客户端请求,由Leader Server来处理,服务器不用再发送prepare请求;如果Leader 宕机,则才需要发送prepare请求选举新的Leader

# Leader服务器向所有服务器发送accept请求,提交提案编号和提案值

# 服务器开始处理,然后向客户端响应

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫言静好、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值