分布式系统一致性与共识算法

        分布式系统的一致性是指从系统外部读取系统内部的数据时,在一定约束条件下相同,即数据(元数据,日志数据等等)变动在系统内部各节点应该是一致的。

        一致性模型分为如下几种:

① 强一致性   所有用户在任意时刻读到的数据,无论会请求到哪个节点上,都是一致的;

② 单调一致性  有用户在任意时刻读到的数据一定会比之前读到的数据新,也就是说,可获取的数据顺序必是单调递增的;

③ 弱一致性   相比于强一致性,弱一致性要求没那个严格,不同用户在不同时间读到的数据可能是不一致的,但过了一段时间会达到一致。

④ 最终一致性    最终一致性属于弱一致性的一种实例。用户只能读到某次更新后的值,但系统保证数据将最终达到完全一致的状态,只是所需时间不能保障。

        实际上一致性还包括顺序一致性、读写一致性、因果一致性等等,这里不做过多讨论。

        之前在分布式基础的文章里也有过讨论,对于分布式系统,主要有CAP理论和BASE理论。对于现实的网络来说,BASE理论是比较适用的,即实现最终一致性。

        再说下共识,共识是指不同的节点通过某种方法对于某种状态达成一致的过程。分布式一致性强调了多个副本呈现的数据的状态,共识强调多个节点之间对某个提案达成一致的过程。通过共识,实现某种一致性,这种一致性包括某提案的一致性,如选举,下线通知等等,也包括数据的一致性。

        共识算法目前有很多种。但根据不同的错误类型可以分为两大类算法:

        1、拜占庭问题。恶意伪造导致的错误;

        2、非拜占庭。出现故障非恶意伪造。

拜占庭问题:

我觉得一个比较简单明了的解释:

        假设有9位将军投票,其中1名叛徒。8名忠诚的将军中出现了4人投进攻,4人投撤离的情况。这时候叛徒可能故意给4名投进攻的将领送信表示投票进攻,而给4名投撤离的将领送信表示投撤离。这样一来在4名投进攻的将领看来,投票结果是5人投进攻,从而发起进攻;而在4名投撤离的将军看来则是5人投撤离。这样各支军队的一致协同就遭到了破坏。

        目前存在的算法主要包括PAXOS,RAFT,还有用于区块链的工作量证明、权益证明等等算法。PAXOS,RAFT主要用来解决不存在拜占庭问题的情况,即不存在作弊情况,基本上都是网络抖动,网络出错,系统宕机等问题,因此基本上都是用于系统内部自治,像开源的各种中间件,消息队列,Redis集群等等。而工作量证明,权益证明这些用于区块链等领域的算法就需要考虑拜占庭问题。

共识算法:

  1. Gossip算法;
  2. Raft算法;
  3. ZAB;
  4. ES选举算法;

一、Gossip算法(论文地址:Gossip论文)

        我觉得用一个简单例子来描述gossip比较合适:说一个村里儿,有一家突然有一天发生了一个事儿,女儿嫁给了一个大她20岁的老爷们儿,她邻居先听说了这个事儿,火急火燎地就把这个事儿告诉了和她打麻将的几个人儿,然后这几个人又分别告诉了好朋友,同时第一听说这件事儿的邻居还没闲下来,还再巴巴地和别人说,就这样很快,整个村儿都知道了。一个消息最后所有人都知道了。

        Gossip协议就是这样一种,没有中心节点,由最初的一个节点先随机选择几个节点通信,然后知道信息的节点同样再选择几个节点通信,就这样看似杂乱无章地相互通信,最终达到了一致性的一种算法。

        这种算法的一个优势是不管是有新节点加入,还是有节点宕机,对现有的网络和在线节点都不会有任何的影响。就算是突然有个新节点加入,也会达到最终一致性。

        目前这个算法已经非常成熟了。Redis-Cluster目前采用了这种协议。RedisCluster集群的每个节点都会有两个重要的数据结构,一个是clusterNode,记录了当前节点的状态,一个是clusterState,包含整个集群的状态等信息。clusterState的slots数组存储的是所有槽分配的地址信息,注意和clsuterNode的区别。clusterNode的slots数组记录的就是当前节点的槽分配信息。如果我们想要查某个slot在哪个节点上,直接使用clusterState的slot记录,时间复杂度是O(1)。

在RedisCluster中有几个比较重要的通信类别:

  • Meet 通过,当前集群的节点会向新节点发送握手请求,加入现有集群。
  • Ping 节点每秒会向集群中其他节点发送 ping 消息,消息中带有自己已知的两个节点的地址、槽、状态信息、最后一次通信时间等。
  • Pong 节点收到 ping 消息后会回复 pong 消息,消息中同样带有自己已知的两个节点信息。
  • Fail 节点 ping 不通某节点后,会向集群所有节点广播该节点挂掉的消息。其他节点收到消息后标记已下线。

        Gossip的特点就是随机冗余发送,最终达到了一致性。但Gossip协议本身也是存在很多的缺点,比如就是通信的冗余,因为就算一个节点收到了某个消息,那么下次仍然有可能收到的,这样就造成了资源的浪费。

        RedisCluster的机制是会每100ms发送一次 ping,这里也不是发送给集群中的所有节点,而是随机选择部分节点。一个clusterSendPing会带上当前节点以及其他部分节点的信息发送出去。

        其实上面说的clusterSendPing也不能完全保证每个节点都能收到其他节点的消息。因此集群还会每1秒都会发送随机选择5个节点,并从中选择最久没有接受pong消息的节点,发送消息。

        此外,还会遍历当前节点中存储的所有其他节点,选择一个最近接受ping消息时间已经超过了cluster_node_timeout/2的就会发送消息。

        上面是RedisCLuster使用Gossip来达到最终一致性的。除此之外在选举过程Redis采用的是Raft算法。

二、Raft算法

        Raft算法是基于之前的PAXOS算法优化的一种可行性方案,PAXOS本身比较复杂,本文也不做赘述。Raft目前是很多成熟的分布式系统都采用的算法。如Redis-cluster,Nacos,Rocketmq,以及Kafka2.8开始摘除ZK之后,也采用基于Raft的共识机制。

        Raft算法大的策略是将问题分治处理,将整个流程分为选举、日志同步、安全性、日志压缩、成员变更等等。

        该算法的前提是为系统定义了三个角色:

        1、Leader角色。整个系统只有该角色负责处理客户端的请求,并把日志同步给Follower(也是一个角色);

        2、Follower角色。一个系统会有多个Follower,他们会接收Leader的日志,并在Leader通知提交日志的时侯进行提交(持久化)。它只能接收请求;

        3、Candidate角色。该角色只有在进行Leader选举的时侯才会存在,每一个Follower都可能临时成为 Candidate 

        一个系统在正常运转的时侯,肯定只有一个Leader和多个Follower存在。        

下面是一个示意图,我觉得它描述得非常清晰(图片非原创)。

        如果一个Follower超过一定时间没有收到Leader角色的心跳,那么它就会等待一段随机的时间发起Leader选举,并将自己也设置为Candidate角色,且投自己一票(当然,你说要投自己一票,让别人也投你,你应该带上自己的最后一条日志的term和log index)。

        如果在超时之前获得了大多数的投票,那么自己就变成Leader;如果收到了其他Leader的消息,证明已经有新的Leader,自己还变成Follower;如果没有获得超过一半的投票,那么就等待该次选举周期超时后再发起选举。

        每一次选举的周期被称为term,随着选举的不断发生,term不断增大。而Candidate在选举时只选举term更大,index最新的节点。这个周期是非常重要的,他要确保同一个参与选举的角色在一个Term内只能投一票,避免会出现脑裂的情况。

        Redis-Cluster采用的就是基于Raft的选举,当某个Master挂掉之后,多个Slave会在间隔一段随机时间后发出广播消息,希望其他Master投它一票,注意这里的随机时间,避免同时发起选举,导致长时间选不出一个master来,不过这样也不能保证发起选举就在一个周期内就会选举成功,这里导致一个问题是,RedisCluster本身也是CP模式的,Master到Slave数据同步是异步的,可能会出现数据丢失的情况。

Raft日志同步:

        Raft算法除了可以用在上面的master选举意外,还可以用于日志同步。

       思想: Leader接收客户端的请求后,会并行地向所有Follower以日志的形式发送,当有半数以上的Follower成功提交了日志,那么才会告知客户端成功提交了。每个日志都会包括term和索引index,以及真正要执行的指令。

        那么Follower是如何处理Leader发来的日志呢?

        首先Follower会将index-1的内容和Leader的进行对比,如果一致,就返回true.如果不等,就返回false,Leader收到false,会减小index值,重新发送,直到最后内容相同,Follower之后的内容都会被覆盖。

        到此为止,可以看到Raft为每个日志都分配了term和index保证唯一性,此外,它也强制Follower必须要和当前的Leader保持一致。

官方描述:

  • leader为每个follower维护一个 nextIndex ,表明下一个将要发送给follower的log entry
  • 当leader刚上任时,会把所有的 nextIndex 设置成其最后一个log entry的index加1,如上图,则是11
  • 当follower的日志和leader不一致时,一致性检查会失败,那么会把 nextIndex 减1
  • 最终 nextIndex 会是leader和follower相同log entry的index加1,这时候,再发送 AppendEntries 会成功,并且会把follower的所有之后不一致的日志删除掉。

Nacos的CP模式用的就是Raft算法,不过其是用了阿里改造的SOFA-Jraft。

Raft文章推荐: Raft日志复制 Raft论文

三、ZAB协议

        该协议是在zookeeper中应用的一种一致性协议,它有很多和Raft相似的地方。比如都是由leader发起写操作,都采用心跳来检测存活性,在选举过程中也都采用谁先获得多数投票谁就成为Leader。但ZAB又有很多独特的地方。如ZAB的Observer不参与请求,只提供给客户端的读请求。

        ZAB全称是Zookeeper Atomic Broadcast,zookeeper原子广播协议,字面意思就可知该协议是基于广播进行的。

        Zookeeper主要有两种模式,崩溃恢复和广播模式,它就是在这两种模式下切换。

        崩溃恢复和Raft的选举过程也很类似,也是在Leader崩溃之后,Follower选择出一个新的Leader(也是获得超过一半的投票)。但投票条件不同,ZAB要求Follower在投票给一个节点前,必须和该节点的日志保证一致,而Raft没这要求,谁term高就给谁投。ZAB的投票参考因素是ZXID,是一个事务的序号,是不断递增的一个值。ZXID是一个64位数字,高32位表示每一代Leader(epoch),低32位表示事务的ID(count)。

        那么可能问了,如果Leader在提交事务后崩溃了或者在把日志复制给Follower时,新Leader会继续处理吗?针对该问题,ZAB协议保证了两点:

        1、已经被Leader的事务会被提交;

        2、已经被Leader跳过的事务不会再执行;

        日志复制和Raft处理方式也是大体一样,也是收到半数以上Follower的Ack后,才会提交事务。区别是ZAB中引入了一个队列,并将带有ZXID的日志按顺序发送给所有Follower,相比于Raft,ZAB实现了解耦。

广播模式的具体流程:

        1、不论是zk集群的哪个机器收到了写请求,就算是follower收到了,它首先是将请求转发给leader服务器,leader负责具体的写请求处理;

        2、leader生成proposal提案,并生成一个全局的ZXID,在后续的恢复模式中是很重要的一个标识。然后通过与每个follwer的队列(FIFO)发送给follower;ZXID在上面已经提到了,官方的对其的定义:

  • Every change to the ZooKeeper state receives a stamp in the form of a zxid (ZooKeeper Transaction Id). This exposes the total ordering of all changes to ZooKeeper. Each change will have a unique zxid and if zxid1 is smaller than zxid2 then zxid1 happened before zxid2.

        3、follower收到消息后,会将数据持久化到硬盘,随后向leader发送一个ACK;

        4、当leader收到集群一半以上的follower发送的ACK,就会向所有的follower发送commit;

        5、follower收到leader发送的commit消息后,就将数据载入内存,供客户端读取。

下面这张图(非原创)比较清晰描述了上个过程,但该图有个问题,就是请求不一定就是发送给leader,可以发送给ZK集群任意一个节点,只不过是如果请求是写请求的话,follower会转发给leader。

其实上面也是一个分布式事务的实现,通过三阶段提交实现事务。关于分布式事务的介绍可以参见: 分布式事务

四、ES选举Bully算法

        ES的选举并没有采用常用的Raft算法,而是使用Bully算法。其基础是为集群的每个节点都分配一个唯一id。ES会为整个集群的每个node分配一个唯一的id,这个id是node在启动时随机分配的。此外,每个节点都会有一个版本号clusterVersion,该字段代表的是状态值,master节点一定是拥有最新版本号的节点。

        ES里的节点分成Master节点,Master候选节点和数据节点。角色需要通过配置来做。Master节点对应Raft的Leader,Master候选节点也是对应Follower和Candidate。

        那么当发现Master节点下线时,候选节点投票的原则是首先选择版本号更高的,如果版本号都相同,就选择id最小的。和Raft相同的是,同样是要求一半以上投票的节点才可成为Master节点,但和Raft不同的是,ES并没有完全避免脑裂的问题,这也是ES选举过程存在的最大问题,之所以会出现脑裂是因为虽然也是获得绝大多数投票的才能成为master,但是他并没有限制一个节点只能投一票,如果一个节点在投票后迟迟等不到选举的结果,可能又开始投票,此时因为优先级的问题又投票给其他节点了,就意味着这个节点投了两票给不同节点,就会出现问题。这种问题Raft算法解决的就很好,Raft引入了Term的概念,一个Term周期内,一个节点只能投一票。Term大的优先级高。    

参考资料:

zookeeper面试题

Raft协议和Zab协议及其对比

分布式一致性与共识算法

Redis-Cluster实现

Raft算法详解

共识机制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/401185.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

git使用过的命令记录

目录 git add .git commit --amendgit push -f origin HEAD:mastergit checkout .git stash想把某个pr的修改应用到本地git pull 将远程仓库的最新代码更新到本地git 撤销,放弃本地修改参考文档 git add . 将本地修改提交到暂存区 git commit --amend 如果本地有…

MySQL 8.0.36 WorkBench安装

一、下载安装包 百度网盘链接:点击此处下载安装文件 提取码:hhwz 二、安装,跟着图片来 选择Custom,然后点Next 顺着左边框每一项的加号打开到每一个项的最底层,点击选中最底层的项目,再点击传过去右边的绿色箭头&a…

MATLAB 导出可编辑的eps格式图像

任务描述:部分期刊要求提交可编辑的eps格式图像,方便美工编辑对图像进行美化 我试了直接print或者在figure窗口导出,发现导出的文件放到Adobe AI中并不能编辑,经Google找到解决办法: %EPS exportgraphics(gcf,myVect…

FFmpeg的HEVC解码器源代码学习笔记-1

一直想写一个HEVC的码流解析工具,看了雷神264码流解析工具,本来想尝试模仿写一个相似的265码流分析工具,但是发现265的解码过程和结构体和264的不太一样,很多结构体并没有完全暴露出来,没有想到很好的方法获得量化参数…

[晓理紫]AI专属会议截稿时间订阅

AI专属会议截稿时间订阅 VX关注{晓理紫}免费,每日更新最新AI专属会议信息,如感兴趣,请转发给有需要的同学,谢谢支持!! VX关注{晓理紫}免费 IROS 2024 Deadline: Sat Mar 2nd 2024 03:59:59 PM CST (2024-03-02 15:59:59 UTC-08) date_location: October 14-18, 2024. A…

鸿蒙会成为安卓的终结者吗?

随着近期鸿蒙OS系统推送测试版的时间确定,关于鸿蒙系统的讨论再次升温。 作为华为自主研发的操作系统,鸿蒙给人的第一印象是具有颠覆性。 早在几年前,业内就开始流传鸿蒙可能会代替Android的传言。毕竟,Android作为开源系统&…

第10讲用户登录SpringSecurity查库实现

用户登录SpringSecurity查库实现 security包下新建MyUserDetailServiceImpl Service public class MyUserDetailServiceImpl implements UserDetailsService {AutowiredSysUserService sysUserService;Overridepublic UserDetails loadUserByUsername(String username) throw…

C#算法(12)—对图像像素做X/Y方向的偏移

我们在上位机开发领域有时候需要对获取的图像的像素做整体的偏移,比如所有像素在X方向上偏移几个像素,或者所有像素在Y方向上偏移几个像素,本文就是开发了像素整体偏移算法来解决这个问题。 比如有一个图像大小为3*3,像素值如下图1,如果我想实现将这个幅图像的像素整体往右…

【深蓝学院】移动机器人运动规划--第5章 最优轨迹生成--作业

0. 题目 1. 解答 — Listing1: void minimumJerkTrajGen(// Inputs:const int pieceNum,const Eigen::Vector3d &initialPos,const Eigen::Vector3d &initialVel,const Eigen::Vector3d &initialAcc,const Eigen::Vector3d &terminalPos,const Eig…

UML---活动图

活动图概述 活动图(Activity Diagram)是UML(Unified Modeling Language,统一建模语言)中的一种行为建模工具,主要用于描述系统或业务流程中的一系列活动或操作。活动图通常用于描述用例中的行为&#xff0c…

算法项目(5)—— 时序模型TFT数据趋势预测

本文包含什么? TFT+机器学习融合完整的在线运行的代码环境(免配置环境)代码介绍运行有问题? csdn上后台随时售后.项目说明 本文主要实现用谷歌的论文Temporal Fusion Transformers for Interpretable Multi-horizon Time Series Forecasting(TFT)来做时间序列的预测. 模型整…

C++类和对象——多态详解

目录 1.多态的基本语法 2.多态的原理剖析 示例&#xff1a;计算机类 3.纯虚函数和抽象类 示例&#xff1a;制作饮品 4.虚析构和纯虚析构 示例&#xff1a;电脑组装 1.多态的基本语法 代码示例&#xff1a; #include<bits/stdc.h> using namespace std;class mus…

1903_CoreMark白皮书阅读笔记

1903_CoreMark白皮书阅读笔记 全部学习汇总&#xff1a; g_embedded: 嵌入式通用技术学习笔记 (gitee.com) 再看ARM的内核架构介绍的时候看到了不同的内核都测试了一个CoreMark/Mhz的参数。从名称看&#xff0c;可以理解为是MCU的算力跑分。至于这部分究竟是测试了哪些功能&…

CV论文--2024.2.22

SOURCE&#xff1a;CV论文--2024.2.22 1、CounterCurate: Enhancing Physical and Semantic Visio-Linguistic Compositional Reasoning via Counterfactual Examples 中文标题&#xff1a;CounterCurate&#xff1a;通过反事实示例增强物理和语义视觉语言组合推理 简介&…

“替代云”知多少?Akamai Linode 重新定义公有云服务!

自2006年云计算概念提出以来&#xff0c;云产业已经成为数字化时代所必备的底层基础&#xff0c;但随着多元化的业务需求的增多&#xff0c;多云战略、本地部署所形成混合环境&#xff0c;都使得云复杂性&#xff0c;日渐成为了迫在眉睫的挑战。 451 Research 云价格指数 (CPI…

HarmonyOS Stage模型基本概念讲解

本文 我们来说harmonyos中的一种应用模型 Stage模型 官方提供了两种模型 一种是早期的 FA模型 另一种就是就是 harmonyos 3.1才开始的新增的一种模型 Stage模型 目前来讲 Stage 会成为现在乃至将来 长期推进的一种模型 也就是 无论是 现在的harmonyos 4.0 乃至 之后要发布的 …

pytest基本应用

文章目录 1.pytest安装2.用例运行规则3.常用参数断言运行参数用例控制setup和teardownini配置文件 4.常用插件5.pytest高阶用法用例跳过参数化 6.pytest之Fixture使用fixture使用装饰器usefixtures 7.pytest之conftest.py8.conftestfixtureyieldyield介绍前后置使用 1.pytest安…

2012及其以上系统修改服务器密码指南

修改服务器密码指南,目前介绍两种不同的方案 方法一 指令式 winR键 弹出运行框里输入 cmd 点击确认或者右下角开始程序里面的点开运行 2.在弹出框里手动输入以下一组文字&#xff1a;net user administrator 123456 框内无法粘贴 需要手动输入 其中administrator 是用…

4核8G服务器腾讯云和阿里云租用价格对比,2024更新

4核8G云服务器多少钱一年&#xff1f;阿里云ECS服务器u1价格955.58元一年&#xff0c;腾讯云轻量4核8G12M带宽价格是646元15个月&#xff0c;阿腾云atengyun.com整理4核8G云服务器价格表&#xff0c;包括一年费用和1个月收费明细&#xff1a; 云服务器4核8G配置收费价格 阿里…

Sora刷爆了,先来了解下基本情况

2月15日&#xff0c;OpenAI发布的Sora模型确实在文生视频领域取得了显著的进步&#xff0c;其特点和创新性表现在以下几个方面&#xff1a; 视频生成长度&#xff1a;Sora模型能够生成长达1分钟的视频&#xff0c;这相比之前的文生视频模型有了显著的提升。这一长度的视频已经…