聊聊Zookeeper技术内幕之客户端与SetData请求处理

聊聊,zookeeper,技术,内幕,客户端,setdata,请求,处理 · 浏览次数 : 44

小编点评

**客户端会话创建到网络连接、请求处理** 1. **ZooKeeper 构造函数**执行,初始化**ClientWatchManager**、**HostProvider**、**ClientCnxn**等核心组件。 2. **ClientCnxn**初始化发送和接收队列,创建**SendThread**和**EventThread**。 3. **SendThread**管理客户端与服务端的网络通信,并处理**WriteRequest**。 4. **EventThread**处理服务端推送的**EventRecord**,并进行相应的处理。 5. 客户端会话检查,并根据会话状态处理请求。 **核心组件介绍** * **ClientWatchManager**:管理客户端连接,监控会话状态。 * **HostProvider**:维护服务器地址列表。 * **ClientCnxn**:管理客户端网络连接。 * **SendThread**:处理客户端发送的请求。 * **EventThread**:处理服务端推送的事件。

正文

从客户端会话创建到网络连接、请求处理,简单的叙述下流程与逻辑

客户端

客户端是开发人员使用ZooKeeper最主要的途径,ZooKeeper的客户端主要由以下几个核心组件组成。

  • ZooKeeper实例:客户端的入口。
  • ClientWatchManager:客户端Watcher管理器。
  • HostProvider:客户端地址列表管理器(管理服务器地址信息)。
  • ClientCnxn:客户端核心线程,其内部又包含两个线程,即SendThread和EventThread。前者是一个I/O线程,主要负责ZooKeeper客户端和服务端之间的网络I/O通信;后者是一个事件线程,主要负责对服务端事件进行处理。

对如上的组件,需要有一个初始化的过程,而这就是Zookeeper构造函数执行的结果。

在初始化阶段中,会做如下的事情:

  1. 初始化Zookeeper对象。
    通过调用ZooKeeper的构造方法来实例化一个ZooKeeper对象,在初始化过程中,会创建一个客户端的Watcher管理器:ClientWatchManager。

  2. 设置会话默认Watcher
    如果在构造方法中传入了一个Watcher对象,那么客户端会将这个对象作为默认Watcher保存在ClientWatchManager中。

  3. 构造Zookeeper服务器地址列表管理器:HostProvider。
    对于构造方法中传入的服务器地址,客户端会将其存放在服务器地址列表管理器HostProvider中。

  4. 创建并初始化客户端网络连接器:ClientCnxn。
    ZooKeeper客户端首先会创建一个网络连接器ClientCnxn,用来管理客户端与服务器的网络交互。另外,客户端在创建ClientCnxn的同时,还会初始化客户端两个核心队列outgoingQueue和pendingQueue,分别作为客户端的请求发送队列和服务端响应的等待队列。

  5. 初始化SendThread和EventThread。
    客户端会创建两个核心网络线程SendThread和EventThread,前者用于管理客户端和服务端之间的所有网络I/O,后者则用于进行客户端的事件处理。同时,客户端还会将ClientCnxnSocket分配给SendThread作为底层网络I/O处理器,并初始化EventThread的待处理事件队列waitingEvents,用于存放所有等待被客户端处理的事件。

Zookeeper的构造函数有蛮多,但最后都是调用此构造函数方法,其参数列表也正是对应着上述的功能模块的初始化。


public ZooKeeper(
        String connectString,
        int sessionTimeout,
        Watcher watcher,
        boolean canBeReadOnly,
        HostProvider hostProvider,
        ZKClientConfig clientConfig
    ) throws IOException {
        LOG.info(
            "Initiating client connection, connectString={} sessionTimeout={} watcher={}",
            connectString,
            sessionTimeout,
            watcher);

        this.clientConfig = clientConfig != null ? clientConfig : new ZKClientConfig();
        this.hostProvider = hostProvider;
        ConnectStringParser connectStringParser = new ConnectStringParser(connectString);

        cnxn = createConnection(
            connectStringParser.getChrootPath(),
            hostProvider,
            sessionTimeout,
            this.clientConfig,
            watcher,
            getClientCnxnSocket(),
            canBeReadOnly);
        cnxn.start();
    }

初始化过程的泳道图如下

image

请求处理(SetData请求)

在Zookeeper中,更新类的操作都属于事务操作,即这个操作需要事务保障的。

服务端对于SetData请求的处理,大体可以分为4大步骤,分别是请求的预处理、事务处理、事务应用和请求响应

流程逻辑大概如下所示:

image

预处理

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

  2. 判断是否是客户端“会话创建”请求。ZooKeeper对于每一个客户端请求,都会检查是否是“会话创建”请求。对于SetData请求,因为此时已经完成了会话创建,因此按照正常的事务请求进行处理。

  3. 将请求交给ZooKeeper的PrepRequestProcessor处理器进行处理。

  4. 创建请求事务头。

  5. 会话检查。客户端会话检查是指检查该会话是否有效,即是否已经超时。如果该会话已经超时,那么服务端就会向客户端抛出SessionExpiredException异常。

  6. 反序列化请求,并创建ChangeRecord记录。面对客户端请求,ZooKeeper首先会将其进行反序列化并生成特定的SetDataRequest请求。SetDataRequest请求中通常包含了数据节点路径path、更新的数据内容data和期望的数据节点版本version。同时,根据请求中对应的path,ZooKeeper会生成一个ChangeRecord记录,并放入outstandingChanges队列中。outstandingChanges队列中存放了当前ZooKeeper服务器正在进行处理的事务请求,以便ZooKeeper在处理后续请求的过程中需要针对之前的客户端请求的相关处理,例如对于“会话关闭”请求来说,其需要根据当前正在处理的事务请求来收集需要清理的临时节点。

  7. ACL检查。由于当前请求是数据更新请求,因此ZooKeeper需要检查该客户端是否具有数据更新的权限。如果没有权限,那么会抛出NoAuthException异常。

  8. 数据版本检查。

  9. 创建请求事务体SetDataTxn。

  10. 保存事务操作到outstandingChanges队列中去。

事务处理

对于事务请求,ZooKeeper服务端都会发起事务处理流程。无论对于会话创建请求还是SetData请求,或是其他事务请求,事务处理流程都是一致的,都是由ProposalRequestProcessor处理器发起,通过Sync、Proposal和Commit三个子流程相互协作完成的。

事务应用

  1. 交付给FinalRequestProcessor处理器。

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

  3. 将事务请求放入队列:commitProposal。

请求响应

  1. 统计处理。

  2. 创建响应体SetDataResponse。SetDataResponse是一个数据更新成功后的响应,主要包含了当前数据节点的最新状态stat。

  3. 创建响应头。

  4. 序列化响应。

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

参考

《从Paxos到Zookeeper:分布式一致性原理与实践 》

zookeeper源码 — 五、处理写请求过程

【Zookeeper】源码分析之请求处理链(三)之SyncRequestProcessor

与聊聊Zookeeper技术内幕之客户端与SetData请求处理相似的内容:

聊聊Zookeeper技术内幕之客户端与SetData请求处理

从客户端会话创建到网络连接、请求处理,简单的叙述下流程与逻辑 ### 客户端 客户端是开发人员使用ZooKeeper最主要的途径,ZooKeeper的客户端主要由以下几个核心组件组成。 - ZooKeeper实例:客户端的入口。 - ClientWatchManager:客户端Watcher管理器。

聊聊Zookeeper的Session会话超时重连

### 概述 简单地说,ZooKeeper的连接与会话就是客户端通过实例化ZooKeeper对象来实现客户端与服务器创建并保持TCP连接的过程。本质上,Session就是一个TCP 长连接。 ### 会话 Session会话的作用: 1. ZK Server 执行任何请求之前,都需要 Client

聊聊我认为的分布式、集群实现关键点

基于常见的中间件(Mysql、ElasticSearch、Zookeeper、Kafka、Redis)等分布式集群设计的机制,自己总结了在在集群设计过程中需要考虑的通用问题。 ### 节点通信机制 主节点的增加、删除、通信机制。 ### 路由算法 即数据路由到哪个节点的策略机制。在集群内有多个节点,

聊聊GLM-4-9B开源模型的微调loss计算

概述 Github官方地址:GLM-4 网上已经有很多关于微调的文章,介绍各种方式下的使用,这里不会赘述。我个人比较关心的是微调时的loss计算逻辑,这点在很多的文章都不会有相关的描述,因为大多数人都是关心如何使用之类的应用层,而不是其具体的底层逻辑,当然咱也说不清太底层的计算。 可了解其它loss

聊聊一个差点被放弃的项目以及近期的开源计划

前言 自从 StarBlog 和 SiteDirectory 之后,我还没写新的关于开源项目的系列,最近又积累了很多想法,正好写一篇博客来总结一下。 关于差点被放弃的项目,就是最近一直在做的单点认证(IdentityServerLite) IdentityServerLite 开发这个项目的起因,是

聊聊 JSON Web Token (JWT) 和 jwcrypto 的使用

哈喽大家好,我是咸鱼。 最近写的一个 Python 项目用到了 jwcrypto 这个库,这个库是专门用来处理 JWT 的,JWT 全称是 JSON Web Token ,JSON 格式的 Token。 今天就来简单入门一下 JWT。 官方介绍:https://jwt.io/introduction

聊聊MySQL是如何处理排序的

在MySQL的查询中常常会用到 order by 和 group by 这两个关键字,它们的相同点是都会对字段进行排序,那查询语句中的排序是如何实现的呢?

聊聊 Linux iowait

哈喽大家好,我是咸鱼。 我们在使用 top 命令来查看 Linux 系统整体 CPU 使用情况的时候,往往看的是下面这一列: %Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 68.0 wa, 0.0 hi, 0.0 si, 0.0 st 其中,man 手册解释 w

聊聊Mybatis框架原理

好久没有写博客了。最近工作中封装了一个类似ORM框架的东西。大概的原理就是将Excel数据初始化到本地sqlite数据库后,通过json配置文件,对数据库的数据做增删改查等操作。 其实大概的思考了下,就是半ORM框架mybatis的逻辑,只是我们自己封装的简陋蛮多。想想有现成的轮子没用,反而是自己写

聊聊Spring的工厂方法与FactoryBean

概述 工厂方法是比较常见,常用的一种设计模式。FactoryBean是Spring提供的一种Bean注入IOC容器的方式。 工厂方法 在做日常开发时,一般都会避免直接new对象,而且将new的操作丢给IOC容器,但对于第三方系统的集成,我们不太好直接丢给IOC容器,此时可以通过工厂模式, 提供一个工