我们的 ZooKeeper 是怎样做到这些点的,在实际项目开发中,我们应该如何使用 ZooKeeper ?要想了解这些问题,我们先要对 ZooKeeper 的数据模型有一定了解和掌握。

数据模型对于 Zookeeper 来说尤为重要,很多典型的使用场景都使用这点基础模块,比如说我们可以利用 Zookeeper 数据模型中的临时节点和 Watch 监控机制来实现一个发布订阅的功能。

数据模型

计算机最本质的作用就是用来处理和存储数据的,Zookeeper 作为一款分布式一致性解决框架,也不例外。
 
其实 Zookeeper 中的数据模型是用来处理和存储数据的一种逻辑结构,与我们使用的 MySQL 数据库一样,在一个系统中,要想处理我们的复杂业务,是不是要知道如何向我们的 MySQL 数据库中新增数据。而我们的 Zookeeper 数据模型要做的事情,就是像我们的 MySQL 数据库一样,这也是 Zookeeper 最根本的功能。

对 Zookeeper 中的数据模型是什么,我们已经知道。但是 Zookeeper 数据模型这个比较抽象。

ZooKeeper 数据模型的结构与我们的 Unix 文件系统很类似,就是现在大家看到下面的这张图,整体上可以看作是一棵树,在这棵树上,它其实有很多的这个节点,每个节点称做一个ZNode。每个Znode可以类似看作是一个目录,其下可以创建子目录。

在每一个节点或者说 znode上,它都可以通过一个路径进行一个唯一标识,你可以看到每一个节点上其实都有一个对应的路径。那么这样的好处就是我们现在可以快速的、清晰的定位到每一个 znode 节点。

image.png

比如说我们现在要找到 znode2 这个节点,那怎么去找呢?其实就是 /znode/znode2,这样的话我们是不是就定位到了这个 znode2 。这个其实就是它的一个数据结构。

我们在使用 Zookeeper 要注意的是:ZooKeeper 的数据模型有一个固定的根节点(/),这个根节点是永远不会变的,我们可以在根节点下创建其子节点,并在子节点下还可以继续创建子节点。ZooKeeper 树中的每一层级用斜杠(/)分隔开,且只能用绝对路径(如“get /znode/znode2”)的方式查询 ZooKeeper 节点,而不能使用相对路径。

节点类型

通过前面的学习,我们已经知道了 Zookeeper 的数据模型是一种树形结构,它的数据模型就像我们的 MySQL 数据库一样,将我们的数据存储在数据库表中。

我们 Zookeeper 中的数据是由数据节点构成,而是由很多个数据节点,这些数据节点最终是构成一个层次级别的树形结构。

在ZooKeeper中,每个数据节点都是有生命周期的,其生命周期的长短取决于数据节点的节点类型。节点类型可以分为持久节点(PERSISTENT)、临时节点(EPHEMERAL)、顺序节点(SEQUENTIAL) 三大类,具体在节点创建过程中,通过组合使用,可以生成以下四种组合型节点类型:

  • 持久节点:  持久节点是 Zookeeper 的默认节点,Zookeeper 中最常用的一种节点类型,在使用 Zookeeper 场景中,几乎都要使用持久节点。持久节点被创建后会一直存在 ZooKeeper 服务器上,即使创建该节点的客户端与服务端的会话关闭了,该节点依然不会被删除,除非使用 delete 命令手动删除。

 

  • 持久顺序节点:  持久顺序节点是在持久节点的基础上,增加了顺序性。也就是说,持久顺序节点被创建时,ZooKeeper 服务器会自动使用一个单调递增的数字作为后缀,追加到我们创建节点的后边。会根据创建的时间进行编号,根据编号我们就可以判断它们的顺序。

  • 临时节点:  从这个名字上我们可以知道该节点类型最重要的特性就是临时性,临时节点与持久节点的特点相反,如果我们将某个节点创建为临时节点,那么该节点数据不会一直存储在 ZooKeeper 服务器上。临时节点被创建之后,如果与创建它的客户端断开连接或者是连接超时等原因,临时节点就会从我们的 Zookeeper 服务器上被销毁。同样的,我们也可以手动的删除我们的临时节点。

  • 临时顺序节点:  临时顺序节点就是在临时节点的基础上,增加了顺序性,与持久顺序节点一样,只不过我们创建的是临时节点。

现在我们已经知道 Zookeeper 服务器存储数据的基本信息了,Zookeeper 中的数据节点有这么四种,分别是持久节点、有序持久节点、临时节点和有序临时节点。

虽然这四种节点的类型不同,但是 Zookeeper 中的每个节点都有相同的基本信息,这些基本信息包括:一个二进制数组,用来存储节点的数据、ACL 访问控制信息、子节点数据,以及每个数据节点有记录自身状态信息的字段。

节点的状态结构

 

在我们的 Zookeeper 服务器中,创建的所有数据节点,其每个数据节点都有属于自己的状态信息,这个就像和我们每个人样,都有自己的身份信息。现在我们来演示演示数据节点的具体信息,获取 /znode/znode2 信息,通过使用 stat /znode/znode2 命令,可以看到在控制台输出以下信息,这些信息就是数据节点的自身基本信息。

image.png

从上图,我们知道每个节点都有自己的基本信息,接下来详细的介绍一下这个基本信息,让大家对这些基本信息有一个了解。

cZxid = 0x36 表示该创建节点的事物ID
ctime = Wed Apr 14 17:13:15 EDT 2021 表示该节点创建时间
mZxid = 0x36 表示该节点最后一次被修改的事物 ID
mtime = Wed Apr 14 17:13:15 EDT 2021 #表示该节点最后一次被修改的时间
pZxid = 0x36  表示该节点的子节点列表最后一次被修改时的事务ID。注意,只有子节点列表变更了才会变更pzxid,子节点内容变更不会影响pzxid
cversion = 0 表示该节点的数据版本号,主要不包括子节点
dataVersion = 0 表示数据版本修改次数
aclVersion = 0 表示权限版本修改次数
ephemeralOwner = 0x0 创建该临时节点的会话 SessionlD如果该节点是持久节点,那么这个属性值是0
dataLength = 0 表示数据长度
numChildren = 0 表示当前节点的子节点数,注意不包括子子节点

Zookeeper 中数据节点为什么要有版本

ZooKeeper 中的版本概念和传统意义上的软件版本有很大的区别,它表示的是对数据节点的数据内容、子节点列表,或是节点 ACL 信息的修改次数,我们以其中的 version 这种版本类型为例来说明。在一个数据节点 /znode/znode2 被创建完毕之后,节点的 version 值是0,表示的含义是“当前节点自从创建之后,被更新过 0 次”。如果现在对该节点的数据内容进行更新操作,那么随后,version 的值就会变成 1。同时需要注意的是,在上文中提到的关于 version 的说明,其表示的是对数据节点数据内容的变更次数,强调的是变更次数,因此即使前后两次变更并没有使得数据内容的值发生变化,version 的值依然会变更。和乐观锁的版本一样。

数据节点的应用场景

服务注册与发现:在我们的微服务项目开发中,可以使用 Zookeeper 的临时节点来实现服务注册与发现,在 Zookeeper 服务上创建一个临时节点,将该服务注册到 Zookeeper 服务的临时节点上,将其的访问的信息交给我们 Zookeeper 进行维护。使用 Zookeeper 的临时节点作为服务注册与发现的好处是,当某个服务与 Zookeeper 服务断开连接的时候,这个临时节点会自动删除,这时 Zookeeper 发现这个服务断开了,就是自动移除该服务的访问地址,目的是避免出现 404 错误的情况,同时我们也可以手动的删除某个服务的对应的临时节点。

配置信息维护:对于目前互联网急剧壮大,我们的项目也逐步扩大,比如我们京东、淘宝这些购物商城类的网站,服务越来越多,服务的配置信息也非常多。一旦配置信息需要修改,会消耗我们大量的时间去修改每个服务中配置信息,而且还有可能会出错,这种情况我们就可以使用 Zookeeper 的持久节点来保存全局的配置信息。当某个服务注册到 ZooKeeper 时,可以去保存配置信息的节点读取配置信息。当我们修改配置时,Zookeeper 会通知这些服务,服务就会重新去读取配置信息。

分布式锁:一个大型的分布式系统,都是有很多个服务,当多个服务同时对一个资源进行修改时,会出现数据的错误,通过临时顺序节点可以避免这种情况。通过为资源加锁的方式来实现,如果当多个服务同时访问资源的时候,获取资源的服务会创建一个临时顺序节点,根据顺序来判断临时节点的编号是否为第一个,如果是为第一个,成功获取到锁,此时服务就可以进行资源修改操作,完成修改操作之后或者是这个服务与 zookeeper 服务断开了连接,相当于删除临时顺序节点,释放了锁。其他的服务同样根据它创建的临时顺序节点的顺序依次来对资源进行相关的操作。

Zookeeper 的节点数据应用场景简介到这里,具体实现方式后期详细介绍。
 

小结

经过上面的讲解,我们知道了很多功能的实现都是基于 Zookeeper 的结构以及 Znode 的类型和它们的特点,所以学习 Zookeeper 的数据模型还是很有必要的。现在我们来对本节的内容进行总结.
 

节点的类型有 4 种:持久节点、持久顺序节点、临时节点、临时顺序节点。