Zookeeper理解---ZAB协议

ZAB协议

  • Zookeeper并不是完全采用Paxos算法,而是使用了一种称为Zookeeper Atomic Broadcast(ZAB,Zookeeper原子消息广播协议)作为数据一致性的核心算法,依据此算法来实现分布式数据一致性的解决。他是一种特别为Zookeeper设计的奔溃可恢复的原子消息广播算法。
  • ZAB协议的核心是定义了对应那些会改变Zookeeper服务器数据状态的师傅请求的处理方式:
    • 所有事务请求必须有一个全局唯一服务器来协调处理,这样的服务器被称为leader服务器
    • 其他服务器成为follower服务器,leader服务器负责讲一个客户端事务请求转换成一个事务Proposal(提议),并将改Proposal分发给集群中所有Follower服务器
    • leader服务器等待所有Follower反馈,等待超过半数Follower进行了正确反馈
    • leader就会再次向所有Follower发出Commons消息,要求将前一个Proposal进行提交

协议介绍

  • ZAB包括两种基本模式:
    • 奔溃恢复: 当整个服务框架启动过程中,或者leader节点出现网络故障或者崩溃退出与重启等异常情况时候,ZAB协议会进入恢复模式进行选举产生新的Leader服务器,当选出来Leader并且同步了半数以上的Follower节点状态(状态同步就是数据同步)后,ZAB才退出恢复模式
    • 消息广播:过半数Follower都与Leader同步完成后,整个服务框架就可以进入消息广播模式了。但一台同样遵循ZAB协议的节点加入后,此时已经有一个Leader节点,新加入的服务会自觉进入恢复模式,同步数据后加入广播流程
    • Leader节点作用在于接受客户端事务请求后,会生成对应的事务提案并发起一轮广播协议,如果集群中其他节点先收到客户端事务请求,他会转发给leader节点
  • 关键字:过半数节点

消息广播

  • ZAB协议的消息广播过程是使用的原子广播协议,类似一个二阶段提交的过程,上面一节提到过,就如下图中所示
    在这里插入图片描述
  • 与二阶段提交不同的是,ZAB的提交过程移除了中断逻辑,也就是不存在应为单个节点没回应ACK而中断广播的情况,所有Follower要么正常反馈,要么抛弃leader服务器,并且只需要过半数的Follower服务器访客ACK后就开始提交事务Proposal,而不需要所有。这种情况有弊端:无法处理leader崩溃带来的数据不一致问题(恢复模式解决此问题),并且整个消息广播协议是有FIFO特性的TCP协议来进行网络通信,能保证消息发送的顺序
顺序性保证
  • 因为只有Leader服务器负责生产对应Proposal来进行广播,并且广播之前,leader会为每一个Proposal分配一个全局唯一递增事务ID(即ZXID)。由此递增ID就可以保证我们每一个Proposal严格按照ZXID顺序来进行处理发送即可
  • 处理好了leader发送顺序,Follower如何保证接受到顺序:广播过程Leader会为每一个Follower分配一个单独队列,依次将Proposal放入队列,并且依据ZXID顺序FIFO策略进行消息发送,每个Follower接受到事务Proposal会以事务日志形式写入本地磁盘,成功写入后反馈给Leader服务器一个Ack响应。
  • Leader收到超半数ACK后,广播一个Commit消息给所有Follower服务器以通知进行事务提交,同事Leader自己也完成Commit。

奔溃恢复

  • Leader节点奔溃后需要触发选举,选出新Leader,并让所有节点能够快速的感知到新的Leader服务器是哪个
基本特性
  • 崩溃恢复可能出现两种数据不一致的隐患, 针对这两种情况ZAB需要保证的特性:

  • 情况一: ZAB协议需要确保已经在Leader服务器上提交的服务最终被所有服务器都提交

  • 事务在Leader服务器上被提交了,并且已经得到过半Follower服务器的ACK反馈,但在Commit消息发送给所有Follower机器之前Leader服务器挂了,如下图:
    在这里插入图片描述

  • 上图leader是Server1,已经广播消息P1,P2,C1,P3和C2,当leader将C2(C2 是Commit of proposal2的缩写)发出后崩溃,此时ZAB协议需要保证Proposal2最终能在所有服务器上被提交

  • 情况二:ZAB需要确保丢弃那些只在Leader服务器上被提出的事务。

  • 与之前相反的情况,奔溃恢复过程中出现一个需要被丢弃的案例,那么恢复后需要跳过次事务:
    在这里插入图片描述

  • 上图Leader服务器Server1 提出一个事务Proposal3后就奔溃,其他follower都没有收到这个事务,当Server1恢复再次加入集群,ZAB需要确保丢弃这个Proposal3

Leader选举
  • 根据以上两种情况确保提交已经被Leader提交的事务Proposal同时丢弃被跳过的事情,需要ZAB必须有这样的Leader选举算法:
    • 保证选举出来的Leader服务器拥有集群中所有机器最高编号(最大ZXID)事务Proposal,那么可以把这这个新选举出来的Leader一定具有所有已经提交的案例,并且可以省去服务器检查proposal的提交和丢弃工作的这部操作,所有事务按最高ZXID节点拥有的数据为准。
数据同步
  • Leader选举后,Leader服务器为每一个Follower服务器准备一个队列,将那些没有被Follower服务器同步的事务以Proposal消息的方法逐个发给Follower服务器,并且在每个Proposal消息后紧接着发一个Commit消息,标识已经提交。等同步完成所有消息并且将数据应用到本地数据库中后,leader会将Follower服务器加入到真正的可用Follower列表,并且开始之后的流程。
丢弃数据
  • 如何处理需要被丢弃的Proposal,ZAB协议变化ZXID设计上解决这个问题:
  • ZXID是一个64位的数据,低32位是一个单调递增的计数器,针对每个事物请求计数器+1操作,高位32位代表Leader周期epoch的编号,每单选举产生一个新的Leader服务器,就会从Leader服务器上去除其本地日志中最大事物Proposal的ZXID,
    并从该ZXID中解析出上一次的epoch值,然后在这个基础上+1,就用此编号作为新的epoch,就相当于每一个Leader都递增1 的一个策略。ZAB协议通过epoch编号来区分Leader周期变化策略,能有效避免不同Leader服务器错误使用相同ZXID变化踢出不一样事务Proposal的异常情况,对于识别崩溃后在恢复之后生成的Proposal非常有帮助。
结论
  • 基于上面的策略,当一个包含上一个Leader周期中没提交的事务Proposal的服务器复活的时候,肯定无法成为Leader,因为当前集群中包含一个Quorum集合,该集合中一定包含了更高epoch的事务Proposal,因此当前复活的节点事务Proposal肯定是旧的,无法成为Leader,当加入集群后,只能以Follow角色链接Leader服务器,接着Leader会根据自己服务器上最后被提交的Proposal来和Follower的Proposal对比,接着会按当前Leader的匹配要求同步当前Leader的数据(也就相当于回退)到一个确实已经被集群中过半集群提交的最新事务Proposal。

深入ZAB协议

  • 上面部分介绍类ZAb协议大体内容以及实际运行中消息官博和奔溃恢复这两个基本模式。以下从系统模型,问题描述,算法描述,运行分析深入理解ZAB协议
系统模型
  • 分布式系统模型中我门将每个server看作是一个进程p,那么可以用集合∏={P1,P2,…,Pn}来表示分布式系统,每个进程都具有格子的存储设备,就好比缓存隔离,个进程直接互相通信来实现消息传递。每个进程都肯奔溃或重启,奔溃我们称为down踢出集合∏,恢复存活状态我们称为up重新加入∏,只要∏ 集合中有超过半数的是up状态就可以进行消息广播,我们将这样一个自集合称为Quorum(上文提到过)之后用Q表示,并假设Q已经存在满足以下:
//存在任意Q Q是 ∏ 的子集
∧ ∀Q,Q ⊆ ∏
//存在任意时候的Q1 Q2,他们的交集不等于空集合(此处的意义在于Q1或Q2 任意一个都超过半数,应此不管如何去交集都能得到一个子集合,极端情况是正好半数多一个元素的情况)
∧ ∀Q1和Q2, Q1∩Q2≠∅
完整性
  • 进程P_j如果收到来自进程P_i的消息m,那么p_i一定发送来消息m
前置性
  • 进程P_j收到来消息m,那么存在这样的消息m’:如果消息m’ 是消息m的前置,那么P_j务必先收到m’,这种关系表示:m’ < m
问题描述
  • Zookeeper需要解决一系列诸如可靠配置存储,运行时状态记录等分布式协调服务,因此必须具备高吞吐量,低延迟特性,能很好的在高并发下完成分布式数据一致性处理,同时能优雅处理运行时故障,快速恢复
  • ZAB核心是只有一个主进程,如果主进程挂了就重选,主进程选举与消息广播密切相关。随着时间推移可能出现无限多个主进程并构成一个主进程序列:P_1,P_2,P_3…P_e-1,P_e其中P_e ⊆ ∏ ,e表示主进程序列好吗,我们这里称他为主进程周期。
  • 对于以上序列中任意一个如果存在e < e’,那么我们就说P_e 是P_e’ 之前的主进程,使用 P_e < P_e’ ,他门是同一个进程只不过是不同周期而已
主进程周期
  • 用以上 P_e < P_e’ 的案例来解释,就比如进程P_e周期中主节点是L_e,此时主节点L_e 挂掉了,重新选出L_e’(e’=e+1)就得到了P_e’,其实是同一个进程只是表示他在不同的Leader周期下而已,我们表示为e < e’
事物
  • 几个概念,我们假设各个进程中有一个transactions(v,z)这样的函数,用来实现主进程堆状态变更的广播,其中参数v:事物内容,z:事物表示,而每一个事物表示z=<e,c>,e表示进程周期,c表示周期内事物技术,也就是我们上文中提到的epoch(z)表示事物标识中的主进程周期epoch,counter(z)表示事务计数器
  • 每个新事务c都递增,实际运行中事务z 优与事务 z’ ,有两种情况:
    • epoch(z) < epoch(z’) :z是上一个主进程周期中的事务,z’是重新选举后的事务
    • epoch(z) = epoch(z’) 且 counter(z) < counter(z’) 同一个主进程周期,但是z’事务序列号更大
算法描述
  • ZAB协议注意包括消息广播和崩溃恢复,进一步可以分三个阶段:发现(Discovery),同步(Synchronization),广播(Broadcast),先定义如下专用标识和属于
术语名说明
F.pFollower f处理过的最后一个事务Proposal
F.zxidFollower f处理过的历史事务Proposal中最后一个Proposal的事务表示ZXID
h_f每一个Follower f通常都已经处理(接受)了不少事务Proposal,并且会有一个针对已经处理过的事务的集合,将其表示为Hf,表示Follower f已经处理过的事务的序列
I_e初始化历史记录,在某个主进程周期epoch中,当准Leader完成阶段一之后,此时他的h_f就被标记为I_e
阶段一:发现
  • 主要是Leader选举过程,用于分布式进程中选举主进程,准Leader L,和Follower F工作流程:(姑且认为Leader L是随机出来的)

    • 步骤F.1.1 Follower F将自己最后接受的事务Proposal的epoch值CEPOCH(F.p)发送给准Leader L
    • 步骤L.1.1 当接受来自过半的Follower的Cepoch(F.p)消息后,准Leader L会生成NEWEPOCH(e’),这个epoch的值e’ 是Leader L从CEPOCH(F.p)消息中选取的最大epoch,然后对其+1得到e’(就是获取最大一个ZXID的值从中得到epoch,然后在+1)
    • 步骤F1.2 当Follower 接受到来自准Leader L的NEWEPOCH(e’)消息后,如果其检测到当前CEPOCH(F.p)小于e’,那么就将CEPOCH(F.p)=e’,同时向这个准Leader L反馈Ack消息。这个反馈消息(ACK-E(F.p, h_f)),包含当前该Follower的epoch(F.p)也就是最后一个事务的信息,以及该Follower的历史事务Proposal列表:h_f
  • 当Leader L接受到来自过半Follower的确认消息Ack后,Leader L就会从这过半服务器中选取出一个Follower F,使用他的I_e最为初始化事务结婚I_e’

  • 关于这个Follower F的选取对于Quorum中其他任意一个Follower F’ ,F需要满足以下两个条件中的一个:

//任意Follower F'的epoch主节点周期值小于 Follower F主节点周期值(主节点周期值也就是Leader节点序列号每次选举+1这个)
CEPOCH(F'.p) < CEPOCH(F.p)
//如果两节点Follower F与Follower F'的epoch值相同也就是在同一个主节点周期,那么我们比较Follower F'处理的最后一个事务的ZXID要小于 选出来的Follower F处理的最后一个事务的ZXID,也就是我们选出来的必然是up集合中拥有最大ZXID事务的Follower节点,或者两个都相同则都可以是Leader列表的备选
(CEPOCH(F'.p) = CEPOCH(F.p)) & ( F'.zxid < F.zxid 或 F'.zxid = F.zxid)
阶段二:同步
  • 发现流程后,进入同步节点,此时Leader L与Follower F流程如下:
    • L.2.1 Leader 会将e’和I_e’以NEWLEADER(e’, I_e’)消息的形式发送给Quorum中的Follower(将新的epoch主节点序列号和 最全的事务列表同步)
    • 步骤F.2.1 当Follower接受到来自Leader L的NEWLEADER(e’, I_e’)消息后,如果Follower发现CEPOCH(F.p)≠ e’,那么直接跳过进入下一轮循环因为此时Follower 发现自己还在上一轮,或者更上一个的同步中,因为需要在发现阶段就已经将epoch修改为e’,他可能还在发现阶段属于另外一半还没收到Leader L的NEWEPOCH(e’)消息的节点
    • 如果CEPOCH(F.p) = e’ ,那么Follower会执行事务应用操作,具体的对每一个事务Proposal:<v, z > ⊆ I_e’, Follower都会接受<e’, <v, z>>。最后Follower会反馈给Leader,表示字节已经接受并处理来所有I_e’中的事务,(此处的意思是Leader L节点将最新的一份Proposal列表的信息以及最新的epoch数据发送给每一个Follower节点让他去同步修改,如果Follower中的Proposal是在其中,那么我就将之前Proposal里面的epoch值也就是e修改为新的epoch值也就是e’)
    • 步骤L.2.2 当Leader 接受到来自过半Follower 针对NEWWLEADER(e’, I_e’)的反馈消息后,就会向所有Follower发送消息Commit,至此Leader 完成阶段二
    • 步骤F.2.2 当Follower收到来自Leader的Commit后,就会一次处理并提交所有在I_e’中为未理的事务,至此Follower完成阶段二
阶段三:广播
  • 完成同步后ZAB开始正式工作,接受客户端新事务请求,进行广播流程
  • 步骤L.3.1 Leader L接受到客户端新的事务请求,会生成对应的事务Proposal,并且根据ZXID顺序向Follower发送提案<e’, <v, z>>,其中epoch(z) = e’,z就是ZXID,64位,低32 是Proposal事务序列号,高32位是Leader周期的epoch序列号
  • 步骤F.3.1 Follower根据消息接收先后顺序处理来自Leader事务的Proposal,并将他们追加到h_f中去,之后在反馈给Leader
  • 步骤L.3.1 当Leader接收到来自过半Follower针对事务Proposal<e’, <v, z>>的Ack消息后,就发送Commit<e’, <v, z>>消息给所有Follower,要求他们进行事务的提交
  • 步骤F.3.2 当Follow F接受到来自Leader的Commit<e’, <v, z>> 就会开始提交Proposal<e’, <v, z>>,需要主要,此时该Follower F必定已经提交来事务Proposal<v’, z’ >,其中<v’, z’ > ⊆ h_f, z’ < z
总结

如下图是以上三个流程总结,各个消息说明如下:
在这里插入图片描述

  • CEPOCH:Follower进程向准Leader发送字节处理过的最后一个事务Proposal的epoch值
  • NEWEPOCH:准Leader根据接受到的各进程的epoch生成新一轮的周期epoch值
  • ACK-E:Follower进程反馈Leader进程发来的NEWEPOCH消息
  • NEWLEADER: 准Leader进程确认字节领导地位,并发生NEWLEADER消息给各个进程
  • ACK-LD:Follower进程反馈Leader进程发来的NEWLEADER消息
  • COMMIT-LD:要求Follower进程提交相应的历史事务Proposal
  • PROPOSE:Leader进程生成一个针对客户端事务请求的Proposal
  • ACK:Follower进程反馈Leader进程发来的PROPOSAL消息
  • COMMIT:Leader发送COMMIT消息,要求所有进程提交事务PROPOSE

上一篇:Zookeeper–简介
下一篇:Zookeeper–ZAB与Paxos算法联系与区别

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【最强VSCode】之管理MySql数据库

(梅花香自苦寒来)你没有看错&#xff0c;就是用VSCode来管理MySql数据库&#xff0c;我也是第一次听说&#xff0c;感谢群管理DX小伙伴&#xff0c;三人行必有我师焉。话不多说&#xff0c;直接开张&#xff0c;VSCode还是很不错的&#xff0c;以后多多分享插件吧。1、你平时是…

[Flags]标识的Enum不能使用Html.GetEnumSelectList方法

在使用Asp.Net Core MVC写程序时&#xff0c;对用户类型做了如下定义&#xff1a;namespace ManufacturingExecutionSystemCore.Enums {public enum UserType{[Description("无身份人员")][Display(Name "无身份人员")]UnidentifiedPerson0x00,[Descripti…

Zookeeper实践与应用- Canal

基于MySql BinLog的增量订阅和消费组件&#xff1a;Canal Cancal是阿里13年1月开源的一个基于MySql数据库Binlog实现的增量订阅和消费的组件。项目取名Canal取自管道的英文单词&#xff0c;流转的医生&#xff0c;是一个定位于基于MySql数据库Binlog增量日志来实现数据库镜像&…

你遇到的面试官是「伯乐」吗?

之前写了一篇应应聘者视角的「面试中要注意的点」&#xff0c;《聊聊面试的事&#xff08;应聘方&#xff09;》。这次再来一篇面试官视角的。如果你不是面试官&#xff0c;也没关系。所谓“知己知彼&#xff0c;方能百战百胜”&#xff0c;了解一下面试官在面试时的侧重点&…

记录一次线上超时异常查询

线上事故复盘 前言 前一次上线&#xff0c;当时正常&#xff0c;第二天发现有部分超时报警&#xff0c;最终发现应为Dubbo接口一次传输数据量太大导致线程虚拟内存占用 线上问题排查过程 报警邮件中查询到有一部分接口超时量激增&#xff0c;查询定位到某个Dubbo接口&#x…

没用过.gitignore还敢自称高级开发?

Git是跟踪项目中所有文件的好工具&#xff0c; 但是&#xff0c;您会希望在项目的整个生命周期中不要跟踪某些文件及其变更。系统文件&#xff08;i.e. Mac系统的.Ds_Store&#xff09;应用程序配置文件&#xff08;i.e. app.config, .env&#xff09;构建组件&#xff08;i.e.…

支付价格计算中精度问题之double,float

前言 前段时间开发新的微信小程序&#xff0c;借此机会将老掉牙的支付模块重构&#xff0c;并且支持现金支付&#xff08;之前都是虚拟币支付&#xff09;&#xff0c;在重构期间遇到计算上的一些精度问题&#xff0c;虽然数额影响非常小但是影响比较大&#xff0c;我觉得有必…

.net core 集成 sentry 进行异常报警

.net core 集成 sentry 进行异常报警IntroSentry 是一个实时事件日志记录和汇集的平台。其专注于错误监控以及提取一切事后处理所需信息而不依赖于麻烦的用户反馈。它分为客户端和服务端&#xff0c;客户端(目前客户端有 C#, Python, PHP, JavaScript, Ruby等多种语言)就嵌入在…

[Qt入门]QTableWidget控件创建

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);//TableWidget控件//设置列数ui->tableWidget->setColumnCount(3);//设置水平表头ui->tableWidget->…

Zookeeper--Watcher机制源码剖析一

Watcher-- 数据变更通知 我们知道Zookeeper提供来分布式数据的订阅/发布功能&#xff0c;一个典型的发布/订阅模型系统定义了一种一对多的订阅关系&#xff0c;能让多个订阅者同时监听某个主题对象&#xff0c;当这个被监听对象自身状态发生变化时候&#xff0c;会通知所有订阅…

.NET Core 3.1 的REST 和gRPC 性能测试

看到越南小哥 的github 上的Evaluating Performance of REST vs. gRPC &#xff0c; 使用的是.NET Core 3.0 , 今天我把它升级到.NET Core 3.1 同样做了一个测试&#xff0c;文章的结果和他的博客文章是一样的&#xff1a;https://dev.to/thangchung/performance-benchmark-grp…

Zookeeper--Watcher机制源码剖析二

Watcher触发 我们从实际操作时候的表现来看Watcher的触发&#xff0c;比如Zookeeper中NodeDataChanged时间的触发是“Watcher监听的对应数据节点的数据内容发生变更”&#xff0c;需要修改节点数据那么必然和数据节点存储的位置DataTree有关系&#xff0c;我们从这里去寻找修改…

吴军《硅谷来信》工作篇学习总结

【学习总结】| 作者 / Edison Zhou这是恰童鞋骚年的第215篇原创文章2018年在得到App上订阅了吴军老师的《硅谷来信》&#xff0c;从此每天的碎片时间就开始听吴军老师在大洋彼岸寄来的信件了。整个来信涵盖了职业发展、工作效率、业余生活等多个主题&#xff0c;从吴军老师的视…

Zookeeper实践与应用-- Nginx负载均衡差异

Nginx/ZooKeeper 负载均衡的差异 Nginx 是我们常见的反向代理服务器&#xff0c;也被广泛的用作负载均衡服务器ZooKeeper是分布式协调服务框架&#xff0c;有时也被用来做负载均衡 Nginx Nginx负载均衡配置非常简单&#xff0c;吧多个Web Server配置到nginx中&#xff0c;用…

从对我的质疑说起,谈谈Linux下的文件删除

特特本来就是个刚毕业的小菜&#xff0c;很多知识都是靠着大家的指点才慢慢学会的。之前在一篇"纯属虚构"的文章 (鹅厂后台开发工程师的工作日常) 提到使用 rm 命令删除一个近 100 G 的 log 文件。很荣幸&#xff0c;这篇文章被一个大号转载了&#xff0c;获得了很不…

Zookeeper实践与应用--分布式锁实现

分布式锁 分布式锁是控制分布式系统之间同步访问资源的一种方式&#xff0c;如果不同系统是同一个系统的不同主机之间共享一个或一组资源&#xff0c;那么访问这些资源的时候&#xff0c;往往需要通过一些呼哧手段来防止彼此之间的干扰保证统一性&#xff0c;因此需要分布式锁…

关于 Blazor Server Side 的一些杂项, 感想

在2016年, 本人就开始了一个内部项目, 其特点就是用C#构建DOM树, 然后把DOM同步到浏览器中显示. 并且在一些小工程中使用.3年下来, 效果很不错, 但因为是使用C#来构建控件树, 在没有特定语法的情况下, 代码风格不是那么好.典型的风格大概是这样的:这个模式挺好的, 有点嫌弃C#代…

重现江湖!大数据高并发——架构师秘籍

大数据高并发的话题屡见不鲜&#xff0c;各种应对的方式方法也四处可见。然而笔试面试中一问就懵&#xff0c;简直是高薪拦路虎。为什么呢&#xff1f;究其原因&#xff0c;还是思路不清晰&#xff0c;缺乏实操&#xff0c;所以一问就倒。作为专注.Net领域十几年的老司机&#…

[剑指offer]面试题4:替换空格

面试题4&#xff1a;替换空格 题目&#xff1a;请实现一个函数&#xff0c;把字符串中的每个空格替换成"%20"。例如输入“We are happy.”&#xff0c;则输出“We%20are%20happy.”。 ❖ 时间复杂度为O&#xff08;n2&#xff09;的解法&#xff0c;不足以拿到Offer…

Zookeepe实践与应用--分布队列

分布式队列 接触到不少分布式队列的产品&#xff0c;比如&#xff0c;ActiveMq&#xff0c;RocketMQ&#xff0c;kafka等消息中间价&#xff0c;现在我们看看Zookeeper实现的分布式队列。分布式队列简单讲就可以分两个部分&#xff0c;一种是先进先出&#xff0c;另外一种是等…