1.单机
1.准备 Java 环境
2.下载 ZooKeeper 安装包
https://www.apache.org/dyn/closer.cgi/zookeeper/
3.解压
tar -xzvf zookeeper-3.4.14.tar.gz /usr/local
4.配置文件 zoo.cfg
cp /usr/local/zookeeper-3.4.14/conf/zoo_sample.cfg /usr/local/zookeeper-3.4.14/conf/conf/zoo.cfg
具体配置
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper
dataLogDir=/tmp/zookeeper/logs
clientPort=2181
server.1=192.168.0.116:2888:3888
5.启动
/usr/local/zookeeper-3.4.14/bin/zkServer.sh start
6.验证
telnet 192.168.0.116 2181
stat
Mode : standalone
2.集群
机器1 : 192.168.0.116
机器2 : 192.168.0.115
机器3 : 192.168.0.102
1.编辑 zoo.cfg 文件
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper
dataLogDir=/tmp/zookeeper/logs
clientPort=2181
server.1=192.168.0.116:2888:3888
server.2=192.168.0.115:2888:3888
server.3=192.168.0.102:2888:3888
2.创建 /tmp/zookeeper/myid(dataDir 指定的目录) 文件,写入 Server ID
3.分别在3台机器启动
4.验证
telnet 192.168.0.116 2181
stat
Mode : leader/follower
说明:
1.在集群模式下,集群中的每一台服务器都需要感知到整个集群是由哪几台机器组成的,在配置文件中,可以按照这样的格式进行配置,每一行都代表一个机器配置:
server.id=host.port:port
其中,id被称为 Server ID,用来标识该机器在集群中的机器序号。同时,在每台 zookeeper 机器上,我们都需要在数据目录(即 dataDir 参数指定的那个目录)
下创建一个 myid 文件,该文件只有一行内容,并且是一个数字,即对应于每台机器的 Server ID 数字。
2.在 zookeeper 的设计中,集群中所有机器上 zoo.cfg 文件的内容应该都是一致的。因此最好使用 svn 或者是 git 管理起来。。
3.上面也提到了,myid 文件中只有一个数字,即一个 Server ID。注意,请确保每个服务器的 myid 文件中的数字不同,并且和自己所在机器的 zoo.cfg 中
server.id=host:port:port 的 id 一致。另外 id 的范围是 1~255。
./zkServer.sh status 查看角色
3.伪集群模式
1.创建zoo1.cfg,zoo2.cfg,zoo3.cfg
vim zoo1.cfg :
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper/1
dataLogDir=/tmp/zookeeper/logs/1
clientPort=2181
server.1=192.168.0.116:2888:3888
server.2=192.168.0.116:2889:3889
server.3=192.168.0.116:2890:3890
vim zoo2.cfg :
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper/2
dataLogDir=/tmp/zookeeper/logs/2
clientPort=2182
server.1=192.168.0.116:2888:3888
server.2=192.168.0.116:2889:3889
server.3=192.168.0.116:2890:3890
vim zoo3.cfg :
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper/3
dataLogDir=/tmp/zookeeper/logs/3
clientPort=2183
server.1=192.168.0.116:2888:3888
server.2=192.168.0.116:2889:3889
server.3=192.168.0.116:2890:3890
2.创建 myid
echo 1 > /tmp/zookeeper/1/myid
echo 2 > /tmp/zookeeper/2/myid
echo 3 > /tmp/zookeeper/3/myid
3.启动
../bin/zkServer.sh start zoo1.cfg
../bin/zkServer.sh start zoo2.cfg
../bin/zkServer.sh start zoo3.cfg
4.查看状态
../bin/zkServer.sh status zoo1.cfg
../bin/zkServer.sh status zoo2.cfg
../bin/zkServer.sh status zoo3.cfg
4.运行服务
1.启动服务
1.Java 命令行
2.zookeeper 自带命令行
zkCleanup.sh //清理 zookeeper 历史数据,包括事务日志文件和快照数据文件
zkCli.sh // zookeeper 的一个简易客户端
zkEnv.sh // 设置 zookeeper 的环境变量
zkServer.sh // zookeeper 服务器启动,停止和重启脚本
5.客户端脚本
./zkCli.sh //默认本地的 zookeeper 服务器
./zkCli.sh -server ip:port // 指定 zookeeper 服务器,./zkCli.sh -server 192.168.0.116:2182
1.创建
create [-s] [-e] path data acl
其中,-s 或者 -e 分别指定节点的特性:顺序或者临时节点。默认情况下是,即不添加-s 或 -e 参数的,创建的是持久节点。
create /zk-book 123
执行完上面的命令后,就在 zookeeper 的根节点下创建了一个叫做 /zk-book 的节点,并且节点的内容是 123。另外,create
命令的最后一个参数是 acl,它是用来进行权限控制的,缺省情况下,不做任何权限控制。
2.读取
ls path [watch]
使用 ls 命令,可以列出 zookeeper 指定节点下的所有子节点。当然,这个命令只能看到指定节点下第一级的所有子节点。
ls /
第一次部署的 zookeeper 集群,默认在根节点 '/' 下面又个叫做 /zookeeper 的保留节点。
get path [watch]
使用 get 命令,可以获取 zookeeper 指定节点的数据内容和属性信息。
get /zk-book
123 //数据内容
cZxid = 0x30000000c //创建该事务节点的事务id (cZxid)
ctime = Sat Sep 21 18:25:40 CST 2019
mZxid = 0x30000000c //最后一次更新该节点的事务id (mZxid)
mtime = Sat Sep 21 18:25:40 CST 2019 //最后一次更新该节点的是时间 (mtime)
pZxid = 0x30000000c
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
3.更新
set path data [version]
其中,data 就是要更新的内容。注意,set 命令后面还有一个 version 参数,在 zookeeper 中,节点的数据是有版本的概念的,这个参数用于
指定本次更新操作是基于 ZNode 的哪一个数据版本进的。
set /zk-book 456
dataVersion 从 0 变成 1
4.删除
delete path [version]
version 参数和 set 一样。
注意:要删除某个指定的节点,该节点必须没有子节点存在。
6.Java 客户端 API 使用
注意,zookeeper 客户端和服务端会话的建立是一个异步的过程,也就是说在程序中,构造方法会处理完客户端初始化工作后立即返回,在大多数的情况下,
此时并没有真正的建立好一个可用的会话,在会话的生命周期中处于 'CONNECTING' 的状态。
当该会话真正创建完毕后,zookeeper 服务端会向会话对应的客户端发送一个事件通知,已告知客户端,客户端只有在获取这个通知后,才算真正的建立了
会话。
CAS(Compare and Swap):在 <<Java 并发编程实践>> 中提到,在现代大多数的计算机处理器体系架构中,都实现了对 cas 的指令支持。通俗的讲,
CAS 的意思是 '对于值 V,每次更新前都会比较对其值是否是预期值A,只有符合预期,才会将 V 原子化的更新到新值 B'。zookeeper 的 setData接口
中的 version 参数正是由 CAS 原理演化而来的。从前面的介绍中,我们已经了解到,zookeeper 的每个节点都是数据版本的概念,在调用更新操作的时候,
就可以添加 version 这个参数,该参数可以对应于 cas 原理中的 '预期值',表明的是对该数据版本进行更新的。具体来说,假如一个客户端试图进行更新
操作,它会携带上次获取到的 version 值进行更新。而如果在这段时间内,zookeeper 服务器上该节点的服务恰好被其他客户端更新了,那么其数据版本也
一定发生了变化,因此肯定与客户端携带的 version 无法匹配,于是便无法更新成功 --- 因此可以有效的避免一些分布式更新并发问题,zookeeper 的
客户端就可以利用该特性构建更复杂的应用场景,如分布式锁服务等。
7.开源客户端
1.ZkClient
2.Curator
Master 选举:
在分布式系统中,经常碰到这样的场景:对于一个复杂的任务,仅需要从集群中选举出一台进行处理即可。诸如此类的分布式问题,我们统称为'Master 选举'。
借助 zookeeper,我们可以很方便的实现 Master 选举的功能,其大体思路非常简单:
选举一个根节点,例如 /master_select, 多台机器同时向该节点创建一个子节点 /master_select/lock, 利用 zookeeper 的特性,最终只有一台机器
能够创建成功,成功的那台机器就是 Master。
分布式锁
分布式计数器:
基于 zookeeper 的分布式计数器的实现思路:指定一个 zookeeper 数据节点作为计数器,多个应用实例在分布式锁的控制下,通过更新该数据节点的内容
来实现计数功能。
分布式 Barrier :
Barrier 是一种用来控制多线程之间同步的经典方式。