Zookeeper的诞生
在了解 Zookeeper 之前先来看看 Zookeeper 是如何诞生的
互联网的飞速发展让我们的单体架构已无法满足业务的发展,因此我们的系统开始往分布式架构发展,但是在发展的过程中也出现了诸多的问题,比如服务与服务之间的协调与通知
分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统
为了更好理解服务与服务之间的协调,我们引入一个例子来进一步的说明一下
假如有两个服务是分布式部署的,这两个服务分别为 服务A 、服务B,它们之间的通信通过某种通信协议进行通信,比如 HTTP协议 、Dubbo协议,如下:
两者之间虽然能够通过这种通信协议来进行数据交流,但是这种数据交流是实时的,也就是说服务A发送数据给服务B,服务B就立马需要去做处理,这里设想一下,假如服务B没时间去处理服务A的数据,那该怎么办呢
因此这种方式无法真正做到两个服务之间的数据协调
为了解决这个问题,我们引入一个第三方系统,我们就称为数据协调系统吧,如下:
这种方式就是服务A把数据存放到数据协调系统里,等到服务B有时间处理的时候再从数据协调系统去拿
这样服务A既不需要等待服务B去及时的处理并响应,又不用担心服务B没时间去处理,这样就很好的解决了服务之间的协调
既然这是一个协调系统,那毋庸置疑是一个非常重要的系统,因此这个数据协调系统也需要分布式并且是以集群的方式部署,而不是单机部署
那么分布式部署就必然会有数据一致性、网络分区带来的网络故障等问题
为了解决数据协调系统由于分布式部署带来的问题,雅虎研究院就开始研究出一个分布式协调中间件,并将命名为 Zookeeper
Zookeeper 使用 ZAB 协议解决了分布式协调系统带来的问题,并于 2011 年 11 月正式成为了 Apache 的顶级项目
现如今 Zookeeper 发展到现在也不仅仅是作为一个协调系统而存在,而更是作为分布式数据一致性的解决方案而存在
Zookeeper的特点
顺序一致性:从同一个客户端发起的请求,Zookeeper 会严格按照其请求顺序进行处理
原子性:所有的请求处理结果在 Zookeeper 集群中所有的节点上都是一致的,在处理过程中要么一起成功要么一起失败
单一试图:无论客户端连接到 Zookeeper 集群中的哪台机器,看到的数据模型都是一致的
可靠性:一旦有客户端的请求对 Zookeeper 里的数据或服务状态进行了修改,并成功响应了,那么这次修改数据或服务状态会一直保留下来,除非有另外的一个请求对其进行了修改
实时性: Zookeeper 里的一旦有数据或服务状态被修改,那么客户端就能够立即读取到修改后的最新数据状态
Zookeeper的应用场景
Zookeeper 除了用来做分布式协调/通知外,还可以实现数据发布/订阅、负载均衡、命名服务、集群管理、Master 节点选举、分布式锁和分布式队列等功能
下面来例举三种最为典型的应用场景来说说:
1、注册中心:我们学习过Dubbo应该都知道,通过把服务调用地址注册到 Zookeeper 上,然后Dubbo通过 Watcher 机制进行监听,并拉取远程服务的调用地址
2、分布式锁:我们有了解过 Redis 可以用来做分布式锁,但是 Zookeeper 也同样可以,我们可以利用 Zookeeper 创建唯一节点的来实现,创建了唯一节点就获取到锁,删除唯一节点就释放锁
3、数据的发布/订阅:Zookeeper 提供了 Wacher 监听机制,可以很方便的实现发布/订阅功能
除了上面的一些使用场景外,另外很多的开源项目也使用到了 Zookeeper ,比如 Kafka、HBase、Hadoop 等
Zookeeper的数据存储结构
Zookeeper 的数据存储也是存储在内存中的,也可以持久化到磁盘上,其在内存中的存储结构不像 Redis 那种通过 K-V 方式去存储的,而是通过树状结构对数据进行存储,如下:
这种方式跟 Unix 文件系统有点类似,数据就是存放到节点下,其根节点就用 "/" 表示,每个节点下可以创建子节点
每个节点在 Zookeeper 的概念中被称之为 ZNode ,ZNode 是 Zookeeper 数据中最小的单位
ZNode 节点信息
znode 节点除了存储的数据外,其本身还有一些状态信息,我们在 Zookeeper 的客户端可以通过 get 命令获取,如下:
[zk: 127.0.0.1:2181(CONNECTED) 6] get /demo
cZxid = 0x2
ctime = Tue Nov 27 11:05:34 CST 2018
mZxid = 0x2
mtime = Tue Nov 27 11:05:34 CST 2018
pZxid = 0x3
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
下面我们来看下每个信息代表什么吧
cZxid:create ZXID,该数据节点被创建时的事务 id
ctime:create time,即该节点的创建时间
mZxid:modified ZXID,即该节点最终一次更新时的事务 id
mtime:modified time,即该节点最后一次的更新时间
pZxid: 该节点的子节点列表最后一次修改时的事务 id,只有子节点列表变更才会更 新pZxid,子节点内容变更不会更新
cversion: 子节点版本号,当前节点的子节点每次变化时值增加 1
dataVersion: 数据节点内容版本号,节点创建时为 0,每更新一次节点内容(不管内容有无变化)该版本号的值增加 1
aclVersion:节点的 ACL 版本号,表示该节点 ACL 信息变更次数
ephemeralOwner:创建该临时节点的会话的 sessionId;如果当前节点为持 久节点,则 ephemeralOwner=0
dataLength: 数据节点内容长度
numChildren:当前节点的子节点个数
Zookeeper各个节点的特性
ZNode 一共分为四种类型:
持久节点(PERSISTENT): 所谓持久节点是指数据节点被创建的后就会一直存在于Zookeeper 上,直到有删除操作来主动删除这个节点。持久节点是 Zookeeper 中最为常用的节点
持久顺序节点(PERSIS_SEQUENTIAL): 除了与持久节点的特性一致之外,其创建的节点还需有顺序性
临时节点(EPHEMERAL): 与上面两个节点不同的是,临时节点具有生命周期,其生命周期与客户端的会话绑定在一起,也就是说,如果客户端的会话失效了,那么这个节点就会被自动清理掉
临时顺序节点(EPHEMERAL_SEQUENTIAL):临时顺序节点与临时节点的特性也基本一致,同样也是多了一个具有顺序的特性
Zookeeper 集群
Zookeeper 的集群模式为 Master/Savle (主从)模式,这种集群模式 Master 服务器统一对外提供服务,Savle 服务器只用作数据同步及备份
对应的集群架构如下:
Zookeeper 集群角色
虽然 Zookeeper 集群模式是主动模式,但是Zookeeper并没有使用传统的"主","从"概念,而是引用了Leader、Follower 和 Observer 三种角色,如下图所示:
Leader 可以为客户端提供读写服务,Follwer 和 Observer 除了能只能提供读服务,而 Follwer 与 Observer 主要区别在于 Observer 不参与 Leader 的选举,也不参与写操作的 “过半写成功” 策略
Observer 存在的作用就在于为 Leader 分担读请求,从而提高整个集群的读性能
ZooKeeper 集群中的服务器状态
LOOKING :开始进入到选举周期中的状态。
LEADING :Leader 状态,对应的节点为 Leader
FOLLOWING :Follower 状态,对应的节点为 Follower
OBSERVING :Observer 状态,对应节点为 Observer,该节点不参与 Leader 选举
结束语
码字不易,还希望多多点赞、收藏支持下