你应该知道的分布式Zookeeper

Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。
Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管框架,它负责存储和管理核心数据,接收观察者的注册,一旦核心数据发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的哪些观察者做出相应的反应,Zookeeper=文件系统+通知机制。
在这里插入图片描述

Zookeeper特点

  • 一个领导者(Leader),多个跟随着(Follower)组成的集群.
  • 集群中只要有半数以上节点存活,Zookeeper集群就能正常服务.
  • 全局数据一致:每个Server保存一份相同的数据副本,Client随机连接到那个Server,数据都是一致的
  • 更新请求顺序进行,来自同一个Client的更新请求按发送顺序依序执行
  • 数据更新原子性,要么全部成功,要么全部失败.
  • 实时性,在一定范围内,Client能读取到最新数据.

Zookeeper数据结构

在这里插入图片描述
ZooKeeper这颗"树"有什么特点呢??ZooKeeper的节点我们称之为Znode,Znode分为两种类型:
短暂/临时(Ephemeral):当客户端和服务端断开连接后,所创建的Znode(节点)会自动删除
持久(Persistent):当客户端和服务端断开连接后,所创建的Znode(节点)不会删除
短暂/临时:又区分为普通短暂节点/带序号的短暂节点.
持久:又区分为普通持久节点/带序号的持久节点.

Zookeeper服务场景

提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。

统一命名服务:

在这里插入图片描述
在ZooKeeper中每个命名空间(Namespace)被称为ZNode,你可以这样理解,每个ZNode包含一个路径和与之相关的元数据,以及继承自该节点的孩子列表。与传统文件系统不同的是,ZooKeeper中的数据保存在内存中,实现了分布式同步服务的高吞吐和低延迟。
在上图示例的ZooKeeper的数据模型中,有如下要点:

  • 每个节点(ZNode)中存储的是同步相关的数据(这是ZooKeeper设计的初衷,数据量很小,大概B到KB量级),例如状态信息、配置内容、位置信息等。
  • 一个ZNode维护了一个状态结构,该结构包括:版本号、ACL变更、时间戳。每次ZNode数据发生变化,版本号都会递增,这样客户端的读请求可以基于版本号来检索状态相关数据。
  • 每个ZNode都有一个ACL,用来限制是否可以访问该ZNode。
  • 在一个命名空间中,对ZNode上存储的数据执行读和写请求操作都是原子的。
  • 客户端可以在一个ZNode上设置一个监视器(Watch),如果该ZNode数据发生变更,ZooKeeper会通知客户端,从而触发监视器中实现的逻辑的执行。
统一配置管理:

在这里插入图片描述
ZooKeeper集群由一组Server节点组成,这一组Server节点中存在一个角色为Leader的节点,其他节点都为Follower。当客户端Client连接到ZooKeeper集群,并且执行写请求时,这些请求会被发送到Leader节点上,然后Leader节点上数据变更会同步到集群中其他的Follower节点。

统一集群管理:

在这里插入图片描述
ZooKeeper中的Watch是只能触发一次。也就是说,如果客户端在指定的ZNode设置了Watch,如果该ZNode数据发生变更,ZooKeeper会发送一个变更通知给客户端,同时触发设置的Watch事件。如果ZNode数据又发生了变更,客户端在收到第一次通知后没有重新设置该ZNode的Watch,则ZooKeeper就不会发送一个变更通知给客户端。
ZooKeeper异步通知设置Watch的客户端。但是ZooKeeper能够保证在ZNode的变更生效之后才会异步地通知客户端,然后客户端才能够看到ZNode的数据变更。由于网络延迟,多个客户端可能会在不同的时间看到ZNode数据的变更,但是看到变更的顺序是能够保证有序一致的。
ZNode可以设置两类Watch,一个是Data Watches(该ZNode的数据变更导致触发Watch事件),另一个是Child Watches(该ZNode的孩子节点发生变更导致触发Watch事件)。调用getData()和exists() 方法可以设置Data Watches,调用getChildren()方法可以设置Child Watches。调用setData()方法触发在该ZNode的注册的Data Watches。调用create()方法创建一个ZNode,将触发该ZNode的Data Watches;调用create()方法创建ZNode的孩子节点,则触发ZNode的Child Watches。调用delete()方法删除ZNode,则同时触发Data Watches和Child Watches,如果该被删除的ZNode还有父节点,则父节点触发一个Child Watches。
另外,如果客户端与ZooKeeper Server断开连接,客户端就无法触发Watches,除非再次与ZooKeeper Server建立连接。

服务器动态上下线

在这里插入图片描述
当Server节点因某些原因下线不能提供服务,zookeeper集群会通知客户端,客户端通过监听Server服务器列表变化,重新获取服务器列表并注册新的监听

软负载均衡:

Zookeeper会记录每台服务器的访问数,根据服务器性能,让访问数最少的服务器去处理最新的客户端请求

常见问题:

ZooKeeper为什么推荐搭建奇数台服务集群?
zookeeper集群一般是奇数台服务器,假如:1,2,3,4,5台服务器;那么挂掉4,5两台服务器,zookeeper集群仍能正常服务,因为集群中只要有半数以上节点存活,Zookeeper集群就能正常服务,如果是偶数台服务器,假如:1,2,3,4,5,6;那么挂掉4,5.6三台服务,Zookeeper集群就不能正常服务

ZooKeeper的选举机制?
假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。
在这里插入图片描述

  • 服务器1启动,此时只有它一台服务器启动了,它发出去的报文没有任何响应,所以它的选举状态一直是LOOKING状态。
  • 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1、2还是继续保持LOOKING状态。
  • 服务器3启动,根据前面的理论分析,服务器3成为服务器1、2、3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的Leader。
  • 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1、2、3、4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了。
  • 服务器5启动,同4一样当小弟。

ZooKeeper使用了一种自定义的原子消息协议,在消息层的这种原子特性,保证了整个协调系统中的节点数据或状态的一致性。Follower基于这种消息协议能够保证本地的ZooKeeper数据与Leader节点同步,然后基于本地的存储来独立地对外提供服务。
当一个Leader节点发生故障失效时,失败故障是快速响应的,消息层负责重新选择一个Leader,继续作为协调服务集群的中心,处理客户端写请求,并将ZooKeeper协调系统的数据变更同步(广播)到其他的Follower节点。

写数据流程:
在这里插入图片描述

  • Client向zookeeper的Server1上写数据,发送一个写请求
  • 如果Server1不是Leader,那么Server1会把接收到的请求进一步转发给Leader,因为每个Zookeeper的Server里面有一个是Leader.这个Leader将会将写请求广播给集群中各个Server,比如Server1和Server2,各个Server写成功后就回通知Leader.
  • 当Leader收到大多数(半数以上)Server数据写成功了,那么就说明数据写成功了,然后Leader会告诉Server1数据写成功了
  • Server1会进一步通知Client数据写成功了,这时就回默认整个写操作成功了

ZooKeeper的监听原理是什么?
在这里插入图片描述

发布了32 篇原创文章 · 获赞 53 · 访问量 2480

猜你喜欢

转载自blog.csdn.net/qq_41714882/article/details/103952276