zookeeper - session建立(4)

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 概述    在讲解完zookeeper核心的选举部分的功能逻辑之后,另外一个我个人觉得需要理解的就是zookeeper的client-server之间的连接的建立过程,因为除了zookeeper各个节点之间的通信外,另外一大块就是zookeeper作为server端与client端的交互,包括之前的连接建立以及后续的各种操作命令入get/set等操作,这个博文专注于讲清楚前面部分的概念,后面部分的逻辑会有专门的一篇博文来阐述。

概述

    在讲解完zookeeper核心的选举部分的功能逻辑之后,另外一个我个人觉得需要理解的就是zookeeper的client-server之间的连接的建立过程,因为除了zookeeper各个节点之间的通信外,另外一大块就是zookeeper作为server端与client端的交互,包括之前的连接建立以及后续的各种操作命令入get/set等操作,这个博文专注于讲清楚前面部分的概念,后面部分的逻辑会有专门的一篇博文来阐述。

    当然由于现在对于zookeeper的访问已经有很多开源的实现,排在首位的应该就是Curator了(最早介绍这个东西给我的还是我在车来了的同事袁翔,感谢当初带我入门),大部分情况我们使用的都是它封装的高级API,但是其实如果我们只是使用它的高级API而没有细究底层,我们还是不知道client-server之间的交互细节的,所以为了能够更直观的知道细节,我就在网上找了一个demo,基于这个demo我们可以开始开始我们的分析了。

img_c4c58b52ff41a697713e21a89a7fbf2c.png
zookeeper-api

说明

    上面中我们看到的client通过new ZooKeeper的api创建了server的连接,然后开始的一系列操作,所以我们的源码分析也从这个地方开始。


zookeeper-session连接


Session建立 - client端

    通过demo我们看出来,client连接zookeeper的server端其实就是创建了zookeeper对象。

    创建zookeeper对象,核心的点是创建了ClientXnxn对象,该对象内部包含两个核心对象,分别是sendThread和eventThread。

    启动zookeeper对象,实际上是启动sendThread和eventThread。当然我们关注的是sendThread这部分的工作,基本上建立连接(session的建立)也就是它在玩转的。

    在sendThread当中我们需要处理各种连接事件,譬如注册OP_CONNECT/OP_WRITE/

OP_READ等相关事件。


img_4cd252e61a958fdcf929afb1a1fcad39.png
session-client-1

说明:

    Zookeeper当中主要是创建了ClientXnxn对象并进行启动,其中ClientCnxn对象内部主要对象是两个线程,分别是是sendThread和eventThread,其中sendThread负责连接server。


img_cc79bb23adb9f6d42aa81a300ee4830a.png
session-client-2

说明:

    很明显的创建两个线程的逻辑,一个是sendThread,一个是eventThread。我们关注sendThread的run部分逻辑。


img_4febddeef696cef970f7c572ea04a1b7.png
session-sendThread-1

说明:

    sendThread关联的几个对象包括sessionId,outgoingQueue等。

    sendThread内部如果判断clientCnxnSocket没有建立连接,就会开始尝试建立连接。

    我们关注的应该就是建立连接的过程,关注startConnect部分逻辑。


img_f031e3935c225ff8e728f0616136d1f2.png
session-sendThread-2

说明:

    继续跟进connect部分的逻辑


img_425162369abf117363a04ae71edfaba7.png
session-sendThread-3

说明:

    继续跟进registerAndConnect部分的逻辑


img_2519696e7478c6b12ab287cf083a0562.png
session-sendThread-4

说明:

    首先将socket注册到selector当中并关注OP_CONNECT动作,这样异步连接成功的过程中就可以捕捉到事件了。

    如果立即连接成功以后就直接进入后续处理了,关注一下primeConnection这个动作,在异步连接成功后也会执行这个函数的。


img_a14b8f194388d96354862ebdebb45a3f.png
session-sendThread-5

说明:

    连接成功我们开始发送相关报文给server端,其中发送是通过放到outgoing队列中,有专门的发送线程负责发送。

    其实发送了两种报文,但是不知道前面的报文是什么东西,看着像各种watch。

    最后最重要的部分在于connectionPrimed部分操作,其实就是注册了OP_READ和OP_WRITE事件到selector当中了。


img_5e0fb0aa4de62dac98de26f5746dbb0d.png
session-sendThread-6

说明:

    其实这个run逻辑是在sendThread当中执行的,我们真正关心的部分逻辑是在doTransport部分,里面其实是对异步连接成功的处理。


img_fa991e77f3fd5ee77c2bf797e3c4c6b3.png
session-sendThread-7

说明:

    进入doTransport的逻辑我们看到了selector的执行部分,其中select返回的就是感兴趣的事件,我们在registerAndConnect逻辑当中注册了OP_CONNECT事件,所以假设异步连接成功了那么我们就再次进入了sendThread.primeConnection的逻辑。

    在处理OP_CONNECT事件逻辑,sendThread.primeConnection的逻辑其实就是在发送package报文。    

    在处理OP_READ和OP_WRITE的逻辑,进入的其实是doIO部分的逻辑。


img_f856b4f5afd79ffcbf7a1a71845fa76f.png
session-sendThread-8

说明:

    处理读事件也是一件挺有意思的事情,基本上你会看到ByteBuffer的各种用法,这里读取的逻辑其实很简单,先读取4Byte的数据长度,然后再读取剩余的实际报文数据。

    incomingBuffer一开始读取的是报文长度,在readLnegth()内部其实就是读取实际数据,根据sock.read(incomingBuffer)获取报文的长度。


img_9c34c08d9ee8a624488b2940657cbe0a.png
session-sendThread-9

说明:

    处理写事件,基本上就是发送报文,细节没仔细关注。


Session建立 - server端


    server端其实就是接收client端的连接,接受连接部分的逻辑似乎有点绕,所以我默认就从server端已经接受了连接并开始处理报文的逻辑开始。

    通过整个逻辑的串联了解下server对报文请求的处理,其实整个处理过程类似pipeLine的过程,由PrepRequestProcessor、SyncRequestProcessor、FinalRequestProcessor三者进行的串联。


img_ed9cfbced7dd3ba2449606f1d5e86ef6.png
session-server-1

说明:

    开始进入处理connect请求部分的逻辑,入口函数已经很明显了。


img_df9e36b623cc132dbd2032f83a3d948a.png
session-server-2

说明:

    进入创建session部分的逻辑,注意在这里生成了cnxn对象,session密码,超时时间等。


img_0cf3fd732630f52b3bd58197b7573c59.png
session-server-3

说明:

    创建session其实一个异步过程,这了我们生成了一个Request对象,然后提交这个Request对象。


img_5661265f1c94758688d27dcec5051253.png
session-server-4

说明:

    首先我们通过PrepRequestProcessor操作进行第一波处理,processRequest操作其实把request提交到一个队列当中submittedRequests当中,具体的消费处理逻辑看下一个逻辑代码。


img_71b79f333032dc1d99acec622589c436.png
session-server-5

说明:

    没错,这里开始进行第一波处理了,看函数就是PrepRequestProcessor进行处理,具体处理逻辑往后继续看。


img_8aaa09fe43bbe221eb00bbad245b3a82.png
session-server-6

说明:

    其实这个地方我们基本上知道了zookeeper处理请求的核心逻辑代码,我们只是现在关心session的create事件而已。


img_714cc29cbf6685cc2608ac08c9eeb0c9.png
session-server-7

说明:

    这里我们看到createSession部分的逻辑,继续关注pRequest2Txn逻辑。


img_c3adf7978a0b1fd520954d77411c74e0.png
session-server-8

说明:

    我们将进行下一步下一步处理,至于nextProcessor从哪里来的呢,可以看下一个截图。

其实nextProcessor其实是syncProcessor。


img_865a250882c45fb1f64d69c0d46f890d.png
session-server-9

说明:

    基本上可以看出来了,PrepRequestProcessor、SyncRequestProcessor、FinalRequestProcessor。


img_4fdfd7f136b4cc2df059a792a9dfb769.png
session-server-10

说明:

    只是把任务简单的提交了另外一个queue当中,也就是queuedRequests当中。


img_9b1a75dfde10be73d09f6c906c69ebed.png
session-server-11

说明:

    take任务继续下一步处理,这个还在SyncRequestProcessor当中,我们关注其实是flush动作,继续看下图的代码。



img_939f8f73f527014b83faa5afa9f89e2c.png
session-server-12

说明:

    其实flush里面最后还是将任务提交到给FinalRequestProcessor进行处理。


img_61a047dc29553faac7b6024d3531c247.png
session-server-13

说明:

    进入zks.processTxn的逻辑,这部分代码其实很多,所以只截取了其中一部分。


img_2e56051a663b81fc41f9fc489fae0cce.png
session-server-14

说明:

    把session加入到全局session当中。


img_03a9a5fa2c539aeaab993db443abd817.png
session-server-15

说明:

    真正完成session初始的入口函数。

img_0bca3c2dc1cb8e56f18cf4d7a7ff43f1.png
session-server-16

说明:

    一开始通过serverCnxnFactory.registerConnection将session注册到server端,将session创建的结果发送回client端。

img_5df716ad2ffa406821f37831bbf238fa.png
session-server-17

说明:

    在server端维持新建的session对象,但是我暂时也不知道干嘛。我们在创建ServerCnxnFactory的过程中会生成server端负责accept连接,这部分到时候后面再继续补充。


参考文献

使用ZooKeeper Java API编程

Zookeeper源码分析之二Session建立

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
目录
相关文章
|
28天前
|
监控 负载均衡 Cloud Native
ZooKeeper分布式协调服务详解:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入剖析ZooKeeper分布式协调服务原理,涵盖核心概念如Server、Client、ZNode、ACL、Watcher,以及ZAB协议在一致性、会话管理、Leader选举中的作用。讨论ZooKeeper数据模型、操作、会话管理、集群部署与管理、性能调优和监控。同时,文章探讨了ZooKeeper在分布式锁、队列、服务注册与发现等场景的应用,并在面试方面分析了与其它服务的区别、实战挑战及解决方案。附带Java客户端实现分布式锁的代码示例,助力提升面试表现。
123 2
|
4月前
|
消息中间件 Java 网络安全
JAVAEE分布式技术之Zookeeper的第一次课
JAVAEE分布式技术之Zookeeper的第一次课
71 0
|
2月前
|
监控 NoSQL Java
Zookeeper分布式锁
Zookeeper分布式锁
90 1
|
4月前
|
监控 Dubbo Java
深入理解Zookeeper系列-2.Zookeeper基本使用和分布式锁原理
深入理解Zookeeper系列-2.Zookeeper基本使用和分布式锁原理
63 0
|
4月前
|
NoSQL 中间件 API
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)(下)
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)
84 2
|
4月前
|
NoSQL Java API
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)(上)
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)
75 0
|
3天前
|
存储 大数据 Apache
深入理解ZooKeeper:分布式协调服务的核心与实践
【5月更文挑战第7天】ZooKeeper是Apache的分布式协调服务,确保大规模分布式系统中的数据一致性与高可用性。其特点包括强一致性、高可用性、可靠性、顺序性和实时性。使用ZooKeeper涉及安装配置、启动服务、客户端连接及执行操作。实际应用中,面临性能瓶颈、不可伸缩性和单点故障等问题,可通过水平扩展、集成其他服务和多集群备份来解决。理解ZooKeeper原理和实践,有助于构建高效分布式系统。
|
29天前
|
Java 网络安全 Apache
搭建Zookeeper集群:三台服务器,一场分布式之舞
搭建Zookeeper集群:三台服务器,一场分布式之舞
46 0
|
3月前
|
Java Linux Spring
Zookeeper实现分布式服务配置中心
Zookeeper实现分布式服务配置中心
50 0