标签: 分布式 微服务 大数据
简介
ZooKeeper 是一个为分布式应用所设计的分布的、开源的协调服务。分布式的应用可以建立在同步、配置管理、分组和命名等服务的更高级别的实现的基础之上。 ZooKeeper 意欲设计一个易于编程的环境,它的文件系统使用我们所熟悉的目录树结构。 ZooKeeper 使用 Java 所编写,但是支持 Java 和 C 两种编程语言。
zookeeper 架构
zookeeper 是基于观察者模式(发布-订阅模式)设计,zookeeper是一个树的结构,类似于文件系统结构,负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper 就将负责通知已经在 Zookeeper 上注册的那些观察者做出相应的反应,从而实现集群中类似 Master/Slave 管理模式。
zookeeper 安装
- 单机模式
单台服务器上只部署了一个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 - 伪集群模式
伪集群:在一台物理机上运行多个zookeeper实例
zookeeper 源文件配置方式:
zoo1.cfg 和 zoo2.cfg 和 zoo3.cfg 的日志生成路径和端口不一样其他的设置一样
dataDir=/data #保存数据的目录,默认情况下zookeeper将写数据的日志文件也保存在这个目录里
dataLogDir=/datalog
tickTime=2000 #服务器之间或客户端与服务器之间维持心跳的时间间隔,每个tickTime发送一个心跳
initLimit=5
syncLimit=2
clientPost=2181 #客户端访问服务端的端口
autopurge.snapRetainCount=3
autopurge.purgeInterval=0
maxClientCnxns=60
standaloneEnabled=true
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
依次启动 ./zkServer.sh start ../conf/zoo1.cfg ./zkServer.sh start ../conf/zoo1.cfg ./zkServer.sh start ../conf/zoo1.cfg
- 集群模式
组成一个集群服务器数量必须满足(2n+1)[n>0]台服务器,由于zookeeper的主节点是由选举产生。、
修改每台服务器上zookeeper的配置文件:
dataDir=/data
dataLogDir=/datalog
tickTime=2000
#指配置zookeeper接收客户端(zookeeper服务器集群中连接到leader的follower服务器)初始化连接时最多能忍受多少个间隔时长,超过N(配置数)个心跳时间后,zookeeper服务器还没有收到客户端返回的信息,则表明连接失败
initLimit=5
#配置leader与follower之间发送消息、请求的应答时长最多不超过N(设置数)个心跳时长。
syncLimit=2
clientPost=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=0
maxClientCnxns=60
standaloneEnabled=true
##组成服务器的集群
server.1=zoo1:2888:3888 #将zoo1换成zoo1所在服务器的IP
server.2=zoo2:2888:3888 #将zoo2换成zoo2所在服务器的IP
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(容器节点),通过这(三)四(对应版本)个节点的组合得到了其他节点
- 持久节点(PERSISTENT)
持久节点就是该节点只要被创建后,没有被删除,就会一直存在,就算服务器和客户端断开连接,该节点依然存在。 - 临时节点(EPHEMERAL)
临时节点就是该节点在被创建后,客户端与服务器断开连接,则该节点就会被释放删除 - 容器节点(CONTAINER)
容器节点是为leader、lock等操作存在的,当容器节点的最后一个孩子节点被删除之后,容器节点将被标注并在一段时间后删除。 - 持久有序节点(PERSISTENT_SEQUENTIAL)
该节点与持久节点基本特性上没有太大区别,在zookeeper中,父节点会为子节点进行排序(按照子节点的创建顺序),这个顺序在创建时zookeeper会在每个创建的节点的节点名后面加上一个数字后缀,该数字后缀的范围是整型的最大值 - 临时有序节点(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接口就可以实现命名服务;
命名服务有两个应用方向:
- 提供类似JNDI的功能,利用zookeepeer的树型分层结构,可以把系统中各种服务的名称、地址以及目录信息存放在zookeeper,需要的时候去zookeeper中读取。
- 利用zookeeper顺序节点的特性,制作分布式的ID生成器,利用zookeeper顺序节点的特性,我们可以生成有顺序的,容易理解的,同时支持分布式环境的序列号。
配置管理
集群管理
分布式锁
注意三点:加锁、解锁、锁超时
解决的问题也是对应要注意的三项
队列管理
注意事项
(1)Zookeeper不支持递归创建数据节点,无法在父节点不存在的情况下创建子节点。否则会抛出类似以下异常:
Exception in thread "main" org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for /zk-test-create-sequential-/11
at org.apache.zookeeper.KeeperException.create(KeeperException.java:111)
at org.apache.zookeeper.KeeperException.create(KeeperException.java:51)
at org.apache.zookeeper.ZooKeeper.create(ZooKeeper.java:783)
at com.secbro.learn.TestCreateNode.main(TestCreateNode.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
(2)如果节点已经存在,再创建同名节点,会抛出NodeExistsException。
(3)关于权限控制,如果没有特殊要求,可按照上面例子中直接设置为ZooDefs.Ids.OPEN_ACL_UNSAFE,表明之后对节点的任何操作都不受权限控制。
作者 @zzxhub