Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >ZooKeeper 会话的秘密

ZooKeeper 会话的秘密

作者头像
HelloGitHub
发布于 2021-05-08 02:55:22
发布于 2021-05-08 02:55:22
2.4K10
代码可运行
举报
文章被收录于专栏:HelloGitHubHelloGitHub
运行总次数:0
代码可运行

本文作者:HelloGitHub-老荀

Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费开源、有趣、入门级的 ZooKeeper 教程,面向有编程基础的新手。

项目地址:https://github.com/HelloGitHub-Team/HelloZooKeeper

前一篇文章我们介绍了 Follower 或 Observer 是如何同 Leader 同步数据的,以及 ACL 的介绍、使用和原理。这章我们将正式学习有关 session 的内容,具体客户端怎么同服务端保持心跳?服务端不同节点之间是如何保持心跳?

一、客户端会话的秘密

会话,即 session,这个词语或者说概念很多地方都有用到,在 ZK 中会话指的是两个不同的机器建立了网络连接后,就可以说他们之间创建了一个会话。ZK 的会话是有超时的概念的,当会话超时后,会由服务端主动关闭,当然客户端也可以主动请求服务端想要关闭会话。你可能会问,为什么要搞这个麻烦,直接两边连上一直用不就好了吗?有了会话这个概念就是为了防止,在建立连接后,有些客户端不常使用,早点关闭连接可以节省资源。

1.1 鸡太美的一天

我发现我好久没有 cue 鸡太美了,这次就让他再 C 位出道一次吧。

我们的鸡太美每天起床后,日常发微博、直播、跳舞、打篮球,很多事务都需要去办事处办理。

所以第一件事情就是去办事处找马果果(现在就假设马果果一个办事处)申请使用办事处(建立连接,创建会话)

马果果会为鸡太美创建一个 ID,就是会话 ID,这个 ID (我这里假设是 19980802) 和鸡太美会进行绑定,而鸡太美在申请的同时还需要告诉马果果自己最长的超时时间是多久,我这里假设是 6000 毫秒。

马果果这边会记录下来:

马果果开张的时候自己本身也有一个会话的检查间隔,就是配置在 zoo.cfg 中的 tickTime 选项,我这里假设是 3000 毫秒。马果果在开张的时候会计算出一个时间轴,这个时间轴的间隔是固定的,并且不会改变。

然后马果果会通过鸡太美的 6000 以及当前的时间戳结合时间轴,计算出一个鸡太美会话超时时间点

然后会记录下来:

记录完,就算鸡太美会话创建成功了。

马果果这边会遵循这个时间轴的节点定期对会话进行检查,假设现在的时间进行到鸡太美的时间点了

马果果会把在这个时间点的会话全部取出(记得我们上面说过,可以是多个吗?)

然后会根据 ID 信息找到对应的村民,一个个通知他们会话关闭了。

你可能会问现在因为鸡太美超时时间是 6000,而马果果超时检查是 3000,正好是整数倍,如果超时时间不是整数倍呢?要不说我们的马果果同志好学上进呢,他早就想到啦,所以设计了一个算法,无论村民的超时时间是怎么样,都会向下取整找到马果果设置的检查点。

假设鸡太美的超时间是 5900

再比如鸡太美的超时时间是 6500

所以看到了吧,以马果果的 3000 为例,只要小于 3000 的都按照 0 来算,小于 6000 的按照 3000 来算,小于 9000 的按照 6000 来算,以此类推,所以只要马果果自己的检查时间间隔确定了之后,无论是哪个村民设置了什么样的超时时间都能被向下取整至最近的统一检查点。这样马果果检查的时候就不会有太大的负担,可以统一对村民的超时时间进行检查。

但是这么做一定会造成客户端的超时时间是有误差的(通常是比设置的要短一点),减少这个误差的方式就是减小马果果的检查间隔,也就是 tickTime 参数(默认是 2000,已经够用了我觉得)。

马果果的会话管理不会只有鸡太美一个人,我们来看看有多个村民的会话管理页长什么样吧

可以看到使用了三个哈希表去记录这些映射关系,画到时间轴是这样的

所以当时间进行到 25317000 的时候,对应三个村民就超时了,25320000 时另外两个村民就超时了。

这里我还得说下其实会话 ID 在马果果这边办事处开张后就会根据当前时间戳和 myid 初始化出一个基数,举个例子可能是 987434245 类似这种数字,之后每一个村民过来分配会话 ID 的时候,只是对这个数字不停的加 1,所以不会出现乱七八糟无序的数字,图中的数字举例仅仅是我个人的玩梗癖好,和实际情况不符~

但是这样的话,鸡太美岂不是每次 6000 毫秒就超时了吗?这当然不可能,因为村民的每一次任意的操作(增删改查)都会刷新该超时时间戳,具体怎么做的呢?我们一起来看下,假设红色箭头是会话刚创建时马果果鸡太美计算出来的超时时间,假设在绿色箭头时间戳的地方,鸡太美执行了任意操作。

马果果会根据当前时间戳(绿色箭头处)加上鸡太美之前设置的超时时间(6000),重新计算出新的超时时间:

然后对会话管理页的数据进行修改,我仍然以多个村民的例子讲解

更新前:

更新后:

这个更新的过程可以被称为会话激活

1.2 心跳检测

猿话一下,除了客户端每次的正常操作会刷新超时时间以外,客户端仍然需要一个机制去保持住这个会话,这个机制就是我们平时听到过的心跳检测,原理是每次客户端启动的时候也会设置一个心跳检测的间隔时间,在后台一直会去判断最后一次发送的时间戳和当前时间是否超过了该心跳检测的间隔,如果超过了就会发送一个名为 PING 的请求,由于刚刚我们说了客户端的任意操作都会刷新该超时时间,PING 也不例外,有了这个心跳机制就可以让客户端保持住和服务端的会话状态。而服务端收到 PING,除了刷新超时时间会简单的回复一个 PING 给客户端,而客户端收到服务端的 PING 会直接丢弃不需要任何其他操作。

我们以 Java 客户端为例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZooKeeper client = new ZooKeeper("127.0.0.1:2181", 12000, null);

假设超时时间设置 12000 毫秒,那么客户端的心跳间隔就是 4000 毫秒,计算过程如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
12000 * 2 / 3 / 2 = 4000 // 这个公式是代码中的写死逻辑,其实就是 / 3

所以只要客户端空闲时间超过 4000 毫秒,就会发送一个 PING 给服务端,如果客户端的超时时间设置的非常大的话,比如半小时,那每隔 10 秒也会强制发送一个 PING(这个 10 秒是 Java 客户端写死的逻辑)。

客户端和服务端之间的会话先讲到这里,接下来我们聊聊服务端之间的会话。

二、服务端会话的秘密

如果村里是同时有多个办事处的时候(我这里先假设两个),情况就不太一样了。

假设鸡太美第一次连接的时候找到的作为 Follower 的马小云

而 Follower 是不能独自处理非读请求的,所以此次马小云会为鸡太美分配好 ID 之后,将创建会话操作转发给马果果,这样就好像是鸡太美找到马果果一样,流程和上面是一样的,在会话管理页中记录下来。

马小云自己也会简单的维护一个会话 ID 和超时时间的映射关系,以多个村民为例,每次收到请求都会对其进行记录

现在鸡太美是连接的马小云办事处(包括每次心跳发送),但是全局的会话管理数据在马果果这里,这样是怎么维持住会话状态的呢?

这里我们就得先聊聊服务端之间是怎么进行心跳的。

服务端有一个重要的配置 tickTime(默认是 2000),还有另一个重要的配置 syncLimit(默认是 5),我就以这两个默认值来举例:

  • 首先 Leader 会以 1000 (tickTime / 2) 毫秒的频率去对各个 Follower 发起 PING 的请求
  • 每次检查 Follower 返回的 PING 的超时时间是否超过 10000 (tickTime * syncLimit),超过这个时间没有收到该 Follower 的 ACK 响应就关闭和该 Follower 的 socket 连接

那 Follower 收到 PING 的消息后会回复一个 PING 给 Leader 并且会把自己记录的会话映射关系一起发过去

还会立即清空自己本地的映射关系!

然后 Leader 收到 Follower 的这个 PING 响应后,因为之前所有客户端的会话管理数据其实都在 Leader 这里,所以 Leader 可以对发过来的会话 ID 和超时时间进行会话激活,具体方法和之前的例子中是一样的,通过服务端之间的 PING,既可以完成服务端之间的心跳检测,又可以对客户端的会话进行激活,又是一次一鱼两吃。

小结一下:

  • 会话是 ZK 中的重要概念,会话的状态会影响,服务端对客户端请求的处理
  • 客户端的每次操作都会延长会话的超时时间,并且客户端会主动发起 PING 请求来保持住会话,以免在空闲时会话超时被服务端关闭
  • 客户端的会话数据是保存在 Leader 端的,Follower 只是在每次操作的时候简单的记录下会话 ID 和超时时间的映射关系
  • 服务端之间的心跳 PING 是由 Leader 主动向 Follower 发起的
  • Follower 收到 PING 后会将自己保存的会话映射数据发送给 Leader
  • Leader 收到 Follower 的 PING 响应后会对发送过来的会话数据进行激活

我们现在已经知道了会话的概念,就可以聊聊临时节点了。

三、临时节点

我们先来看下临时节点的创建代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
client.create("/HelloZooKeeper/niubi", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

这次的创建操作和其他的持久节点创建并无区别,需要在小红本上写下记录,而这个记录中有一个字段是 ephemeralOwner 当节点是持久节点这个字段值是 0,但当节点是临时节点时这个字段记录的就是持有该节点的会话 ID。

除了在小红本上创建记录以外,由于是临时节点,还需要额外在一个专门的地方也记录一下,假设还是鸡太美创建了 3 个临时节点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
19980802  => ["/鸡太美/我真美", "/鸡太美/我真帅", "/鸡太美/我真秀"]

鸡太美会话超时的时候,可能是会话真超时了(由于有心跳机制,所以这个可能性其实不大),也可能是鸡太美主动关闭的会话。

马果果就会从这个记录临时节点的地方根据鸡太美的会话 ID 取出对应的临时节点的路径,然后根据路径删除即可,效果和鸡太美主动删除是一样的,这样就达到了,当客户端关闭之后,对应的临时节点会自动清除的特点。这个临时节点的特性就会被用在 ZK 实现分布式锁的时候,防止了客户端因意外退出没法执行释放锁的逻辑!

四、协议

还有一个东西我一直就没提过,就是 ZK 的协议。

众所周知,ZK 是一个 CS 架构的应用,有客户端和服务端之分,那既然这样就免不了需要进行网络通信,而且不光是客户端和服务端之间,服务端和服务端之间也需要通信,有了网络通信就离不开协议,但是协议既是最重要的东西,也是最不重要的东西。

  • 最重要是因为,ZK 本身就是基于该协议去通信的,无论是客户端还是服务端之间,我之前提到的各种暗号,如:REQUEST、ACK、COMMIT、PING 等。都属于协议中的一个字段,用来区分不同的消息。协议构成了整个 ZK 通信的基础,能够通信了才能完成整个组件的功能。
  • 最不重要是因为,除非你想开发 ZK 的客户端,主动去请求 ZK 服务端,不然即使你完全不知道协议的具体格式,也不会影响你理解整个 ZK 的原理,而且协议的介绍非常的枯燥和无用,容易劝退。

所以我把这个概念留到了最后才提起,并且我也不打算去讲解 ZK 中不同请求的协议具体长什么样。这次我就换一个角度简单的介绍下协议。

首先,我介绍的 ZK 都是 Java 程序,无论客户端还是服务端,所以协议的本质是规定如何把 Java 对象转成字节流,方便在网络中传输,以及拿到字节流的那一方,如何再把这个字节流转换回 Java 对象,这其实就是序列化和反序列化的过程。而为了方便序列化,ZK 中定义的各种对象,如 XxxRequest 、 XxxResponse、XxxPacket 等,它们的字段类型通常就几种:intlongStringbyte[]Listboolean 以及其他嵌套的类型。

4.1 int、long、boolean

对于这三种类型来说最简单,直接用输出流写即可,区别就是一个是 4 字节,一个是 8 字节,一个是 1 字节

4.2 String、byte[]

这两种是类似,如果字段为空,则就写入一个 -1,不为空就先写一个 int 表示长度,之后紧跟 byte[] 表示具体数据即可

4.3 嵌套类型、List

碰到 List 和 4.2 是一样,如果为空就写 -1,不为空就先写 List 长度,之后遍历 List 根据泛型(也只可能是上面这几种)决定如何继续写入,嵌套对象的话就把这个写入操作委托给它就行了,因为它的字段也只可能是上面这几种。

4.4 小结

ZK 的序列化协议采用的紧凑书写的方式,根据不同的字段类型依次写入最终的字节流即可。

五、总结

今天我们介绍了 ZK 会话相关的知识:会话是什么,客户端和服务端的会话如何保持,服务端和服务端的会话如何保持,以及介绍了临时节点是如何利用会话机制在会话结束后被自动删除的,最后再用很短的篇幅带大家了解了下 ZK 的协议,不知不觉已经写了九篇了,我决定这一篇是本系列中最后一篇讲解原理的,之后的文章不讲原理介绍下 ZK 中的一些隐藏功能,还有整理下重要的资料,如配置信息,面试大全,目标是打造收藏向的三篇重磅文章。期待一下吧~

老规矩,如果你有任何对文章中的疑问也可以是建议或者是对 ZK 原理部分的疑问,欢迎来仓库中提问。

地址:https://github.com/HelloGitHub-Team/HelloZooKeeper

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HelloGitHub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
1 条评论
热度
最新
撤那么多鸡儿玩意儿的反而不想看了。。。
撤那么多鸡儿玩意儿的反而不想看了。。。
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
不用代码趣讲 ZooKeeper 集群
Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费开源、有趣、入门级的 ZooKeeper 教程,面向有编程基础的新手。
HelloGitHub
2021/05/14
3000
不用代码趣讲 ZooKeeper 集群
醒一醒,讲到 ZooKeeper 的选举机制了
Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费开源、有趣、入门级的 ZooKeeper 教程,面向有编程基础的新手。
HelloGitHub
2021/05/14
3460
醒一醒,讲到 ZooKeeper 的选举机制了
坐下坐下,基本操作(ZooKeeper 操作篇)
Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费开源、有趣、入门级的 ZooKeeper 教程,面向有编程基础的新手。
HelloGitHub
2021/05/14
2920
坐下坐下,基本操作(ZooKeeper 操作篇)
谁手握账本?趣讲 ZK 的内存模型
Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费开源、有趣、入门级的 ZooKeeper 教程,面向有编程基础的新手。
HelloGitHub
2021/05/14
6760
谁手握账本?趣讲 ZK 的内存模型
不懂就问:ZooKeeper 集群如何进行数据同步?
Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费开源、有趣、入门级的 ZooKeeper 教程,面向有编程基础的新手。
HelloGitHub
2021/05/14
8150
不懂就问:ZooKeeper 集群如何进行数据同步?
欢迎来到 ZooKeeper 动物世界
Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费有趣、入门级的 ZooKeeper 开源教程,面向有编程基础的新手。
HelloGitHub
2021/05/14
4930
欢迎来到 ZooKeeper 动物世界
zookeeper源码分析(8)-会话管理
zookeeper客户端和服务端维持一个TCP长连接,它们之间任何正常的通信都需要一个正常的会话。本文主要分析会话生命周期中会话状态的变化过程和客户端服务端如何管理会话。
Monica2333
2020/06/22
1.4K0
zookeeper完整详细版
配置java环境,这个教程应该能帮你:https://www.runoob.com/java/java-environment-setup.html
许喜朝
2020/09/24
1.4K0
最后一篇:面试遇到 ZK 的问题,横趟!
本文是 HelloZooKeeper 系列的最后一篇文章,接下来主要聊聊面试中如果被问到 ZooKeeper 的问题如何回答,也可以当作学完本系列的测试。
HelloGitHub
2021/05/08
6860
分布式基础概念-分布式服务之ZK[2]
peerlastZxid介于minCommittedLog和maxCommittedLog之间
@派大星
2023/11/03
2030
分布式基础概念-分布式服务之ZK[2]
Hadoop学习13--zookeeper相关
zookeeper要保证各个server之间同步,实现同步的协议是zab协议。此协议有两种模式:恢复模式(选主)和广播模式(同步)。 服务启动或者leader崩溃时,进入恢复模式。选举成功且大多数server完成了和leader的状态同步后(2n+1台中的n+1台),恢复模式就结束了。 状态同步保证了leader和Server具有相同的系统状态。为了保证事务的顺序一致性,zookeeper采用了递增的事务id号 (zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zx
小端
2018/04/16
6840
zookeeper 浅解
从官网 https://apache.org/dist/zookeeper/zookeeper-3.5.5/ 上下载zk(注意windows也是下载 tar.gz后解压),./conf下有个zoo_sample.cfg 复制到同目录下改名为zoo.cfg,在目录下新建data和log文件夹,修改zoo.cfg中的 dataDir 和 dataLogDir为 data和log的路径。现在启动zk,在bin目录下有个zkServer.cmd,运行启动。启动ZK客户端对ZK进行简单的读写操作,在bin目录下打开cmd,运行:
六个核弹
2020/11/03
3920
zookeeper 浅解
很遗憾,没有一篇文章能讲清楚ZooKeeper!
作为分布式系统解决方案的 ZooKeeper,被广泛应用于多个分布式场景。例如:数据发布/订阅,负载均衡,命名服务,集群管理等等。
macrozheng
2020/01/20
1.4K0
很遗憾,没有一篇文章能讲清楚ZooKeeper!
Apache ZooKeeper - FourLetterCommands运维命令
除了 JConsole 监控控制台之外,ZooKeeper 还提供了一些命令,可使我们更加灵活地统计监控 ZooKeeper 服务的状态信息。
小小工匠
2021/08/17
4030
揭秘井井有条的流水线(ZooKeeper 原理篇)
Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费开源、有趣、入门级的 ZooKeeper 教程,面向有编程基础的新手。
HelloGitHub
2021/05/17
2890
揭秘井井有条的流水线(ZooKeeper 原理篇)
ZooKeeper入门,这一篇给你讲的明明白白
面试常常被要求「熟悉分布式技术」,当年搞 “XXX管理系统” 的时候,我都不知道分布式系统是个啥。分布式系统是一个硬件或软件组件分布在不同的网络计算机中上,彼此之间仅仅通过消息传递进行通信和协调的系统。
海星
2020/09/15
5K0
Zookeeper总结
(tickTime也是一个配置项。是Server内部控制时间逻辑的最小时间单位) 如果客户端发来的sessionTimeout超过min-max这个范围,server会自动截取为min或max.
XING辋
2019/05/08
9100
Zookeeper总结
【大数据】ZooKeeper
Zookeeper是一个分布式协调服务的开源框架。主要用来解决分布式集群中应用系统的一致性问题。
陶然同学
2023/02/24
9860
【大数据】ZooKeeper
Zookeeper核心原理
  » 学习者(learner),包括跟随者(follower)和观察者(observer),follower用于接受客户端请求并想客户端返回结果,在选主过程中参与投票
用户4283147
2022/10/27
3850
Zookeeper核心原理
Zookeeper底层原理
ZooKeeper 是一个高可用的分布式协调服务,广泛应用于分布式系统中,用于解决分布式系统的一致性问题。下面将详细介绍 ZooKeeper 的底层原理,包括其架构、数据模型、核心机制和一致性协议等方面。
小马哥学JAVA
2024/07/04
2770
相关推荐
不用代码趣讲 ZooKeeper 集群
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验