分布式与一致性协议之ZAB协议(七)

ZAB协议

ZAB协议:如何处理读写请求

你应该有这样的体会,如果你想了解一个网络服务,执行的第一个功能肯定是写操作,然后才会执行读操作。比如,你要了解ZooKeeper,那么肯定会在zkClient.sh命令行中执行写操作(比如create /geekbang 123)写入数据,然后再执行读操作(比如get /geekbang)查询数据。这样一来,你才会直观地理解ZooKeeper的使用方法。

在我看来,任何网络服务最重要的功能就是处理读写请求,因为我们访问网络服务的本质就是执行读写操作,ZooKeeper也不例外,对ZooKeeper而言,这些功能更重要,因为如何处理写请求关乎着操作的顺序性,会影响节点的创建;而如何处理读请求关乎着一致性,也影响着客户端是否会读到旧数据。

接下来,会从ZooKeeper系统的角度全面地分析整个读写请求的流程,帮助你更加全面、透彻地理解读写请求背后的原理。
我们都知道,在ZooKeeper中,写请求必须在领导者上处理,如果跟随者接收到写请求,则需要将写请求转发给领导者,当写请求对应的提案被复制到大多数节点上时,领导者会提交提案,并通知跟随者提交提案。而读请求可以在任何节点上处理,也就是说,ZooKeeper实现的是最终一致性。

所以,理解了如何处理读写请求,不仅能理解读写这个最重要功能的核心原理,还能更好地理解ZooKeeper的性能和一致性。这样在实际场景中安装部署ZooKeeper的时候,就能游刃有余地做资源规划了。比如,如果度请求比较多,可以增加节点,如配置5节点集群,而不是常见的3节点集群。

ZooKeeper处理读写请求的原理。

其实前面已经演示"如何实现操作顺序性"时旧已经介绍了ZooKeeper处理读写请求的原理。这里不再赘述,只在前面的基础上补充几点。
首先,在ZooKeeper中,与领导者"失联"的节点是不能处理读写请求的。比如,如果一个跟随者与领导者的连接发生了读超时,那么它会将自己的状态设置为LOOKING,那么此时它既不能转发写请求给领导者处理,也不能处理读请求,只有当它"找到"领导者后,才能处理读写请求.

例子
  • 举个例子,某集群发生分区故障,节点C与节点A(领导者)、节点B断联,那么节点C将设置自己的状态为LOOKING,此时节点C既不能执行读操作,也不能执行写操作。如图所示,在这里插入图片描述
    其次,当大多数节点进入广播阶段后,领导者才能提交提案,因为提案提交需要来自大多数节点的确认。最后写请求只能在领导者节点上处理,所以ZooKeeper集群写性能约等于单机。而读请求可以在所有的节点上处理,所以,读性能是水平扩展的。也就是说,你可以通过分集群的方式来突破写性能的限制,并通过增加更加节点来扩展集群的读性能。

ZooKeeper处理读写请求的代码实现

ZooKeeper处理读写请求的具体流程分析如下。

如何实现写操作

在ZooKeeper代码中,处理写请求的核心流程如图所示。这里我用跟随者接收到写请求的情况演示一下。
在这里插入图片描述

  • 1.跟随者在FollowerRequestProcessor.processRequest()中接收到写请求。具体来说,写请求是系统在ZooKeeperServer.submitRequestNow()中发给跟随者的,如代码所示
firstProcessor.processRequest(si)

而firstProcessor是在FollowerZooKeeperServer.setupRequestProcessors()中创建的,如代码所示

protected void setupRequestProcessors() {
// 创建finalProcessor,提交提案或响应查询
RequestProcessor finalProcessor = new FinalRequestProcessor(this);
// 创建commitProcessor,处理提案提交或读请求
comitProcessor = new CommitProcessor(finalProcessor, Long.toString(getServerId()), true, getZooKeeperServerListener());
commitProcessor.start();
// 创建firstProcessor,接收发给跟随者的请求
firstProcessor = new FollowerRequestProcessor(this,commitProcessor);((FollowerRequest)firstProcessor).start();
// 创建syncProcessor,将提案持久化存储,并返回确认响应给领导者
syncProcessor = new SyncRequestProcessor(this, new SendAckRequestProcessor(getFollower()));
syncProcessor.start();
}

需要注意的是,跟随者节点和领导者节点的firstProcessor是不同的,这样firstProcessor在ZooKeeperServer.submitRequestNow()中被调用时,就分别进入了跟随者和领导者的代码流程。另外,setupRequestProcessors()创建了两条处理链,如图所示。在这里插入图片描述

  • 2.跟随者在FollowerRequestProcessor.run()中将写请求转发给领导者,如代码所示
// 调用learner.request() 将请求发送给领导者
zks.getFollower().request(request);
  • 3.领导者在LeaderRequestProcessor.processRequest()中接收写请求,并最终调用pRequest()创建事务(也就是提案)并持久化存储,如代码所示
// 创建事务
pRequest2Txn(request.type, zks.getNextZxid(), request, create2Request, true);
......
// 分配事务标识符
request.zxid = zks.getZxid();
// 调用ProposalRequestProcessor.processRequest()处理写请求,并将事务持久化存储
nextProcessor.processRequest(request);

需要注意的是,写请求也是在ZooKeeperServer.submitRequestNow()中发给领导者的,如代码所示

firstProcessor.processRequest(si)

而firstProcessor是在LeaderZooKeeperServer.setupRequestProcessors()中创建的,如代码所所示:

protected void setupRequestProcessors() {
// 创建finalProcessor,最终提交提案和响应查询
RequestProcessor finalProcessor = new FinalRequestProcessor(this);
// 创建toBeAppliedProcessor,存储可提交的提案,并在提交提案后从toBeApplied队列移除已提交的提案
RequestProcessor toBeAppliedProcessor = new Leader.ToBeAppliedRequestProcessor(finalProcessor, getLeader());
// 创建commitProcessor,处理提案提交或读请求
commitProcessor = new COmmitProcessor(toBeAppliedProcessor, Long.toString(getServerId()),false, getZooKeeperServerListener());
commitProcessor.start();
// 创建proposalProcessor,按照顺序广播提案给跟随者
ProposalRequestProcessor proposalProcessor = new ProposalRequestProcessor(this, commitProcessor);
proposalProcessor.initialize();
// 创建preRequestProcessor,根据请求创建提案
preRequestProcessor = new PreRequestProcessor(this, proposalProcessor);
preRequestProcessor.start();
// 创建firstProcessor,接收发给领导者的请求
firstProcessor = new LeaderRequestProcess(this, preRequestProcessor);
...
}

需要注意的是,与跟随者类似,setupRequestProcessor()也为领导者创建了两条处理链(其中处理链2是在创建proposalRequestProcessor时创建的),如图所示.其中,处理链1是核心处理链,最终实现写请求处理(创建提案、广播提案、提交提案)和读请求对应的数据响应。处理链2实现提案持久化存储,并返回确认响应给领导者自己在这里插入图片描述

  • 4.领导者在ProposalRequestProcessor.processRequest()中调用propose()将提案广播给集群所有节点,如代码所示:
zks.getLeader().propose(request);
  • 5.跟随者在Follower.processPacket()中接收到提案,持久化存储,并返回确认响应给领导者,如代码所示
fzk.logRequest(hdr, txn, digest);
  • 6.领导者在接收到大多数节点的确认响应(Leader.processAck())后,最终在CommitProcessor.tryToCommit()提交提案,并广播COMMIT消息给跟随者,如代码所示
// 通知跟随者提交
commit(zxid);
// 自己提交
zk.commitProcessor.commit(p.request);
  • 7.跟随者接收到COMMIT消息后,在FollowerZooKeeperServer.commit()中提交提案,如果最初的写请求是自己接收到的,则返回成功响应给客户端,如代码所示
// 必须顺序提交
long firstElementZxid = pendingTxns.element().zxid;
if (firstElementZxid != zxid) {
LOG.error("Commiting zxid 0x" + Long.toHexString(zxid) + "but next pending txn 0x" + Long.toHexString(firstElementZxid));
ServiceUtils.requestSystemExit(ExitCode.UNMATCHED_TXN_COMMIT.getValue());
}// 将准备提交的提案从pendingTxns队列移除
Request request = pendingTxns.remove();
request.logLatency(ServiceMetrics.getMetrics().COMMIT_PROPAGRATION_LATENCY);
// 最终调用FinalRequestProcessor.processRequest() 提交提案,如果最初的写请求是自己接收到的,则返回成功响应给客户端
commitProcessor.commit(request);

这样,ZooKeeper就完成了写请求的处理。需要特别注意的是,在分布式系统中,消息或者核心消息的持久化存储很关键,也很重要,因为这是保证集群稳定运行的关键。当然数据写入最终还是为了后续的数据读取,那么ZooKeeper是如何实现读操作的呢?

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

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

相关文章

如何购买阿里云99计划的ECS云服务器?99元购买阿里云2核2G3M服务器教程

阿里云助力中小企业和开发者无忧上云的“99计划”中有两款性价比超高的ECS云服务器,2026年3月31日活动结束前新购和续费价格一样。 其中个人和企业新老用户同享的2核2G3M服务器仅需99元/年(续费同价),企业新老用户同学的2核4G5M仅…

Python 框架安全:Django SQL注入漏洞测试.(CVE-2021-35042)

什么是 Django 框架 Django 是一个用 Python 编写的 Web 应用程序框架。它提供了许多工具和库,使得开发 Web 应用程序变得更加容易和高效。Django 遵循了“MTV”(模型-模板-视图)的设计模式,将应用程序的不同组件分离开来&#x…

《从零开始,搭建一个简单的UVM验证平台》实操

最近的工作中需要用UVM平台去仿真软件同事写的C程序,虽然只要用EDA同事已经搭好的UVM平台稍微改改就行,但对于我这种从未接触过UVM甚至都没用过System Verilog的纯FPGA工程师来说还是很有难度的,因为我对这方面一点概念都没有。 基于此&…

[Kubernetes] 安装KubeSphere

选择4核8G(master)、8核16G(node1)、8核16G(node2) 三台机器,按量付费进行实验,CentOS7.9安装Docker安装Kubernetes安装KubeSphere前置环境: nfs和监控安装KubeSphere masternode1no…

【QT学习】14.线程学习

一。线程了解 线程是计算机科学中的一个重要概念,它是操作系统能够进行运算调度的最小单位。线程是进程中的一个执行流,一个进程可以包含多个线程。与进程相比,线程更轻量级,可以更高效地利用计算机资源。 线程有以下几个特点&…

OpenCV|简单绘制一个矩形

OpenCV中的rectangle() 为绘制矩形命令,形式如下: # (img: cv2.typing.MatLike, pt1: cv2.typing.Point, pt2: cv2.typing.Point, color: cv2.typing.Scalar, thickness: int ..., lineType: int ..., shift: int ...)cv2.rectangle(img, pt1, pt2, …

Dynamic Extraction of Subdialogues for Dialogue Emotion Recognition

对话情感识别的子对话动态提取 摘要1. 介绍2 相关工作2.1 对话上下文建模2.2 常识知识 3 方法3.1 问题定义3.2 模型概述3.3 特征提取模块3.4 依赖性建模3.5 交互式子对话提取模块3.6 重要性增强的多头自注意力模块3.7 子对话框主题提取模块3.8. 分类模块 四、实验4.1 数据集4.1…

含义:理财风险等级R1、R2、R3、R4、R5

理财风险等级R1、R2、R3代表什么,为什么R1不保本,R2可能亏损 不尔聊投资https://author.baidu.com/home?frombjh_article&app_id1704141696580953 我们购买理财产品的时候,首先都会看到相关产品的风险等级。风险等级约定俗成有5级&…

Java进阶07集合(续)

Java进阶07 集合(续) 一、数据结构(树) 1、关于树 1.1 相关概念 节点:树中每个单独的分支 节点的度:每个节点的子节点数量 树高:树的总层数 根节点:最顶层节点 左子节点&…

Python专题:三、数字和运算(2)

目录 一、数学运算 二、赋值运算 一、数学运算 1、运算符号 加法 减法- 乘法* 除法/ 计算机中浮点数表示有精度限制,Python有限,所以近似取数 2、除法取整// Python2中 整数/整数 值为整数 Python3中 整数/整数 整数or浮点数 //计算除法对结果取…

2024年最适合做的母婴赛道,选品思路揭秘,教你如何选品!

大家好,我是电商花花。 在我印象中,每年都有人唱衰抖音小店不好做了,太卷了,普通人没有机会了,但是现在直播电商时代,很多信息都会片面的,做不好并不是因为不好做,而是因为你做不好…

60*13薪,外包到新疆...去吗?

大家好,我是白露呀。 今天我在牛客上看到一篇帖子,一位网友说自己收到一个 offer ,薪资很高:60k*13,大约一年有近80万。 但是有个要求是外包到新疆的乌鲁木齐,他拿不定主意,就在牛客上发了这个…

Crocoddyl 使用教程(二)

系列文章目录 前言 小车摆杆是另一个经典的控制实例。在这个系统中,一根欠驱动的杆子被固定在一辆一维驱动的小车顶部。游戏的目的是将杆子升到站立位置。 模型如下: https://en.wikipedia.org/wiki/Inverted_pendulum 我们用 表示小车质量、 表示摆杆质…

Agent Hospital: 一种可进化医疗代理人的医院模拟器

论文来源: https://arxiv.org/pdf/2405.02957 1 引言 大型语言模型(LLM)代理在各种任务中表现出了有前景的性能,包括代码生成、信息博弈和问答等。受 LLM 代理能力的启发,一些研究采用它们来模拟人类互动和行为,而不是处理单一任务,例如社交媒体上的信息传播和"Stanford…

Pyside6详细使用教程python之GUI开发

1、首先需要安装Pyside6,终端执行命令: pip3.10 install pyside6 2、你们的一般是 pip install pyside6 2、如下代码创建一个简易程序导入必要的模块 import sys from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton,…

c语言实现贪吃蛇小游戏————附全代码!!!

目录 1.Win32 API 1.1控制台应用程序 1.2控制台的名称,控制台窗口大小 1.3设置控制台光标位置 COORD - 光标坐标 GetStdHandle - 获取句柄 SetConsoleCursorPosition - 设置光标位置 封装一个设置光标的函数 1.4设置控制台光标的属性 CONSOLE_CURSOR_INFO …

HNU-人工智能-作业1

人工智能-作业1 计科210x 甘晴void 第1题 考虑一个实时的在线电话翻译系统,该系统实现英语与日语之间的实时在线翻译,讨论该系统的性能度量,环境,执行器,感知器,并对该环境的属性进行分析。(10…

【Android】源码解析Activity的结构分析

源码解析Activity的结构分析 目录 1、Activity、View、Window有什么关联?2、Activity的结构构建流程3 源码解析Activity的构成 3.1 Activity的Attach方法3.2 Activity的OnCreate 4、WindowManager与View的关系总结 1、一个Activity对应几个WindowManage&#xff0…

Java 中的 HTTP 客户端库OkHttp、Apache HttpClient和HttpUrlConnection

大家好,我是G探险者。 项目开发里面经常会有这么一种场景:与服务器进行 HTTP 通信。一般存在于服务间远程调用的场景 Java 生态系统提供了多种 HTTP 客户端库,每种都有其自己的特点、优势和适用场景。 本文将介绍几种主要的 Java HTTP 客户…

基于Springboot的校园招聘系统(有报告)。Javaee项目,springboot项目。

演示视频: 基于Springboot的校园招聘系统(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构&…