ZooKeeper入门

ZooKeeper 致力于提供一个高性能、高可用,且具备严格的顺序访问控制能力的分布式协调服务,是雅虎公司创建,是 Google 的 Chubby 一个开源的实现,也是 Hadoop 和 Hbase 的重要组件

ZooKeeper优点

  1. 简单的数据结构 :共享的树形结构,类似文件系统,存储于内存
  2. 可以构建集群 :避免单点故障,3-5 台机器就可以组成集群,超过半数正常工作就能对外提供服务
  3. 顺序访问 :对于每个读请求,ZooKeeper 会分配一个全局唯一的递增编号,利用这个特性可以实现高级协调服务
  4. 高性能 :基于内存操作,服务于非事务请求,适用于读操作为主的业务场景,3 台 ZooKeeper 集群能达到 13w QPS

那些场景可以使用

  • 数据发布订阅
  • 负载均衡
  • 命名服务
  • Master 选举
  • 集群管理
  • 配置管理
  • 分布式队列
  • 分布式锁

ZooKeeper安装

ZooKeeper的安装配置不论是单机安装还是集群(或者集群伪分布)都是非常的简单

首先准备工作

  1. Linux 需要安装配置jdk环境
  2. ZooKeeper官网 下载 ZooKeeper 安装包,然后上传至Linux,我上传在 /usr/local 目录下

下面的内容都是基于 CentOS7 安装ZooKeeper(3.4.12)

单机安装

  1. 解压压缩包
tar -zxvf zookeeper-3.4.12.tar.gz
复制代码
  1. 进入解压的目录,将配置文件 zoo_sample.cfg 复制一份为 zoo.cfg ,因为 ZooKeeper 启动时默认配置文件为 zoo.cfg ,当然你也可以指定配置文件 zoo_sample.cfg 启动(命令: ./zkServer.sh start ../conf/zoo_sample.cfg
cd zookeeper-3.4.12

cp zoo_sample.cfg zoo.cfg
复制代码
  1. 修改 zoo_sample.cfg 配置文件的 dataDir 属性,这里存放了 ZooKeeper 的快照文件,根据自己的需求修改,如果定义的目录不存在需要先创建出来
vim zoo.cfg

dataDir=/usr/local/zookeeper-3.4.12/data
复制代码
  1. 进入解压目录 zookeeper-3.4.12 下的 bin 目录,启动 ZooKeeper,相关命令如下
启动命令:./zkServer.sh start
停止命令:./zkServer.sh stop
重启命令:./zkServer.sh restart
状态查看命令:./zkServer.sh status
复制代码
  1. 启动后,可以查看一下状态是否启动成功,然后使用命令行进行登录操作,之后就可以尝试使用 ZooKeeper 的命令行了,命令操作再后面介绍
./zkCli.sh -server 192.168.182.130:2181
复制代码

集群安装

集群伪分布就是在一台服务器上面部署多个ZooKeeper,这里就不使用 集群伪分布 来示例了,之前 Redis 有使用过集群伪分布,集群伪分布就是通过配置文件端口号区别多个ZooKeeper,集群最好以奇数个为佳

过程如下

  1. 不使用集群伪分布,那么首先准备好三台Linux服务器,我这里使用了三个虚拟机CentOS7,ip分别为:192.168.182.130、192.168.182.131、192.168.182.132,同时开放 2888 和 3888 这两个端口访问,不然集群无法相互通信,查看状态一直为 ERROR
  2. 然后还是和单机安装一样,解压安装文件,复制配置文件,修改配置文件,不过配置文件还需要增加一个集群配置,贴出我的配置,其中:2888:集群内机器通讯使用(Leader监听此端口);3888:选举leader使用
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just 
# example sakes.
dataDir=/usr/local/zookeeper-3.4.12/data
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the 
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1

# 增加的集群配置
server.0=192.168.182.130:2888:3888
server.1=192.168.182.131:2888:3888
server.2=192.168.182.132:2888:3888
复制代码
  1. 配置好 192.168.182.130 这台服务器的配置文件之后,还需要做一件事情,在配置的 dataDir=/usr/local/zookeeper-3.4.12/data 目录下生成一个myid文件,分别对应上面配置中的server.0、server.1、server.2,例如 192.168.182.130 对应的就是 0
echo 0 > myid
复制代码
  1. zookeeper-3.4.12 这个目录使用 scp 命令远程复制到 192.168.182.131 和 192.168.182.132这两个服务器的 /usr/local 目录下,远程复制碰到登录密码输入即可,当然,你也可以使用其他工具复制
scp -r /usr/local/zookeeper-3.4.12 root@192.168.182.131:/usr/local
scp -r /usr/local/zookeeper-3.4.12 root@192.168.182.132:/usr/local
复制代码
  1. 前面提到 192.168.182.130 对应配置文件中的 0,那么 192.168.182.131 对应的就是 1,192.168.182.132 对应的就是2,所以还需要在这两台服务器上 分别更改 myid 文件内容
echo 1 > myid

echo 2 > myid
复制代码
  1. 最后分别启动每个服务器上的 ZooKeeper 就可以了,分别启动后可以查看一下三台服务器节点的状态,如果显示 Mode: follower 或者 Mode: leader 则代表集群成功,可以使用以下命令行工具查看效果

ZooKeeper安装目录结构

  • bin:存放系统脚本
  • conf:存放配置文件
  • contrib:附加功能支持
  • dist-maven:maven 仓库文件
  • docs:文档
  • lib:依赖的第三方库
  • recipes:经典场景样例代码
  • src:源码

其中 bin 和 conf 是非常重要的两个目录,平时也是经常使用的

bin目录

常用的两个:zkServer.sh 为服务端,zkCli 为命令行客户端

conf目录

主要是配置文件的参数,其中几个比较重要的如下:

  • clientPort:访问端口,即应用对外服务的端口
  • dataDir:用于存放内存数据库快照的文件夹,同时用于集群的 myid 文件也存在这个文件夹里(注意:一个配置文件只能包含一个 dataDir 字样,即使它被注释掉了),新安装这文件夹里面是没有文件的,可以通过 snapCount 参数配置产生快照的时机
  • snapCount:每进行 snapCount 次事务日志输出后,触发一次快照(snapshot), 此时,ZooKeeper 会生成一个 snapshot.* 文件,同时创建一个新的事务日志文件 log.* ,默认是100000(真正的代码实现中,会进行一定的随机数处理,以避免所有服务器在同一时间进行快照而影响性能)(Java system property:zookeeper.snapCount )
  • dataLogDir:用于单独设置 transaction log 的目录,transaction log 分离可以避免和普通 log 还有快照的竞争
  • tickTime:心跳时间,为了确保连接存在的,以毫秒为单位,最小超时时间为两个心跳时间
  • initLimit:多少个心跳时间内,允许其他 server 连接并初始化数据,如果 ZooKeeper 管理的数据较大,则应相应增大这个值
  • syncLimit:多少个 tickTime 内,允许 follower 同步,如果 follower 落后太多,则会被丢弃

ZooKeeper特性

会话

客户端与服务端的一次会话连接,本质是 TCP 长连接,通过会话可以进行心跳检测和数据传输

会话状态

ZooKeeper 客户端和服务端成功连接后,就创建了一次会话,ZooKeeper 会话在整个运行期间的生命周期中,会在不同的会话状态之间切换,这些状态包括:CONNECTING、CONNECTED、RECONNECTING、RECONNECTED、CLOSE

一旦客户端开始创建 Zookeeper 对象,那么客户端状态就会变成 CONNECTING 状态,同时客户端开始尝试连接服务端,连接成功后,客户端状态变为 CONNECTED,通常情况下,由于断网或其他原因,客户端与服务端之间会出现断开情况,一旦碰到这种情况,Zookeeper 客户端会自动进行重连服务,同时客户端状态再次变成 CONNCTING,直到重新连上服务端后,状态又变为 CONNECTED,在通常情况下,客户端的状态总是介于 CONNECTING 和 CONNECTED 之间。但是,如果出现诸如会话超时、权限检查或是客户端主动退出程序等情况,客户端的状态就会直接变更为 CLOSE 状态

数据模型

ZooKeeper 的视图结构和 Unix 文件系统类似,其中每个节点称为“数据节点”或 ZNode, 每个 znode 可以存储数据,还可以挂载子节点,因此可以称之为“树”,需要注意的是,每一个 znode 都必须有值,如果没有值,节点是不能创建成功的

  • 在 Zookeeper 中,znode 是一个跟 Unix 文件系统路径相似的节点,可以往这个节点存储或获取数据
  • 通过客户端可对 znode 进行增删改查的操作,还可以注册 watcher 监控 znode 的变化

节点类型

zNode有两种节点类型:持久节点(persistent)、临时节点(ephemeral)

  • 持久节点创建:不须其他参数,value可以为任意值,持久节点客户端断开连接后不会删除
create /SunnyBear value
复制代码
  • 临时节点创建:加上 -e 参数即代表创建临时节点,客户端断开连接后会删除
create -e /testSunnyBear ephemeralNodeTest
复制代码

zNode节点有四种形式的目录节点:持节节点、持久顺序节点、临时节点、临时顺序节点

持久节点 和 临时节点 前面已经说了,那么来看下 持久顺序节点 和 临时顺序节点,创建时加上参数 -s 则代表加上了顺序,例如分别创建 持久顺序节点 和 临时顺序节点

create -s /SunnyBear2 tests
# 返回了Created /SunnyBear20000000008

create -e -s /testSunnyBear ephemeralNodeTest
# 返回了Created /testSunnyBear0000000009
复制代码

从上面的结果可以看到,顺就节点即在创建的节点名称后面加上了序号,并且同时需要注意的是,create 命令如果不是创建顺序节点,如果节点名称已经存在是无法创建的,会报错 Node already exists: /SunnyBear ,还有临时节点不允许有子节点

ZooKeeper节点状态属性

属性 数据结构 描述
cZxid long 节点被创建的Zxid值
ctime long 节点被创建的时间
mZxid long 节点被修改的Zxid值
mtime long 节点被修改的时间
pZxid long 子节点最后一次被修改时的Zxid值
cversion long 子节点的版本号
dataVersion long 节点修改的版本号
aclVersion long 节点的ACL被修改的版本号
ephemeralOwner long 如果此节点为临时节点,那么它的值为这个节点持有者的会话ID,否则,它的值为0
dataLength int 节点数据域的长度
numChildren int 节点拥有的子节点的长度
  • 其中 Zxid 为 事务id,可以识别出请求的全局顺序
  • 基于 CAS 理论保证分布式数据原子性操作

ACL保障数据的安全

ACL 机制,表示为 scheme:id:permissions 格式,第一个字段表示采用哪一种机制,第二个 id 表示用户,permissions 表示相关权限(如只读,读写,管理等),详细的命令使用在后面介绍

命令行

服务端常用命令

启动命令:./zkServer.sh start
停止命令:./zkServer.sh stop
重启命令:./zkServer.sh restart
状态查看命令:./zkServer.sh status
复制代码

客户端常用命令

使用 ./zkCli.sh ip:端口 命令连接到 ZooKeeper,连接成功之后就可以使用下面的命令了,前面也提到了一些命令

# 查看当前 ZooKeeper 中根目录下的子节点信息
ls /

# 查看当前 ZooKeeper 中根目录下子节点信息,并能看到更新次数等数据
ls2 /

# 创建节点,这个之前已经提到过了,其中-e代表临时节点,-s代表为顺序节点
create [-e] [-s] zNodeName zNodeValue

# 获取创建节点的信息
get /zNodeName

# 修改节点内容,这个和redis不同,如果key不存在,那么会报错
set /zNodeName zNodeValue

# 删除节点,如果存在子节点删除失败
delte /zNodeName

# 递归删除,子节点同时删除
rmr /zNodeName

# 退出客户端
quit

# 帮助命令
help
复制代码

ACL 命令常用命令

之前提到了ACL命令为 scheme:id:permissions 格式,那么分别看下这三段代表什么

  • schema:代表授权策略
  • id:代表用户
  • permission:代表权限

scheme

scheme有四种方式:

  • world:默认方式,所有人都可以访问
  • auth:代表已经认证通过的用户
  • digest:即用户名:密码这种方式认证,这也是业务系统中最常用的
  • ip:使用ip地址认证

id

和 scheme 一一对应,他也有四种:其中 auth 为明文,digest 为密文

  • world -> anyone
  • auth -> username:password
  • digest -> username:BASE64(SHA1(password))
  • ip -> 客户端ip地址

permission

c(CREATE)、d(DELETE)、r(READ)、w(WRITE)、a(ADMIN)这几个权限,对应增,删,查,改,管理权限,简称cdrwa

  • c:创建子节点的权限
  • d:删除子节点的权限
  • r:读取节点数据的权限
  • w:修改节点数据的权限
  • a: 给子节点授权的管理权限

具体命令

# 获取子节点的ACL信息
getAcl /zNodeName

# 设置子界面ACL信息,例如:
# 设置所有人都可以访问testDir节点,但是却没有删除权限
setAcl /testDir world:anyone:crwa

# 设置auth方式,先增加用户再赋予权限,例如对/testDir目录下的/testAcl1进行操作
create /testDir/testAcl1 testAcl1
addauth digest user1:123456
setAcl /testDir/testAcl1 auth:user1:123456:crwa

# 设置digest方式,这个和auth的区别就是明文密码和密文密码的区别,不适用密文密码会设置失败,所以需要获取密文密码
# 通过shell命令获取密文密码
java -Djava.ext.dirs=/usr/local/zookeeper-3.4.12/lib -cp /usr/local/zookeeper-3.4.12/zookeeper-3.4.12.jar org.apache.zookeeper.server.auth.DigestAuthenticationProvider user2:123456
# 得到结果
user2:123456->user2:hZG2W+NR7DCvADzOkGR6JGLqoTY=
# 接下来就是基本操作了,使用zkCli客户端登录
create /testDir/testAcl2 testAcl2
addauth digest user2:123456
setAcl /testDir/testAcl2 digest:user2:hZG2W+NR7DCvADzOkGR6JGLqoTY=:crw

# 设置ip方式
create /testDir/testAcl3 testAcl3
set /testDir/testAcl3 ip:192.168.31.6:cdrwa
复制代码

设置之后就可以使用命令来测试以下权限是否设置成功了,如果是 auth 和 digest的那么需要登录来获取权限,quit退出连接重新连接ZooKeeper,然后执行下面命令就可测试了

addauth digest user1:123456
复制代码

ZooKeeper日志

前面 conf 配置中提交到 dataDirdataLogDir

  • dataDir :ZooKeeper 的数据目录,主要目的是存储内存数据库序列化后的快照路径,可以通过 snapCount 参数配置产生快照的时机,默认是100000,但是实际源码中会使用 50000 + random(50000) 作为实际产生快照的操作次数,避免多个节点同时产生快照,影响性能。如果没有配置事务日志(即dataLogDir配置项)的路径,那么 ZooKeeper 的事务日志也存放在数据目录中
  • dataLogDir :指定事务日志的存放目录。事务日志对ZooKeeper的影响非常大,强烈建议事务日志目录和数据目录分开,不要将事务日志记录在数据目录(主要用来存放内存数据库快照)下

快照即类似于 Redis 中的RDB,每 50000 + random(50000) 次记录操作就生成快照; 事务日志则类似于 Redis 中的AOF,记录着每一条操作命令

查看快照和事务日志文件内容命令

需要注意的是,下面命令的分隔符在window上是 ; ,在Linux上面是 : ,同时还需要注意 jar版本号 和 文件目录位置,修改为自己的

查看快照:

java -cp ../../zookeeper-3.4.12.jar:../../lib/slf4j-api-1.7.25.jar org.apache.zookeeper.server.SnapshotFormatter snapshot.xxx
复制代码

查看事务日志

java -cp ../../zookeeper-3.4.12.jar:../../lib/slf4j-api-1.7.25.jar org.apache.zookeeper.server.LogFormatter log.xxx
复制代码
我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章