标签: 分布式 微服务 大数据

简介

ZooKeeper 是一个为分布式应用所设计的分布的、开源的协调服务。分布式的应用可以建立在同步、配置管理、分组和命名等服务的更高级别的实现的基础之上。 ZooKeeper 意欲设计一个易于编程的环境,它的文件系统使用我们所熟悉的目录树结构。 ZooKeeper 使用 Java 所编写,但是支持 Java 和 C 两种编程语言。

zookeeper 架构

zookeeper 是基于观察者模式(发布-订阅模式)设计,zookeeper是一个树的结构,类似于文件系统结构,负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper 就将负责通知已经在 Zookeeper 上注册的那些观察者做出相应的反应,从而实现集群中类似 Master/Slave 管理模式。

zookeeper 安装

  1. 单机模式
    单台服务器上只部署了一个zookeeper服务,之后一个服务端提供服务;
    zookeeper部署方式:
    一、docker 启动
    docker run -d -p 2181:2181 -v /mysoft/zookeeper/data/:/data/ —name=zookeeper —privileged zookeeper
    二、zookeeper源文件,脚本启动
    ./zkServer.sh start ../conf/zoo.cfg
  2. 伪集群模式
    伪集群:在一台物理机上运行多个zookeeper实例
    zookeeper - 图1
    zookeeper 源文件配置方式:
    zoo1.cfg 和 zoo2.cfg 和 zoo3.cfg 的日志生成路径和端口不一样其他的设置一样
  1. dataDir=/data #保存数据的目录,默认情况下zookeeper将写数据的日志文件也保存在这个目录里
  2. dataLogDir=/datalog
  3. tickTime=2000 #服务器之间或客户端与服务器之间维持心跳的时间间隔,每个tickTime发送一个心跳
  4. initLimit=5
  5. syncLimit=2
  6. clientPost=2181 #客户端访问服务端的端口
  7. autopurge.snapRetainCount=3
  8. autopurge.purgeInterval=0
  9. maxClientCnxns=60
  10. standaloneEnabled=true
  11. server.1=zoo1:2888:3888
  12. server.2=zoo2:2888:3888
  13. server.3=zoo3:2888:3888
  1. 依次启动 ./zkServer.sh start ../conf/zoo1.cfg ./zkServer.sh start ../conf/zoo1.cfg ./zkServer.sh start ../conf/zoo1.cfg
  1. 集群模式
    组成一个集群服务器数量必须满足(2n+1)[n>0]台服务器,由于zookeeper的主节点是由选举产生。、
    修改每台服务器上zookeeper的配置文件:
  1. dataDir=/data
  2. dataLogDir=/datalog
  3. tickTime=2000
  4. #指配置zookeeper接收客户端(zookeeper服务器集群中连接到leaderfollower服务器)初始化连接时最多能忍受多少个间隔时长,超过N(配置数)个心跳时间后,zookeeper服务器还没有收到客户端返回的信息,则表明连接失败
  5. initLimit=5
  6. #配置leaderfollower之间发送消息、请求的应答时长最多不超过N(设置数)个心跳时长。
  7. syncLimit=2
  8. clientPost=2181
  9. autopurge.snapRetainCount=3
  10. autopurge.purgeInterval=0
  11. maxClientCnxns=60
  12. standaloneEnabled=true
  13. ##组成服务器的集群
  14. server.1=zoo1:2888:3888 #将zoo1换成zoo1所在服务器的IP
  15. server.2=zoo2:2888:3888 #将zoo2换成zoo2所在服务器的IP
  16. server.3=zoo3:2888:3888 #将zoo3换成zoo3所在服务器的IP

zookeeper高可用

所有的写操作都要经过leader节点才能完成,所有的读操作所有节点都可以完成

zookeeper集群保证高可用—ZAB协议(保证数据一致性)

  • ZAB协议
    解决了:数据一致性、集群崩溃恢复

共有三种状态:

  • looking: 选举状态
  • following: follower节点(从节点)所处的状态
  • leading: leader节点(主节点)所处的状态

zookeeper 数据结构特点

  • zookeeper每个子目录项都被称作 Znode,这个 Znode是被他所在路径的唯一标识;
  • Znode 可以有子节点目录,并且每个节点目录都可以存储数据,EPHEMERAL(临时节点)类型的目录节点不能有子节点目录;
  • Znode 有版本,每个Znode中存储的数据可以有多个版本;
  • Znode可以是临时节点,但是服务器与客户端失去连接,临时节点类型的 Znode 被删除,因为服务器与客户端的通信采用长连接方式;
  • Znode 的目录名可以自动编号,例如有了APP1,在创建的话就是APP2;
  • Znode 可以被监控,包括监控目录节点中存储的数据的修改,子节点目录的变化,若发生变化,则将这些变化通知给设置监控的客户端。

节点类型

在zookeeper中,节点大体分为PERSISTENT(持久节点)、EPHEMERAL(临时节点)、SEQUENTIAL(时序节点)、版本3.6.0+ 新增了CONTAINER(容器节点),通过这(三)四(对应版本)个节点的组合得到了其他节点

  1. 持久节点(PERSISTENT)
    持久节点就是该节点只要被创建后,没有被删除,就会一直存在,就算服务器和客户端断开连接,该节点依然存在。
  2. 临时节点(EPHEMERAL)
    临时节点就是该节点在被创建后,客户端与服务器断开连接,则该节点就会被释放删除
  3. 容器节点(CONTAINER)
    容器节点是为leader、lock等操作存在的,当容器节点的最后一个孩子节点被删除之后,容器节点将被标注并在一段时间后删除。
  4. 持久有序节点(PERSISTENT_SEQUENTIAL)
    该节点与持久节点基本特性上没有太大区别,在zookeeper中,父节点会为子节点进行排序(按照子节点的创建顺序),这个顺序在创建时zookeeper会在每个创建的节点的节点名后面加上一个数字后缀,该数字后缀的范围是整型的最大值
  5. 临时有序节点(EPHEMERAL_SEQUENTIAL)
    临时有序节点,该节点是临时节点和有序节点的组合,有这两个节点的基本特性,则该节点是zookeeper作为分布式锁的主要原因

以上五种节点中持久节点、临时节点、持久有序节点、临时有序节点是常用的四种节点。

zookeeper基本操作

server端

ZooKeeper的数据模型server端常用的shell操作命令:

操作 描述
create 创建一个节点
ls 查看当前节点数据
ls2 查看当前节点数据,并能看到更新次数等信息
set 修改节点
get 得到一个节点,包含数据和更新次数等信息
delete 删除一个节点
rmr 递归删除
stat 打印节点状态
setAcl 设置节点权限策略
getAcl 获取节点权限策略
aync 强制同步
addauth 节点权限认证

zookeeper 基础操作api

操作 描述
conn(String connectionHost) 创建客户端
conn(String connectionHost,int sessionTimeoutMs,int connectionTimeoutMs) 创建客户端
conn(String connectionHost,int sessionTimeoutMs,int connectionTimeoutMs,String nameSpace) 创建客户端
start(CuratorFramework client) 启动客户端
isExists(CuratorFramework client,String path) 判断节点是否存在
create(CuratorFramework client,String path) 创建节点
create(CuratorFramework client,String path,String data) 创建节点
create(CuratorFramework client,String path,CreateMode createMode) 创建节点
create(CuratorFramework client,String path,String data,CreateMode createMode) 创建节点
setData(CuratorFramework client,String path,String data) 设置节点存储数据
setData(CuratorFramework client,String path,String data,Integer version) 设置节点存储数据
getData(CuratorFramework client,String path) 获取节点存储数据
delete(CuratorFramework client,String path) 删除节点
delete(CuratorFramework client,String path,Integer version) 删除节点
getChildren(CuratorFramework client,String path) 获取节点子节点

zookeeper使用场景

统一命名服务

由于zookeeper的节点是树形结构的命名,而Name Service又是zookeeper内置的功能,只需要调用zookeeper API的create接口就可以实现命名服务;
命名服务有两个应用方向:

  1. 提供类似JNDI的功能,利用zookeepeer的树型分层结构,可以把系统中各种服务的名称、地址以及目录信息存放在zookeeper,需要的时候去zookeeper中读取。
  2. 利用zookeeper顺序节点的特性,制作分布式的ID生成器,利用zookeeper顺序节点的特性,我们可以生成有顺序的,容易理解的,同时支持分布式环境的序列号。

配置管理

集群管理

分布式锁

  1. 注意三点:加锁、解锁、锁超时
  2. 解决的问题也是对应要注意的三项

队列管理

注意事项

(1)Zookeeper不支持递归创建数据节点,无法在父节点不存在的情况下创建子节点。否则会抛出类似以下异常:

  1. Exception in thread "main" org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for /zk-test-create-sequential-/11
  2. at org.apache.zookeeper.KeeperException.create(KeeperException.java:111)
  3. at org.apache.zookeeper.KeeperException.create(KeeperException.java:51)
  4. at org.apache.zookeeper.ZooKeeper.create(ZooKeeper.java:783)
  5. at com.secbro.learn.TestCreateNode.main(TestCreateNode.java:24)
  6. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  7. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  8. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  9. at java.lang.reflect.Method.invoke(Method.java:606)
  10. at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

(2)如果节点已经存在,再创建同名节点,会抛出NodeExistsException。
(3)关于权限控制,如果没有特殊要求,可按照上面例子中直接设置为ZooDefs.Ids.OPEN_ACL_UNSAFE,表明之后对节点的任何操作都不受权限控制。

作者 @zzxhub