重点

  • leader选举规则
  • watch事件监听

zookeeper - 图1


什么是zookeeper

zookeeper是一种集中式服务,用于维护配置信息,命名,提供分布式同步和提供组服务。

zookeeper使用类似文件操作系统的目录结构树来维护元数据。

zookeeper安装

zookeeper中的三个角色

  1. leader

leader是整个zookeeper的主节点

负责响应所有对zookeeper状态变更的请求

证集群内部消息处理的FIFO(先进先出)

  1. follower

响应本服务器上的请求

处理leader的提议

在leader提交该提议时在本地提交

和leader一起构成集群的法定人

参与新leader的选举

  1. observer

不参与投票

只接受票选结果

不用返回写请求ack

使用时需要修改配置文件

不影响集群的性能

不属于集群的关键角色

断开连接不影响集群可用性

配置软连接

ln -s zookeeper-3.4.14 default

单节点模式

单节点模式,只需要修改配置文件添加日志目录即可(日志目录需要提前创建)

  • 修改配置文件
  1. cp zoo_sample.cfg zoo.cfg
  2. vim zoo.cfg
  • 修改为下图:

伪分布式模式

伪分布式环境要求


  • 复制多份相同的zookeeper包,创建多个目录并修改配置文件。

  • 目录如下所示:
  1. ├── server001
  2. ├── data
  3. ├── logs
  4. └── zookeeper-3.4.0
  5. ├── server002
  6. ├── data
  7. ├── logs
  8. └── zookeeper-3.4.0
  9. ├── server003
  10. ├── data
  11. ├── logs
  12. └── zookeeper-3.4.0
  13. ├── server004
  14. ├── data
  15. ├── logs
  16. └── zookeeper-3.4.0
  17. └── server005
  18. ├── data
  19. ├── logs
  20. └── zookeeper-3.4.0
  • 每个包中的文件夹及内容

伪分布式配置

  • 修改配置文件
  1. cp zoo_sample.cfg zoo.cfg
  2. vim zoo.cfg

  • 修改为下图:


  • 注意事项

每个节点端口号都不同(包括启动端口和通信端口)

ip地址相同

  • 创建myid文件

在每个包的data文件夹下创建文件myid,文件内容为server后的数值,如server002为2

  1. echo '2' > myid
  • 依次启动每个包中的zookeeper
  1. bin/zkServer.sh start
  • 查看zookeeper状态
  1. bin/zkServer.sh status
  • 出现下面页面说明成功

model的值可以为follower或者为leader都为正常。

环境配置详解

  • tickTime

心跳时间。作为zookeeper服务器之间或客户端与服务器之间维持心跳的时间间隔,每个tickTime都会发送一个心跳

  • dataDir

zookeeper保存数据的目录,默认将数据的日志文件也卸载这个文件里

  • dataLogDir

zookeeper的日志存放目录

  • clientProt

zookeeper的端口号,客户机连接zookeeper的端口,zookeeper会监听这个端口,接收客户端请求。

  • initLimit

初始化限制时间,初始化时follwer连接leader时的允许等待的心跳数。

  • syncLimit

通信限制时间。leader和follwer之间发送消息的最长应答时间(心跳数)

  • server.A=B:C:D

A是一个数字表示这个集群的几号机器

B是这个服务器的ip地址

C是该机器与leader通信的端口

D是选举端口,在leader出现问题时,剩余机器进行选举时使用。

zookeeper的端口号

2181:对外通信端口号

2888:leader与follower通信端口号

3888:选举端口号

命令行操作


  1. ls2:查看结点详细信息

  2. create [-e] [-s] /node data :创建<临时><有序>结点,结点需要有数据,默认创建持久结点。

  3. get /node :获取结点数据

  4. set /node data:修改结点

  5. get /node watch:监听结点变化

  6. delete /node: 删除结点

  7. rmr /node:递归删除

  8. stat /:查看结点状态
  1. czxid:事务id
  2. ctime-znode:创建时间戳
  3. mzxid-znode:最后更新的事务id
  4. mtime-znode:最后修改的时间戳
  5. pzxid-znode:最后更新的子节点zxid
  6. cversion-znode:子节点变化号,znode子节点修改次数
  7. dataversion-znode:数据变化版本号
  8. aclversion-znode:访问控制列表的变化号
  9. ephemeralowner:临时节点的session id。持久节点为0。

  1. setAcl:设置权限,需要指定结点,指定权限

  2. getAcl:获取权限

  3. addauth:添加认证用户,切换用户

zookeeper的acl权限控制

acl权限控制类似linux的文件权限

包含三部分

  1. 1. 权限模式
  2. 2. 授权对象
  3. 3. 权限列表

例如: setAcl /node ip:192.168.1.10:crwda //将/node结点的192.168.1.10的权限设置为可增删改查管理权限

  • 权限模式
    • world:全局模式,所有人,对象只有一种:anyone
    • IP:对象是针对固定ip
    • auth:对象使用添加认证的用户
    • digest:对象使用名密码方式认证的用户
  • 权限列表【针对当前节点】
    • c:create
    • d:delete
    • r:read
    • w:write
    • a:admin

auth授权模式

添加认证用户:addauth digest <suer>:<password>

添加认证授权后可以对该用户进行特殊权限管理。

digest授权模式

添加授权:addauth <path> digest:<user>:<password>:<acl>

该授权模式不用提前进行用户认证。

但是该授权方式的密码需要时加密后的密文格式

密码加密:

echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64

超级管理员

zookeeper中存在一个超级管理员用户名是super

该管理员访问任意结点,所有权限。

使用该管理员需要修改zookeeper的启动配置项,添加超级管理员权限。【超级管理员的授权方式是digest授权模式,需要对密码进行加密】

zab协议

zab协议是 ZooKeeper Atomic Broadcast ,zookeeper源自消息广播协议。是保证zookeeper数据一致性的核心算法。是一种通用的分布式一致性算法。

选举规则,宕机数据恢复等等都是通过该协议实现。

zookeeper的选举流程


  • 服务器id

数值越大,权重越高


  • 选举状态
    • looking:选举状态
    • leading:领导状态
    • following:跟随状态
    • observing:观察状态,不参与投票

  • 事务id

数值越大,数据越新,权重越高


  • 逻辑时钟

投票次数

全新集群选举机制

集群启动时的选举机制。

核心是投票数过半。

【3台服务器的集群】


  1. 服务器1启动,投票给自己

将选举结果发送给其他服务器。但是由于没有其他服务器启动,所以没有反馈信息。


  1. 服务器2启动,投票给自己

将选举结果发送给其他服务器,服务器1和2交换投票结果,由于2号服务器的数值大权重高,所以服务器1将票投给2号,2号持有两张选票,大于半数。所以服务器2当选leader。状态变为leading。1号状态为following。

如果集群为5台,那么即使2号结果大于1号,也不能选举为leader,因为其选票只有两张。1和2都是looking状态。启动服务器3后,交换选举结果,因为3号的权重更大,所以,1,2都投票给3号,3号当选leader。


  1. 服务器3启动,虽然服务器编号大,但是已经存在了leader,所以服务器3直接为following状态。

非全新集群选举机制

当leader宕机后,选举leader的规则


  1. 首先统计逻辑时钟是否相同

逻辑时钟即投票次数,如果逻辑时钟小,则说明运行过程中出现过宕机情况。

那么该服务器的选举结果将会被忽略。


  1. 比较事务id

事务id越大说明数据越新,运行状态越稳定,权重越大

为什么要设置比较事务这一项?

有可能leader在宕机的时候,follower1接受了一个请求,还没传给leader的时候,leader宕机了,这时为了保证数据的一致性和准确性,所以比较事务id来确定哪个follower是最新的事务。

如果多个follower在leader宕机时都接收到了请求,那么在选举出leader之后,会将请求发送给leader。


  1. 如果数据id和逻辑时钟都相同,则比较服务器id

选举规则是为了选取出整个集群中越行最稳定的服务器leader

zookeeper的目录结构

zookeeper的结构非常类似windows文件系统的结构

不同点是文件系统的目录不能存储数据,只能文件存储数据,zookeeper是目录和文件都能存储数据

其实更像树形结构。


  • zookeeper包含的结点类型

    1. 临时结点

临时创建的结点,程序执行完或者会话结束就会消失


  1. 临时有序节点

有序排列的临时节点


  1. 持久化结点

持久化到本地的结点,程序结束或者会话结束后依然存在


  1. 持久化有序结点

有序排列的持久化结点

zookeeper的watch事件监听

zookeeper提供了数据的发布/订阅功能,多个订阅者可同时监听某一特定主题对象,当该主题对象的自身状态发生变化时例如节点内容改变、节点下的子节点列表改变等,会实时、主动通知所有订阅者。

zookeeper采用了 Watcher机制实现数据的发布订阅功能。该机制在被订阅对象发生变化时会异步通知客户端,因此客户端不必在 Watcher注册后轮询阻塞,从而减轻了客户端压力。

watcher机制事件上与观察者模式类似,也可看作是一种观察者模式在分布式场景下的实现方式。

监听内容:

  1. 结点创建
  2. 节点删除
  3. 节点数据修改
  4. 子节点变更

监听实现步骤

  1. 监听机制中包含两个线程,一个连接线程,将监听事件发送给服务端,一个listener监听器接收服务端通知。
  1. 客户端注册监听事件到服务端。
  2. 将监听时间保存到服务端的管理列表中。
  3. 服务端监听所有数据的变化
  4. 服务器主动通知客户端。
  5. 客户端收到消息后执行相应的处理逻辑。

监听的特性:

  1. 一次性,监听触发后会被移除。需要重新注册
  2. 客户端顺序回调:回调是顺序串行执行
  3. 轻量级:watchevent监听事件是最小的通信单位,结构上只包含通知状态,事件类型和节点路径。不包含数据内容。
  4. 时效性:作用范围在session时效内,session失效后快速重连成功,监听事件依然存在。

zookeeper写数据的流程


  1. 客户端向服务端发送写数据请求

  2. 如果接受请求的服务端不是leader,那么会进一步转发给leader

  3. leader将写请求广播给所有server,follower执行写操作,但不提交

  4. leader收到大多数的server写成功的ack【半数原则】,认为写数据成功

  5. leader发送commit提交广播,follower执行提交操作。此时数据写入完成

    如果没有半数ack成功返回,超时后写入失败。

类似Innodb的两阶段提交。只不过是innodb是在备库同步时,zookeeper发生在分布式集群中。


  1. leader通知接收请求的服务端写成功

  2. 服务端通知客户端写入成功。

zookeeper的读数据不需要经过zookeeper,因为zookeeper每个结点上的数据都是一致的

zookeeper实现动态上下线

zookeeper实现服务动态上下线,实际是使用结点的创建删除与监听机制来完成的。

客户端1用来监听和管理。可以启动一个监听事件,一直监听zookeeper某个目录下的结点。

客户端2服务中运行正常的处理逻辑,除此之外还包括结点注册和运行监听事件,监听自己创建的结点是否存在。

当服务上线时,创建对应的结点。注册成功。

客户端1可以对客户端2执行下线操作,删除客户端2对应结点,客户端2监听到系欸但删除后程序执行退出操作。完成下线。

zookeeper实现分布式锁

zookeeper的一个主要功能是实现分布式系统的数据一致性。

其中重要的是分布式锁的实现。

zookeeper中的锁其实就是一个结点【临时有序结点】。

zookeeper的实现方式是:


  1. 一个客户端来获取锁,创建一个临时有序节点。
    1. 判断当前他持有的有序结点是否为最小结点。
      1. 如果为最小结点,那么获取到锁,执行任务。
      2. 如果不是最小节点,该客户端会启动watch监听事件,监听比他小的有序节点
        1. 当他监听的结点被删除之后,说明他之前的客户端已经释放了锁,从而该客户端可以获取到锁
  1. 执行完任务之后,删除临时有序结点。
  2. 该客户端后的结点监听到节点删除后,获取到锁。

这种实现方式相当于AQS中的独占锁的实现,所有的客户端形成了一个等待队列。

只不过由AQS中的线程唤醒后续结点变成了后续节点监听前置结点。

第三方curator客户端可以实现zookeeper的分布式锁。

锁的种类:

  1. 分布式可重入排他锁
  2. 分布式排他锁
  3. 分布式读写锁
  4. 多个锁执行一组操作。
  5. 共享信号量

种类和单体锁的种类类似

zookeeper实现配置中心

设计依靠监听机制实现

  1. 1. 将配置信息存储在zookeeper的节点中
  2. 2. 客户端在启动时,首先链接zookeeper,然后读取对应节点的信息进行配置
  3. 3. 客户端服务启动,并且启动事件监听。监听对应目录的数据变化
  4. 4. 变化后,zookeeper会通知客户端,客户端重新加载配置信息。

zookeeper实现分布式唯一id

在分库分表的情况下可以使用临时有序节点来实现唯一id。

但是使用该方法实现有缺陷。zookeeper集群重启后,临时节点将被清除。且存在最大值,会使用完。

curator

curator是奈飞开源的一个zookeeper的客户端。提供给apache。对zookeeper的原生api进行了包装。解决了很多zookeeper客户端非常底层的细节开发。

  • zookeeper原生api的不足
    • 连接对象是手动控制异步等待。【即手动控制线程等待结点创建】
    • 没有超时自动重连机制
    • watch只生效一次【可以用递归实现多次】
    • 不支持递归创建树形结点。
  • curator特点
    • 解决session超时重连问题
    • watcher自动反复注册
    • 简化api
    • 提供了分布式锁,共享数据器【唯一id】,缓存机制等。

zooInspector

zooInspector是zookeeper的图形化工具。

taokeeper

淘宝实现的zookeeper的web管理工具。