Zookeeper 初识

565 阅读6分钟

zookeeper 是什么?

官方文档是这样解读zookeeper的:它是一个分布式协调框架,是Apache Hadoop 的一个子项目,它主要是用来 解决分布式应用中 经常遇到的一些 数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。

zookeeper的两大基本特性

数据结构

Zookeeper 维护一个类似Linux文件系统的数据结构。

“/”可以理解为根目录,及其子目录项都被称作为 znode(目录节点),和文件系统类似,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode。

zookeeper 有6种节点类型:

  1. PERSISTENT - 持久化目录节点
    • 目录节点一经创建,只要不手动删除该节点,他将永远存在。客户端与zookeeper断开连接,节点不会删除。
  2. PERSISTENT_SEQUENTIAL - 持久化顺序编号目录节点
    • 顺序节点在持节化节点的基础上,对目录节点进行顺序标号
  3. EPHEMERAL - 临时目录节点
    • 一次session中有效,session 过期就会被删除。客户端与zookeeper断开连接后,哪怕短时间内重连,只要不是同一session登录,该节点也会删除。
  4. EPHEMERAL_SEQUENTIAL - 临时顺序编号目录节点
    • 临时顺序节点,在临时节点的基础上,对目录节点进行顺序标号
  5. TTL节点
    • 可设置超时时间,一旦超过限定时间就会被删除,zk后台维护了一个定时任务,每60秒扫描一次,过期的删除。【默认禁用,只能通过系统配置zookeeper.extendedTypesEnabled=true 开启,不稳定】
  6. Container - 容器节点
    • 3.5.3 版本新增,新建的容器节点和普通节点无异,一旦容器节点下新建过子节点,最后清空子节点,那么该容器节点也会在未来被删除。【zk后台维护了一个定时任务,每60秒扫描一次】

节点监听机制

zookeeper 服务端提供节点监听功能,以便客户端感知到服务端节点发生变化。
zookeeper 提供了三种监听方式:

  1. 监听某一节点(get -w /path)
    • 当该节点的被删除,或者数据发生修改时,服务端会通知客户端节点发生变化【只会告知是节点被删除,还是节点中的数据发生变化,而不会告知数据变化的结果,需要客户端手动获取新数据】
  2. 监听某一目录(ls -w /path)
    • 当该目录下有子节点新增或者删除,服务端会通知客户端
  3. 监听某个目录的递归子节点(ls -R -w /path)
    • 当该根目录的被删除、数据被修改时,或者子目录有新增删除时,会通知客户端

注:zookeeper 所有的监听机制都是单次生效,一旦触发,监听事件就会被移除。如果监听的是目录的递归子节点,每个节点都会触发一次。

zookeeper 的使用场景

基于zookeeper的两大特性,可以很方便的完成

  1. 分布式配置中心/分布式注册中心:利用zk的持久化节点以及监听机制,可以很方便的将 配置/ 应用信息 保存在zk的持久化节点上面,最终通过监听机制,在配置发生改变时,通知各应用。【适合体量不大的应用】
  2. 分布式锁:利用zk节点的名称的唯一性,可以比较简单的实现分布式锁
    • 公平锁:通过临时持久化顺序节点,让想要获取锁的对象在某一父节点下依次新增顺序节点,然后监听上一个新增的节点。抢锁条件:序号最小的节点获取锁。再上一节点释放锁被删除时,下一节点会监听到这一消息,然后进行抢锁工作。
    • 非公平锁:通过监听某一固定名称的临时节点,实现非公平锁。在请求进来时,先去尝试获取锁(get -w /path),如果获取不到,循环等待。然后等上一个占用锁的线程结束时,服务器通知所有等待获取锁的线程,所有等待线程再竞争锁。【在高并发下,这种方式效率比较低。原因:惊群效应,每次只能一个线程获取锁,但是唤醒了所有线程】
    • 读写锁:在应用中同时存在缓存层和数据库层时,在高并发情况下下,可能出现缓存和数据读写不一致的情况。 这种情况下我们需要添加一把读写锁,来确保写操作发生时,读操作不能再进行读取,需等待写操作完成后,才能进行读取;读操作正在发生时,写操作不能进行写,需等待读操作完成后,才能写入。
      监听规则:连续读的情况,监听上一个写,如果之前没有写,无需加锁;写的情况,监听自己上一个节点;

zookeeper 集群

  1. 复制zoo.cfg,并修改如下配置(示范为单机,伪集群配置)
    • dataDir=/zookeeper/zk1
    • clientPort=2181 ### 客户端连接端口
    • server.1=localhost:2888:3888 ### 2888 集群数据同步通信端口 3888 选举通信端口
    • server.2=localhost:2889:3889
    • server.3=localhost:2890:3890
  2. 再对应的dataDir目录下新建myid文件【不带文件格式,server.1服务,myid文件内容就是”1“】
  3. 将服务分别启动

zookeeper 集群选举流程* 面试常问

以三个节点的zookeeper节点为例,当两个及以上服务启动后,正式选举开始:

  1. 第一轮选举:在 ZK 服务启动时,会向配置文件中配置的所有其他节点发送一张选票,选票内容包括 自身serverId最新数据的ZXID 等。同时会收到其他应用的选票,将收到的选票和自身选票对比【对比规则:ZXID大的优先,如果ZXID一致,serverId大的优先】
  2. 第二次选举:各个 ZK 服务,会向其他节点发送,自己所得的所有选票(包括自己)中优先级最高的选票。如果投某一服务的票数超过半数,则选举结束。选举出来的机器,就是leader。
  3. 之后其他服务连接到集群,就会发现已经存在leader,自动将自身设置为follower。

zookeeper 集群数据同步

在选举完成后,客户端连接zookeeper - leader节点写入数据,此时leader节点会打开一个socket等待follower节点来连接,follower节点连接上leader节点后,leader节点会持续发送新的数据到follower节点。如果当时没有新的数据写入,且旧数据已经同步完成,leader节点会周期性的发送一些空白的socket信息,用于保持节点间的连接。