分布式一致性算法之Paxos原理剖析

本文涉及的产品
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
云原生网关 MSE Higress,422元/月
MSE Nacos/ZooKeeper 企业版试用,1600元额度,限量50份
简介: 清楚zk背后leader一致性选举paxos(帕克索斯)原理

概述

Zookeeper集群中,只有一个节点是leader节点,其它节点都是follower节点(实际上还有observer节点,不参与选举投票,在这里我们先忽略,下同)。所有更新操作,必须经过leader节点,leader节点和follower节点之间保持着数据同步和心跳。


客户端使用zookeeper时,可能会连到follower身份的server上,也可能会连到leader身份的server上。

三类角色分工如下:

Leader:处理写请求,单点

Follower:处理客户端请求,参与投票

Observer:不参与leader选举投票,只处理客户端请求

在一个zookeeper集群里,有多少个server是固定的,每个节点有一个唯一id,标识它自己,另外,每个server还有用于选举的IP和port,这些都在配置文件中。一个具体的例子如下:

server.1= server1的IP地址:2888:3888

server.2= server2的IP地址:2888:3888

server.2= server3的IP地址:2888:3888

这里有 3 server ,其 id 分别为 1 2 3 2888 为节点和 leader 交换信息的端口, 3888 为选举端口。这个节点的 id ,在投票时,用户标识参加竞选的节点的身份。

问题:这个leader节点是怎么确定的?

答案:zookeeper系统自己选举出来的,所有server节点(observer除外),都参与这个选举。这样做的好处是:当现在leader挂掉了之后,系统可以重新选举一个节点做leader。

Zookeeper的选举算法能保证:只要超过半数节点还活着,就一定能选举出唯一个一个节点作为leader。

选举发生时机

   当任何一个节点进入looking状态时,选举开始,进入looking状态有如下原因:

   1、节点刚启动,使自己进入选举状态

   2、发现leader节点挂掉了

   Zookeeper中的leader怎么知道follower还活着?follower怎么知道leader还活着?leader会定时向follower发ping消息;follower会定时向leader发ping消息。当发现无法ping通leader时,就会将自己的状态改为LOOKING,并发起新一轮选举。处于选举模式时,zookeeper服务不可用。

一个节点成为leader条件

    一个节点要成为leader,必须得到至少n/2+1(即半数以上节点)投票,实际上,在实现时,还可以考虑其它规则,比如节点权重。

    为什么要保证至少n/2+1的节点同意?因为这样能保证本节点得到多数派的支持。因为每一个节点,只能支持一个节点成为leader,因此,只要一个节点获得至少n/2+1选票,就一定会比其它任何节点得到的选票多。

    这个规则意味着,如果超过半数以上的节点挂掉,zookeeper是选举不出leader节点的,因此,zookeeper集群最多允许n/2节点故障。

要解决的问题

    选举算法目标是确保一定要选出一个唯一的leader节点。这有两层含义:

    1、一定要选出一个节点作为leader

    2、这个leader一定要唯一

    为此,要解决如下问题:

    1、在一次选举中,节点应该把票投给谁?

    规则:每个节点有一个唯一id,在选举中,节点总是把票投给id最大的那个节点,这样,id大的节点更有可能成为leader,天生就是做领导的料。

    2、在一次选举过程中,有些节点由于没有启动而没参加(有些人去国外了,没有赶上这次大选,当他回国后,进入looking状态,要发起选举,怎么办?),后来这个节点启动了,此时要求选举,怎么解决?

    3、运行过程中,leader节点挂掉了,怎么办?

    此时其它节点会发现leader挂了,会发起新一轮选举,最后选出新leader。

尝试解决方案

    1、直接指定一个节点做leader,例如,永远都让id最大节点当leader,这个想法最简单。问题:这个节点挂了怎么办?这会出现单点问题。

    2、每次选举中,让活着节点中,id最大节点当leader。问题:1、其它节点怎么知道活着节点中,谁id最大?

选举算法流程

    选举开始时,每个节点为自己生成一张投票,推荐自己成为leader,并把投票发送给其它节点,这相当于paxos算法中的proposer角色。接下来,节点启动一个接收线程接收其它节点发送过来的投票,并对选票进行处理,这相当于paxos中的acceptor角色。简单说,节点之间通过这种消息发送(投票),最终选举出leader。

    当收到其他它节点的选票之后,会和自己的投票比较,如果比自己的投票好(比如推荐的leader的id更大,选举轮数更新),则更新自己的选票,接下来把收到的选票放在选票列表里(该列表存储了所有节点的投票,是一个key-value结构,key为节点的id,value为该节点的投票)。并再次把自己的投票发送给其它节点。

    接下来节点会统计选票列表中每个节点获得的票数,如果有一个节点获得超过半数的选票,则认为该节点是leader。如果本节点就是,则将自身的状态置为leading,表明自己是leader;否则将自己的状态置为following,表明自己是follower。

    通过若干轮的消息交换,最终,会有一个节点获得超过一半的选票而成为leader。这种方法的精髓在于,每个节点在不需要获得所有节点的信息(投票结果)的前提下,达成一致意见,选出leader。

算法中涉及的重要变量

logicalclock

volatile long logicalclock;

     表示选举轮数,在 lookForLeader 开始的时候会加 1, ,另外,在收到其他节点的投票信息时,如果其它节点的 electionEpoch 比本值大,本值会被赋成 electionEpoch 。也就是说,每次节点启动时,该值为 0 ?这个值只在节点存活的时候有意义?即节点重启后,该值为 0

ProposedLeader

    long proposedLeader;

    该值为本节点推荐的leader的id,初始时为自己,后面会更新,这个值不会从文件中读,也就是说,重启后会自动使用本节点id。getInitId源代码如下:

    public long getId() {

       return myid;

    }

ProposedZxid

    long proposedZxid;

    本节点建议的zxid,在starter函数中,被初始化为-1;在updateProposal函数中,会更新该变量的值。

    updateProposal(getInitId(), getInitLastLoggedZxid(), getPeerEpoch());

        private long getInitLastLoggedZxid(){

        if(self.getLearnerType() == LearnerType.PARTICIPANT)

            return self.getLastLoggedZxid();

        else return Long.MIN_VALUE;

 }

 public long getLastLoggedZxid() {

     if (!zkDb.isInitialized()) {

           loadDataBase();

     }

     return zkDb.getDataTreeLastProcessedZxid();

     }

ProposedEpoch

    long proposedEpoch;

    表示本节点推荐的选举轮数,在updateProposal函数更新选票时,会更新该值。节点启动初始化时候,第一次调用updateProposal,会把proposedEpoch的值赋为getPeerEpoch,而该函数又会调用getCurrentEpoch,getCurrentEpoch的代码如下:

    public long getCurrentEpoch() throws IOException {

             if (currentEpoch == -1) {

                  currentEpoch = readLongFromFile(CURRENT_EPOCH_FILENAME);

             }

             return currentEpoch;

    }

    这表明,该值会从日志文件中读出来。也就是说,节点重启后,会使用上次活着的时候的值。

     为什么有了zxid还需要epochzxid是用来表示数据的新旧,而epoch是用来表示选举的轮数。

运行实例

    假设 zookeeper 集群中有 3 个节点,其 ID 分别为 1 2 3 。整个集群开始运行时,每个节点 zxid 都为 1
  • 节点123启动后,都进入looking状态,开始leader选举。每个节点的proposedLeader即推荐的leader都是自己;logicalclock值都为1;建议的proposedZxid值都为1;建议的proposedEpoch值都为1;投票列表为每个节点投自己的一票(1->1,2->2,3->3)。节点1首先向23发送自己的投票消息:

  • 节点2、3收到节点1的投票消息,首先查看1的状态,发现1处于looking状态。接下来,判断1发来的electionEpoch和本地逻辑时钟logicalclock的大小,发现两者相等(都为1)。接着判断leader、zxid、peerEpoch和本地proposedLeader、proposedZxid、proposedEpoch的大小,节点2发现节点1推荐的leader的id比自己小(1<2),节点3也发现节点1推荐的leader的id比自己的小(1<3),因此不用更新自己的投票。接下来,节点2、3把节点1的投票放入自己的投票列表中,这样,节点2收到的投票的列表为:

         1->1

         2->2

         节点3的为:

         1->1

         3->3

     节点2、3再判断此次投票是否可以结束,发现不能结束。如下图所示:

  • 节点2向节点13发送自己的投票信息,节点3由于发送线程的故障原因,投票信息一直没有出去:

      在2发出的投票信息中,选择的leader是它自己。

  • 节点13收到节点2的投票消息。节点1比较自己的logcalclock和节点2发来的electionEpoch的大小,二者相等,接下来比较leaderzxidpeerEpoch和本地proposedLeaderproposedZxidproposedEpoch的大小,发现节点2推荐的leaderid2)比自己的proposedLeader1)大,于是更新自己的选票,将proposedLeader改为2。然后,节点12的选票(2->2)放入自己收到的投票箱中,接着判断投票是否可以结束(调用函数termPredicate),由于节点2被超过半数的节点选择(12),因此选举可以结束,由于自己不是leader,节点1将自己的状态改为following
  • 节点3比较自己的logcalclock和节点2发来的electionEpoch的大小,二者相等,接下来比较leaderzxidpeerEpoch和本地proposedLeaderproposedZxidproposedEpoch的大小,发现节点2推荐的leaderid2)比自己的proposedLeader3)小,不用更新自己的选票。然后,节点32的选票(2->2)放入自己收到的投票箱中,接着判断投票是否可以结束(调用函数termPredicate),由于没有节点获得超过半数的选票,因此选举继续。
  • 节点1收到节点2的选票,更新选票后,再向节点13发送自己的投票信息:此时,节点1选的leader已经变为2,而且节点1的状态已经变成following
  • 节点2在收到节点1的选票信息后,判断节点1的状态,发现为following,这表明,节点1已经认为leader选出来了,并且是2。节点2首先更新自己的收票箱,将1的投票改为2,接着,判断选举是否结束,发现确实可以结束,节点2就更新自己的状态,由于发现自己是被半数以上人推荐的leader,因此把自己的状态改为leading同样,节点3在收到节点1的投票信息后,判断节点1的状态,发现为following,这表明,节点1已经认为leader选出来了,并且是2。节点3首先更新自己的收票箱,将1的投票改为2,接着,判断选举是否结束,发现确实可以结束,节点3就更新自己的状态,由于发现自己不是被半数以上人推荐的leader,因此把自己的状态改为following至此,选举结束,选出来的leader213都为follower


相关文章
|
3月前
|
消息中间件 存储 缓存
zk基础—1.一致性原理和算法
本文详细介绍了分布式系统的特点、理论及一致性算法。首先分析了分布式系统的五大特点:分布性、对等性、并发性、缺乏全局时钟和故障随时发生。接着探讨了分布式系统理论,包括CAP理论(一致性、可用性、分区容错性)和BASE理论(基本可用、软状态、最终一致性)。文中还深入讲解了两阶段提交(2PC)与三阶段提交(3PC)协议,以及Paxos算法的推导过程和核心思想,强调了其在ZooKeeper中的应用。最后简述了ZAB算法,指出其通过改编的两阶段提交协议确保节点间数据一致性,并在Leader故障时快速恢复服务。这些内容为理解分布式系统的设计与实现提供了全面的基础。
|
2月前
|
存储 负载均衡 算法
我们来说一说 Java 的一致性 Hash 算法
我是小假 期待与你的下一次相遇 ~
|
4月前
|
NoSQL 算法 安全
分布式锁—1.原理算法和使用建议
本文主要探讨了Redis分布式锁的八大问题,包括非原子操作、忘记释放锁、释放其他线程的锁、加锁失败处理、锁重入问题、锁竞争问题、锁超时失效及主从复制问题,并提供了相应的优化措施。接着分析了Redis的RedLock算法,讨论其优缺点以及分布式专家Martin对其的质疑。此外,文章对比了基于Redis和Zookeeper(zk)的分布式锁实现原理,包括获取与释放锁的具体流程。最后总结了两种分布式锁的适用场景及使用建议,指出Redis分布式锁虽有性能优势但模型不够健壮,而zk分布式锁更稳定但部署成本较高。实际应用中需根据业务需求权衡选择。
|
6月前
|
机器学习/深度学习 数据采集 算法
短视频到底如何推荐的?深度剖析视频算法推送原理详细且专业的解读-优雅草卓伊凡-【01】短视频算法推荐之数据收集
短视频到底如何推荐的?深度剖析视频算法推送原理详细且专业的解读-优雅草卓伊凡-【01】短视频算法推荐之数据收集
511 12
短视频到底如何推荐的?深度剖析视频算法推送原理详细且专业的解读-优雅草卓伊凡-【01】短视频算法推荐之数据收集
|
7月前
|
运维 NoSQL 算法
【📕分布式锁通关指南 04】redis分布式锁的细节问题以及RedLock算法原理
本文深入探讨了基于Redis实现分布式锁时遇到的细节问题及解决方案。首先,针对锁续期问题,提出了通过独立服务、获取锁进程自己续期和异步线程三种方式,并详细介绍了如何利用Lua脚本和守护线程实现自动续期。接着,解决了锁阻塞问题,引入了带超时时间的`tryLock`机制,确保在高并发场景下不会无限等待锁。最后,作为知识扩展,讲解了RedLock算法原理及其在实际业务中的局限性。文章强调,在并发量不高的场景中手写分布式锁可行,但推荐使用更成熟的Redisson框架来实现分布式锁,以保证系统的稳定性和可靠性。
304 0
【📕分布式锁通关指南 04】redis分布式锁的细节问题以及RedLock算法原理
|
8月前
|
存储 人工智能 算法
解锁分布式文件分享的 Java 一致性哈希算法密码
在数字化时代,文件分享成为信息传播与协同办公的关键环节。本文深入探讨基于Java的一致性哈希算法,该算法通过引入虚拟节点和环形哈希空间,解决了传统哈希算法在分布式存储中的“哈希雪崩”问题,确保文件分配稳定高效。文章还展示了Java实现代码,并展望了其在未来文件分享技术中的应用前景,如结合AI优化节点布局和区块链增强数据安全。
|
8月前
|
机器学习/深度学习 算法 PyTorch
深度强化学习中SAC算法:数学原理、网络架构及其PyTorch实现
软演员-评论家算法(Soft Actor-Critic, SAC)是深度强化学习领域的重要进展,基于最大熵框架优化策略,在探索与利用之间实现动态平衡。SAC通过双Q网络设计和自适应温度参数,提升了训练稳定性和样本效率。本文详细解析了SAC的数学原理、网络架构及PyTorch实现,涵盖演员网络的动作采样与对数概率计算、评论家网络的Q值估计及其损失函数,并介绍了完整的SAC智能体实现流程。SAC在连续动作空间中表现出色,具有高样本效率和稳定的训练过程,适合实际应用场景。
2085 7
深度强化学习中SAC算法:数学原理、网络架构及其PyTorch实现
|
9月前
|
算法 Java 数据库
理解CAS算法原理
CAS(Compare and Swap,比较并交换)是一种无锁算法,用于实现多线程环境下的原子操作。它通过比较内存中的值与预期值是否相同来决定是否进行更新。JDK 5引入了基于CAS的乐观锁机制,替代了传统的synchronized独占锁,提升了并发性能。然而,CAS存在ABA问题、循环时间长开销大和只能保证单个共享变量原子性等缺点。为解决这些问题,可以使用版本号机制、合并多个变量或引入pause指令优化CPU执行效率。CAS广泛应用于JDK的原子类中,如AtomicInteger.incrementAndGet(),利用底层Unsafe库实现高效的无锁自增操作。
361 0
理解CAS算法原理
|
14天前
|
机器学习/深度学习 算法 新能源
【优化调度】基于matlab粒子群算法求解水火电经济调度优化问题研究(Matlab代码实现)
【优化调度】基于matlab粒子群算法求解水火电经济调度优化问题研究(Matlab代码实现)
|
16天前
|
算法 机器人 定位技术
基于机器视觉和Dijkstra算法的平面建筑群地图路线规划matlab仿真
本程序基于机器视觉与Dijkstra算法,实现平面建筑群地图的路径规划。通过MATLAB 2022A读取地图图像,识别障碍物并进行路径搜索,支持鼠标选择起点与终点,最终显示最优路径及长度,适用于智能导航与机器人路径规划场景。

热门文章

最新文章