一、前言

  在前面学习了Zookeeper中服务器的三种角色及其之间的通信,接着学习对于客户端的一次请求,Zookeeper是如何进行处理的。

二、请求处理

  2.1 会话创建请求

  Zookeeper服务端对于会话创建的处理,大体可以分为请求接收、会话创建、预处理、事务处理、事务应用和会话响应六大环节,其大体流程如


  1. 请求接收

  (1) I/O层接收来自客户端的请求。NIOServerCnxn维护每一个客户端连接,客户端与服务器端的所有通信都是由NIOServerCnxn负责,其负责统一接收来自客户端的所有请求,并将请求内容从底层网络I/O中完整地读取出来。

  (2) 判断是否是客户端会话创建请求。每个会话对应一个NIOServerCnxn实体,对于每个请求,Zookeeper都会检查当前NIOServerCnxn实体是否已经被初始化,如果尚未被初始化,那么就可以确定该客户端一定是会话创建请求。

  (3) 反序列化ConnectRequest请求。一旦确定客户端请求是否是会话创建请求,那么服务端就可以对其进行反序列化,并生成一个ConnectRequest载体。

  (4) 判断是否是ReadOnly客户端。如果当前Zookeeper服务器是以ReadOnly模式启动,那么所有来自非ReadOnly型客户端的请求将无法被处理。因此,服务端需要先检查是否是ReadOnly客户端,并以此来决定是否接受该会话创建请求。

  (5) 检查客户端ZXID。正常情况下,在一个Zookeeper集群中,服务端的ZXID必定大于客户端的ZXID,因此若发现客户端的ZXID大于服务端ZXID,那么服务端不接受该客户端的会话创建请求。

  (6) 协商sessionTimeout。在客户端向服务器发送超时时间后,服务器会根据自己的超时时间限制最终确定该会话超时时间,这个过程就是sessionTimeout协商过程。

  (7) 判断是否需要重新激活创建会话。服务端根据客户端请求中是否包含sessionID来判断该客户端是否需要重新创建会话,若客户单请求中包含sessionID,那么就认为该客户端正在进行会话重连,这种情况下,服务端只需要重新打开这个会话,否则需要重新创建。

  2. 会话创建

  (1) 为客户端生成sessionID。在为客户端创建会话之前,服务端首先会为每个客户端分配一个sessionID,服务端为客户端分配的sessionID是全局唯一的。

  (2) 注册会话。向SessionTracker中注册会话,SessionTracker中维护了sessionsWithTimeout和sessionsById,在会话创建初期,会将客户端会话的相关信息保存到这两个数据结构中。

  (3) 激活会话。激活会话涉及Zookeeper会话管理的分桶策略,其核心是为会话安排一个区块,以便会话清理程序能够快速高效地进行会话清理。

  (4) 生成会话密码。服务端在创建一个客户端会话时,会同时为客户端生成一个会话密码,连同sessionID一同发给客户端,作为会话在集群中不同机器间转移的凭证。

  3. 预处理

  (1) 将请求交给PrepRequestProcessor处理器处理。在提交给第一个请求处理器之前,Zookeeper会根据该请求所属的会话,进行一次激活会话操作,以确保当前会话处于激活状态,完成会话激活后,则提交请求至处理器。

  (2) 创建请求事务头。对于事务请求,Zookeeper会为其创建请求事务头,服务端后续的请求处理器都是基于该请求头来识别当前请求是否是事务请求,请求事务头包含了一个事务请求最基本的一些信息,包括sessionID、ZXID(事务请求对应的事务ZXID)、CXID(客户端的操作序列)和请求类型(如create、delete、setData、createSession等)等。

  (3) 创建请求事务体。由于此时是会话创建请求,其事务体是CreateSessionTxn。

  (4) 注册于激活会话。处理由非Leader服务器转发过来的会话创建请求。

  4. 事务处理

  (1) 将请求交给ProposalRequestProcessor处理器。与提议相关的处理器,从ProposalRequestProcessor开始,请求的处理将会进入三个子处理流程,分别是Sync流程、Proposal流程、Commit流程。

  Sync流程

  使用SyncRequestProcessor处理器记录事务日志,针对每个事务请求,都会通过事务日志的形式将其记录,完成日志记录后,每个Follower都会向Leader发送ACK消息,表明自身完成了事务日志的记录,以便Leader统计每个事务请求的投票情况。

  Proposal流程

  每个事务请求都需要集群中过半机器投票认可才能被真正应用到内存数据库中,这个投票与统计过程就是Proposal流程。

    · 发起投票。若当前请求是事务请求,Leader会发起一轮事务投票,在发起事务投票之前,会检查当前服务端的ZXID是否可用。

    · 生成提议Proposal。若ZXID可用,Zookeeper会将已创建的请求头和事务体以及ZXID和请求本身序列化到Proposal对象中,此Proposal对象就是一个提议。

    · 广播提议。Leader以ZXID作为标识,将该提议放入投票箱outstandingProposals中,同时将该提议广播给所有Follower。

    · 收集投票。Follower接收到Leader提议后,进入Sync流程进行日志记录,记录完成后,发送ACK消息至Leader服务器,Leader根据这些ACK消息来统计每个提议的投票情况,当一个提议获得半数以上投票时,就认为该提议通过,进入Commit阶段。

    · 将请求放入toBeApplied队列中。

    · 广播Commit消息。Leader向Follower和Observer发送COMMIT消息。向Observer发送INFORM消息,向Leader发送ZXID。

  Commit流程

    · 将请求交付CommitProcessor。CommitProcessor收到请求后,将其放入queuedRequests队列中。

    · 处理queuedRequest队列请求。CommitProcessor中单独的线程处理queuedRequests队列中的请求。

    · 标记nextPending。若从queuedRequests中取出的是事务请求,则需要在集群中进行投票处理,同时将nextPending标记位当前请求。

    · 等待Proposal投票。在进行Commit流程的同时,Leader会生成Proposal并广播给所有Follower服务器,此时,Commit流程等待,直到投票结束。

    · 投票通过。若提议获得过半机器认可,则进入请求提交阶段,该请求会被放入commitedRequests队列中,同时唤醒Commit流程。

    · 提交请求。若commitedRequests队列中存在可以提交的请求,那么Commit流程则开始提交请求,将请求放入toProcess队列中,然后交付下一个请求处理器:FinalRequestProcessor。

  5. 事务应用

  (1) 交付给FinalRequestProcessor处理器。FinalRequestProcessor处理器检查outstandingChanges队列中请求的有效性,若发现这些请求已经落后于当前正在处理的请求,那么直接从outstandingChanges队列中移除。

  (2) 事务应用。之前的请求处理仅仅将事务请求记录到了事务日志中,而内存数据库中的状态尚未改变,因此,需要将事务变更应用到内存数据库。

  (3) 将事务请求放入队列commitProposal。完成事务应用后,则将该请求放入commitProposal队列中,commitProposal用来保存最近被提交的事务请求,以便集群间机器进行数据的快速同步。

  6. 会话响应

  (1) 统计处理。Zookeeper计算请求在服务端处理所花费的时间,统计客户端连接的基本信息,如lastZxid(最新的ZXID)、lastOp(最后一次和服务端的操作)、lastLatency(最后一次请求处理所花费的时间)等。

  (2) 创建响应ConnectResponse。会话创建成功后的响应,包含了当前客户端和服务端之间的通信协议版本号、会话超时时间、sessionID和会话密码。

  (3) 序列化ConnectResponse。

  (4) I/O层发送响应给客户端。

  2.2 SetData请求

  服务端对于SetData请求大致可以分为四步,预处理、事务处理、事务应用、请求响应。

  1. 预处理

  (1) I/O层接收来自客户端的请求。

  (2) 判断是否是客户端"会话创建"请求。对于SetData请求,按照正常事务请求进行处理。

  (3) 将请求交给PrepRequestProcessor处理器进行处理。

  (4) 创建请求事务头。

  (5) 会话检查。检查该会话是否有效。

  (6) 反序列化请求,并创建ChangeRecord记录。反序列化并生成特定的SetDataRequest请求,请求中包含了数据节点路径path、更新的内容data和期望的数据节点版本version。同时根据请求对应的path,Zookeeper生成一个ChangeRecord记录,并放入outstandingChanges队列中。

  (7) ACL检查。检查客户端是否具有数据更新的权限。

  (8) 数据版本检查。通过version属性来实现乐观锁机制的写入校验。

  (9) 创建请求事务体SetDataTxn。

  (10) 保存事务操作到outstandingChanges队列中。

  2. 事务处理

  对于事务请求,服务端都会发起事务处理流程。所有事务请求都是由ProposalRequestProcessor处理器处理,通过Sync、Proposal、Commit三个子流程相互协作完成。

  3. 事务应用

  (1) 交付给FinalRequestProcessor处理器。

  (2) 事务应用。将请求事务头和事务体直接交给内存数据库ZKDatabase进行事务应用,同时返回ProcessTxnResult对象,包含了数据节点内容更新后的stat。

  (3) 将事务请求放入commitProposal队列。

  4. 请求响应

  (1) 创建响应体SetDataResponse。其包含了当前数据节点的最新状态stat。

  (2) 创建响应头。包含当前响应对应的事务ZXID和请求处理是否成功的标识。

  (3) 序列化响应。

  (4) I/O层发送响应给客户端。

  2.3 GetData请求

  服务端对于GetData请求的处理,大致分为三步,预处理、非事务处理、请求响应。

  1. 预处理

  (1) I/O层接收来自客户端的请求。

  (2) 判断是否是客户端"会话创建"请求。

  (3) 将请求交给PrepRequestProcessor处理器进行处理。

  (4) 会话检查。

  2. 非事务处理

  (1) 反序列化GetDataRequest请求。

  (2) 获取数据节点。

  (3) ACL检查。

  (4) 获取数据内容和stat,注册Watcher。

  3. 请求响应

  (1) 创建响应体GetDataResponse。响应体包含当前数据节点的内容和状态stat。

  (2) 创建响应头。

  (3) 统计处理。

  (4) 序列化响应。

  (5) I/O层发送响应给客户端。

三、总结

  本篇博文讲解了Zookeeper服务端对于客户端不同请求的处理的具体流程,可能从文字上看步骤会显得相对枯燥,但是会为之后的源码分析打下很好的基础,谢谢各位园友的观看~

【分布式】Zookeeper请求处理的更多相关文章

  1. mysql 和 hive 和分布式zookeeper和HBASE分布式安装教程

    一,mysql 安装mysql5.7完整教程1. yum -y install mysql-server直接执行语句后等待就好已安装: mysql-community-server.x86_64 0: ...

  2. java架构之路-(分布式zookeeper)zookeeper真实使用场景

    上几次博客,我说了一下Zookeeper的简单使用和API的使用,我们接下来看一下他的真实场景. 一.分布式集群管理✨✨✨ 我们现在有这样一个需求,请先抛开Zookeeper是集群还是单机的概念,下面 ...

  3. Zookeeper请求处理原理分析

    Zookeeper是可以存储数据的,所以我们可以把它理解一个数据库,实际上它的底层原理本身也和数据库是类似的. 一.数据库的原理 我们知道,数据库是用来存储数据的,只是数据可以存储在内存中或磁盘中.而 ...

  4. SpringBoot整合分布式ZooKeeper和Dubbo

    ZooKeeper ZooKeeper是一个分布式的,开放远吗的分布式应用程序协调服务.它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护.域名服务.分布式同步.组服务等. 服务提供者 ...

  5. java架构之路-(分布式zookeeper)zookeeper集群配置和选举机制详解

    上次博客我们说了一下zookeeper的配置文件,以及命令的使用https://www.cnblogs.com/cxiaocai/p/11597465.html.我们这次来说一下我们的zookeepe ...

  6. Zookeeper 源码(七)请求处理

    Zookeeper 源码(七)请求处理 以单机启动为例讲解 Zookeeper 是如何处理请求的.先回顾一下单机时的请求处理链. // 单机包含 3 个请求链:PrepRequestProcessor ...

  7. 【分布式】Zookeeper服务端启动

    一.前言 前面已经了解了Zookeeper会话相关知识点,接着来学习Zookeeper服务端相关细节. 二.服务端 服务端整体架构如下 Zookeeper服务器的启动,大致可以分为以下五个步骤 1. ...

  8. (转)ZooKeeper伪分布式集群安装及使用

    转自:http://blog.fens.me/hadoop-zookeeper-intro/ 前言 ZooKeeper是Hadoop家族的一款高性能的分布式协作的产品.在单机中,系统协作大都是进程级的 ...

  9. ZooKeeper:win7上安装单机及伪分布式安装

    zookeeper是一个为分布式应用所设计的分布式的.开源的调度服务,它主要用来解决分布式应用中经常遇到的一些数据管理问题,简化分布式应用,协调及其管理的难度,提高性能的分布式服务. 本章的目的:如何 ...

随机推荐

  1. 干货分享:让你分分钟学会 JS 闭包

    闭包,是 Javascript 比较重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,很难从定义去理解它.因此,本文不会对闭包的概念进行大篇幅描述 ...

  2. ASP.NET Aries 入门开发教程7:DataGrid的行操作(主键操作区)

    前言: 抓紧勤奋,再接再励,预计共10篇来结束这个系列. 上一篇介绍:ASP.NET Aries 入门开发教程6:列表数据表格的格式化处理及行内编辑 本篇介绍主键操作区相关内容. 1:什么时候有默认的 ...

  3. MVVM模式和在WPF中的实现(二)数据绑定

    MVVM模式解析和在WPF中的实现(二) 数据绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...

  4. 我为什么要写LeetCode的博客?

    # 增强学习成果 有一个研究成果,在学习中传授他人知识和讨论是最高效的做法,而看书则是最低效的做法(具体研究成果没找到地址).我写LeetCode博客主要目的是增强学习成果.当然,我也想出名,然而不知 ...

  5. Android raw to bmp

    Android raw 格式转 bmp 图像 raw 保存的为裸数据,转换时都需要把它转成RGBA 的方式来显示.其中: 8位RAW: 四位RGBA 来表示一位灰度; 24位RAW: 三位RGB相同, ...

  6. Java 8 的 Nashorn 脚本引擎教程

    本文为了解所有关于 Nashorn JavaScript 引擎易于理解的代码例子. Nashorn JavaScript 引擎是Java SE 8的一部分,它与其它像Google V8 (它是Goog ...

  7. Hive安装配置指北(含Hive Metastore详解)

    个人主页: http://www.linbingdong.com 本文介绍Hive安装配置的整个过程,包括MySQL.Hive及Metastore的安装配置,并分析了Metastore三种配置方式的区 ...

  8. 2Sum

    用哈希表(unordered_map)使得时间复杂度从O(n*n)降到O(n),空间复杂度从O(1)增到O(n):一边找一边插入哈希表 注意 在C++11以前要使用unordered_map需要 #i ...

  9. 如何用Java类配置Spring MVC(不通过web.xml和XML方式)

    DispatcherServlet是Spring MVC的核心,按照传统方式, 需要把它配置到web.xml中. 我个人比较不喜欢XML配置方式, XML看起来太累, 冗长繁琐. 还好借助于Servl ...

  10. C# 工厂模式+虚方法(接口、抽象方法)实现多态

    面向对象语言的三大特征之一就是多态,听起来多态比较抽象,简而言之就是同一行为针对不同对象得到不同的结果,同一对象,在不同的环境下得到不同的状态. 实例说明: 业务需求:实现一个打开文件的控制台程序的d ...