zookeeper

一、zookeeper介绍

简介

  • zookeeper是一种分布式协调服务,用于管理大型主机。在分布式环境中协调和管理服务是一个复杂的过程。zookeeper通过其简单的架构和API解决了这个问题。zookeeper允许开发人员专注于核心应用程序逻辑,而不必担心应用程序的分布式特性
  • ZooKeeper主要服务于分布式系统,可以用ZooKeeper来做:统一配置管理、统一命名服务、分布式锁、集群管理。
  • 使用分布式系统就无法避免对节点管理的问题(需要实时感知节点的状态、对节点进行统一管理等等),而由于这些问题处理起来可能相对麻烦和提高了系统的复杂性,ZooKeeper作为一个能够通用解决这些问题的中间件就应运而生了。

假设我们的程序是分布式部署在多台机器上,如果我们要改变程序的配置文件,需要逐台机器去修改,非常麻烦,现在把这些配置全部放到zookeeper上去,保存在 zookeeper 的某个目录节点中,然后所有相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会收到 zookeeper 的通知,然后从 zookeeper 获取新的配置信息应用到系统中。

zookeeper应用场景

  • 分布式协调组件

​ 在分布式系统中,需要有zookeeper作为分布式协调组件,协调分布式系统中的状态。

  • 分布式锁

    zk在实现分布式锁上,可以做到强一致性,关于分布式锁相关的知识,在之后的ZAB协议中介绍。

  • 无状态化的实现

二、搭建zookeeper服务器

zoo.cfg配置文件说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#zookeeper时间配置中的基李单位(毫秒)
tickTime=200o
#允许follower初始化连接到leader最大时长,它表示tickTime时间倍数即:initLimit*tickTime
initLimit=10
#允许follower与leader数据同步最大时长,它表示tickTime时间倍数
syncLimit=5
#zookeper数据存储目录及日志保存目录〈如果没有指明dataLogDir,则日志也保存在这个文件中)
dataDir=/tmp/zookeeper
#对客户端提供的端口号
clientPort=2181
#单个客户端与zookeeper最大并发连接数
maxClientcnxns=60
#保存的数据快照数量,之外的将会被清除
autopurge.snapRetainCount=3
#自动触发清除任务时间间隔,小时为单位。默认为0,表示不自动清除。
autopurge.purgeInterval=1

zookeeper服务器的操作命令

  • 重命名conf中的文件zoo_sample.cfg->zoo.cfg

  • 启动zk服务器

    1
    ./bin/zkServer.sh start ./conf/zoo.cfh
  • 查看zk服务器状态

    1
    ./bin/zkServer.sh status ./conf/zoo.cfh
  • 停止zk服务器

    1
    ./bin/zkServer.sh stop ./conf/zoo.cfh

启动服务端后就可以启动客户端

1
[root@VM-24-12-centos bin]# ./zkCli.sh

三、zookeeper内部的数据模型

zk是如何保存数据的

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

每个子目录项如 NameService 都被称作为 znode(目录节点),和文件系统一样,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,唯一的不同在于znode是可以存储数据的。

zk中的数据是保存在节点上的,节点就是znode,多个znode之间构成一颗树的目录结构。

zookeeper的数据模型是什么样子呢?它很像数据结构当中的树,也很像文件系统的目录。

树是由节点所组成,zookeeper的数据存储也同样是基于节点,这种节点叫做Znode

但是,不同于树的节点,Znode的引用方式是路径引用,类似于文件路径

这种层级结构,让每一个Znode节点拥有唯一的路径,就像命名空间一样对不同信息作出清晰的隔离。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] create /test1
Created /test1
[zk: localhost:2181(CONNECTED) 2] ls /
[test1, zookeeper]
[zk: localhost:2181(CONNECTED) 3] create /test1
Node already exists: /test1
[zk: localhost:2181(CONNECTED) 4] create /test1/sub1
Created /test1/sub1
[zk: localhost:2181(CONNECTED) 5] ls /
[test1, zookeeper]
[zk: localhost:2181(CONNECTED) 6] create test2 abc
Path must start with / character
[zk: localhost:2181(CONNECTED) 7] create /test2 abc
Created /test2
[zk: localhost:2181(CONNECTED) 8] get /test2
abc

zk中的znode是什么样的结构

zk中的znode,包含了四个部分:

  • data:保存数据
  • acl:权限,定义了什么样的用户能够操作这个节点,且能够进行怎样的操作。
    • c:create创建权限,允许在该节点下创建子节点
    • w:write更新权限,允许更新该节点的数据
    • r:read读取权限,允许读取节点的内容以及子节点的列表信息
    • d:delete删除权限,允许删除该节点的子节点
    • a:admin管理者权限。允许对该节点进行acl权限设置
  • stat:描述当前znode的元数据
  • child:当前节点的子节点

zk中节点znode的类型

  • 持久节点:创建出的节点,在会话结束后依然存在。保存数据。

  • 持久序号节点:创建出的节点,根据先后顺序,会在节点之后带上一个数值,越后执行数值越大,适用于分布式锁的应用场景-单调递增

  • 临时节点:

    临时节点是在会话结束后,自动被删除的,通过这个特性,zk可以实现服务注册与发现的效果。

  • 临时序号节点:和持久序号节点相同,适用于临时的分布式锁

  • Container节点:Container容器节点,当容器中没有任何子节点,该容器节点会被zk定期删除(60s)

  • TTL节点:可以指定节点的到期时间,到期后被zk定时删除,只能通过系统配置zookeeper.extendedTypesEnabled=true开启

zk的数据持久化

zk的数据是运行在内存中,zk提供了两种持久化机制:

  • 事务日志

    zk把执行的命令以日志形式保存在dataLogDir指定的路径中的文件中〈如果没有指定dataLogDir,则按dataDir指定的路径)。

  • 数据快照

    zk会在一定的时间间隔内做一次内存数据的快照,把该时刻的内存数据保存在快照文件中。

zk通过两种形式的持久化,在恢复时先恢复快照文件中的数据到内存中,再用日志文件中的数据做增量恢复,这样的恢复速度更快。

四、zookeeper客户端(zkCli)的使用

多节点类型创建

  • 创建持久节点
  • 创建持久序号节点
  • 创建临时节点
  • 创建临时序号节点
  • 创建容器节点

监听通知机制

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。

查询节点

  • 普通查询
  • 查询节点相关信息
    • cZxid:创建节点的事物ID
    • mZxid:修改节点的事物ID
    • pZxid:添加和删除子节点的事物ID
    • ctime:节点创建的时间
    • mtime:节点最近修改的时间
    • dataVersion:节点内数据的版本,每更新一次数据,版本会+1
    • aclVersion:此节点的权限版本
    • ephemeralOwner:如果当前节点是临时节点,该值是当前节点所有者的session id。如果节点不是临时节点,则该值为零。
    • dataLength:节点内数据的长度
    • numChildren:该节点的子节点个数

删除节点

  • 删除节点
  • 乐观锁删除

权限设置

  • 注册当前会话的账号和密码

    1
    addauth digest 账号:密码
  • 创建节点并设置权限

    1
    create /test-node abcd auth:账号:密码:cdwra
  • 在另一个会话中必须先使用密码账号,才能拥有操作该节点的权限

五、curator客户端的使用

curator介绍

Curator是Netflix公司开源的一套zookeeper客户端框架,Curator是对Zookeeper支持最好的客户端框架。Curator封装了大部分Zookeeper的功能,比如Leader选举、分布式锁等,减少了技术人员在使用Zookeeper时的底层细节开发工作。

引入curator

  • 引入依赖

    1
      

六、zk实现分布式锁

zk中锁的种类:

  • 读锁:大家都可以读,要想上读锁的前提︰之前的锁没有写锁

  • 写锁:只有得到写锁的才能写。要想上写锁的前提是,之前没有任何锁。

zk如何上读锁

  • 创建一个临时序号节点,节点的数据是read,表示是读锁获取当前zk中序号比自己小的所有节点

  • 判断最小节点是否是读锁:

    • 如果不是读锁的话,则上锁失败,为最小节点设置监听。阻塞等待,zk的watch机制会当最小节点发生变化时通知当前节点,于是再执行第二步的流程

    • 如果是读锁的话,则上锁成功

zk如何上写锁

  • 创建一个临时序号节点,节点的数据是write,表示是写锁
  • 获取zk中所有的子节点
  • 判断自己是否是最小的节点:
    • 如果是,则上写锁成功
    • 如果不是,说明前面还有锁,则上锁失败,监听最小的节点,如果最小节点有变化,则回到第二步。

羊群效应

如果用上述的上锁方式,只要有节点发生变化,就会触发其他节点的监听事件,这样的话对水k的压力非常大,——羊群效应。可以调整成链式监听。解决这个问题。