首页 > 编程语言 >Zookeeper Session源码

Zookeeper Session源码

时间:2023-04-05 12:00:37浏览次数:37  
标签:请求 Session 创建 Zookeeper 源码 连接 服务端 客户端

我们说客户端与服务端建立连接交互的时候会创建一个 Session 与之对应,那假设客户端请求来了,服务端是如何处理的?Session 又是如何创建出来的?

我们先来看第一个问题:服务端如何处理客户端发来的请求?

一、如何处理请求

所谓的请求全称是网络请求,涉及到网络就少不了 Socket 通信,ZooKeeper 采取的是 NIO 的方式,提供了一个 NIOServerCnxn 实例来维护每一个客户端的连接,也就是说客户端与服务端的通信都是靠 NIOServerCnxn 这个类来处理的,无非就干两件事:接收客户端的请求以及处理请求(将请求体从网络 I/O 中读出来做处理)。这个处理类的核心方法是doIO(),也就是如下:

public class NIOServerCnxn extends ServerCnxn {
    void doIO(SelectionKey k) throws InterruptedException {
        // ...
    }
}

核心处理类结构已经清晰了,那我们接下来就分析 doIO() 这个方法就好了,我上面说这个方法无非就干两件事:接收请求、处理请求。那如何接收请求呢?请求又分为两种:创建连接的请求和发送数据的请求。

我们逐个分析:

  • 何为创建连接的请求?其实很好理解,就是第一次客户端和服务端通信的时候要建立连接,建立完连接才能发送数据进行真正请求。
  • 何为发送数据的请求?上面创建完连接了才能真正发送数据给服务端。

一言以蔽之就是:客户端要想和服务端通信必须先建立连接才能发送数据,且连接只需要建立一次即可。所以我们会有一个变量: initialized 代表是否初始化完成,也就是代表是否已经建立过连接了。代码如下:

public void 接收请求() {
    if (!initialized) {
        // 还没初始化,那就建立连接
        readConnectRequest();
    } else {
        // 初始化完了,那就发送数据
        readRequest();
    }
}

我们继续分析:readConnectRequest(),也就是如何创建连接?首先我们能明确一点的是创建完连接后肯定要把 initialized 状态变为 true,代表已经建立完成。我们先把这块代码写下:

private void readConnectRequest() throws IOException, InterruptedException, ClientCnxnLimitException {
    // 省略真正建立连接代码
    
    initialized = true;
}

在开始真正建立连接之前,我们肯定都知道一点:客户端会传输一些数据给服务端,但是网络传输都是靠字节数组,所以服务端接收到数据后第一件事就是拿到字节数组进行反序列化,反序列化成一个对象,我们叫这个对象为:ConnectRequest。我们继续完善下代码:

public void 建立连接() {
    // 拿到客户端发来的字节数组
    BinaryInputArchive bia = BinaryInputArchive.getArchive(new ByteBufferInputStream(incomingBuffer));
    ConnectRequest connReq = new ConnectRequest();
    // 反序列化成ConnectRequest对象
    connReq.deserialize(bia, "connect");
}

我们在上一 Session 原理篇的时候说过 Session 是有生命周期的,带时效性的,也就是有过期时间的。那这个过期时间肯定是客户端和服务端建立连接的时候通过客户端发过去的,所以我们反序列化出来的对象里还会有 sessionTimeout 字段,如下:

// 基本验证
int sessionTimeout = connReq.getTimeOut();
int minSessionTimeout = getMinSessionTimeout();
if (sessionTimeout < minSessionTimeout) {
    sessionTimeout = minSessionTimeout;
}
int maxSessionTimeout = getMaxSessionTimeout();
if (sessionTimeout > maxSessionTimeout) {
    sessionTimeout = maxSessionTimeout;
}

很简单的一些验证,就好比我们业务代码中分页一样,都会判断不能小于 1、不能大于最大条数等验证。这个过期时间传给 Server 后,并不是真正的过期时间,因为我们在上一篇中也讲解过了,真实过期时间会被计算为 tickTime 的倍数

有了上面这些参数后我们就可以真正创建 Session 了:

long id = createSession(cnxn, passwd, sessionTimeout);

在开始如何创建 Session 之前,我们先画个流程图:

session-12.png

现在创建 Session 的时机和前置条件都搞懂了,那创建 Session 都需要经过哪些步骤呢?

二、如何创建 Session

其实创建 Session 的原理我们在上一篇都讲解得很清楚了,按照大步骤来划分的话无非就是下面这四步:

  • 按照一定规则为客户端生成 SessionId;
  • Session 的创建以及过期机制;
  • 每次正常 CRUD 以及定时心跳 Ping 都会重新刷新 Session 的过期时间,我们称这个过程为 Session 的激活;
  • Session 到期后如何回收。

本篇不打算详细剖析上面这四步,那样会太占用篇幅,所以我把这四点放到下篇单独讲解,本篇讲解整个脉络,也可以称之为“框架”。比如我们上面讲解了服务端是如何处理请求的,然后现在我们假设 Session 已经创建完成了,“框架”如下:

public void proces () {
    // 1. 接收请求
    // 2. 处理请求
    // 3. 创建Session
    //   3.1 生成SessionId
    //   3.2 Session过期机制
    //   3.3 Session激活
    //   3.4 Session回收
}

上面已经为我们提供好了如何激活 Session 的方法,但是什么时候触发这个方法呢?我们也说了是在正常 CRUD 或者心跳 Ping 的时候会进行激活,在剖析这块代码之前我们先时光倒流,回忆一下最开始我们讲如何处理请求的流程:

public void 接收请求() {
    if (!initialized) {
        // 还没初始化,那就建立连接
        readConnectRequest();
    } else {
        // 初始化完了,那就发送数据
        readRequest();
    }
}

如果没建立过连接,那么就建立连接readConnectRequest();如果之前建立过连接,那就是正常地发送数据(可能是正常的 CRUD,也可能是心跳 Ping 请求)。所以大家肯定突然明白一个事情,那就是我们调用 Session 激活方法的入口就是这里——readRequest(),接下来我们一起看下是如何调用的吧~

标签:请求,Session,创建,Zookeeper,源码,连接,服务端,客户端
From: https://www.cnblogs.com/fxh0707/p/17289085.html

相关文章

  • 多任务版TCP服务端程序开发案例+源码
    Python进阶篇-系列文章全篇......
  • Android 构建工具--AAPT2源码解析(一)
    一、什么是AAPT2在Android开发过程中,我们通过Gradle命令,启动一个构建任务,最终会生成构建产物“APK”文件。常规APK的构建流程如下:(引用自Google官方文档)编译所有的资源文件,生成资源表和R文件;编译Java文件并把class文件打包为dex文件;打包资源和dex文件,生成未签名的APK文件;签名APK生成......
  • flask:cbv源码分析、模板语法、请求与响应、session及源码分析、闪现(flash)、请求扩展
    目录一、cbv源码分析1.1基于类的视图写法1.2源码分析1.3分析源码,查找不传别名的时候为什么函数名会变成别名1.4flask的路由注册使用装饰器,如果写了一个登录认证装饰器,那么应该放在路由装饰器上还是下?1.5dispatch_request讲解1.6知识点总结二、模板语法2.1py2.2html三、请......
  • flask框架02 cbv分析 模板 请求与响应 session 闪现 请求拓展
    今日内容详细目录今日内容详细1cbv分析1.1源码分析2模板2.1py文件2.2html页面3请求与响应4session及源码分析4.1session的使用4.2源码分析5闪现6请求拓展1cbv分析#基于类的视图,写法fromflaskimportFlask,requestfromflask.viewsimportView,MethodView......
  • Spring——springboot启动源码分析
    摘要主要介绍的有关于Spring的Spring的事务注解原理和实战(SpringFramework)一、什么是事务的传播?简单的理解就是多个事务方法相互调用时,事务如何在这些方法间传播。:举个栗子,方法A是一个事务的方法,方法A执行过程中调用了方法B,那么方法B有无事务以及方法B对事务的要求不同都会对......
  • 深入剖析 RocketMQ 源码 - 负载均衡机制
    一、引言RocketMQ是一款优秀的分布式消息中间件,在各方面的性能都比目前已有的消息队列要好,RocketMQ默认采用长轮询的拉模式,单机支持千万级别的消息堆积,可以非常好的应用在海量消息系统中。RocketMQ主要由Producer、Broker、Consumer、Namesvr等组件组成,其中Producer负责生产消......
  • cbv分析、模板、请求与响应、session及源码分析、闪现、请求扩展
    cbv分析#基于类的视图,写法fromflaskimportFlask,requestfromflask.viewsimportView,MethodViewapp=Flask(__name__)app.debug=True#视图类,继承MethodView,类中写跟请求方式同名的方法即可,之前学的所有都一致classIndexView(MethodView):defget(s......
  • SpringBoot——注解@SpringBootConfiguration源码分析
    摘要SpringMVC是一个MVC开源框架,用来代替Struts。它是Spring项目里面的一个重要组成部分,能与SpringIOC容器紧密结合,以及拥有松耦合、方便配置、代码分离等特点,让JAVA程序员开发WEB项目变得更加容易。SpringMVC的异常处理?1.web.xml中异常处理通常为了给用户提供良好......
  • Spring——spring MVC源码分析与实战
    摘要SpringWebMVC是基于ServletAPI构建的原始Web框架,基于servlet3.0的规范实现的web框架。springmvc主要实现请求的接受,请求解析,请求响应等步骤。本文将详细的介绍springMVC的源码和springMVC的启动流程与相关原理。一、传统springMVC执行流程用户发送请求至前端控制器Dispa......
  • JDK源码——集合类Iterator、 Collection类
    摘要主要是讲解这个集合的原理类相关的类。参看:https://zhuanlan.zhihu.com/p/165393520这个图由Map指向Collection的Produces并不是说Map是Collection的一个子类(子接口),这里的意思是指Map的KeySet获取到的一个视图是Collection的子接口。我们可以看到集合有两个基本接口:Map和Collec......