一、zookeeper基本概念
- zookeeper是一个开源的分布式协调服务,由知名互联网公司Yahoo创建,它是Chubby的开源实现;换句话讲,zookeeper是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于它实现数据的发布/订阅、负载均衡、名称服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列;
官网地址http://zookeeper.apache.org
1、集群角色:Leader主节点, Follower从节点, Observer观察员
- Leader:选举产生,读/写;
- Follower:参与选举,可被选举,读服务;
- Observer:参与选举,不可被选举,提供读服务;
2、会话:
- zookeeper中,每个节点客户端和服务端建立一个持久会话,通过会话不断更新节点状态,其他节点也可以获取此节点状态,TCP长连接;可以定义超时时长sessionTimeout;
3、数据节点(ZNode):
- 即zookeeper数据模型中的数据单元;zookeeper的数据都存储于内存中,数据模型为树状结构(ZNode Tree);每个ZNode都会保存自己的数据于内存中;
- 第一类是持久节点:仅显式删除才消失
- 第二类是临时节点:会话中止即自动消失,临时节点不得有子节点。
4、版本(version):
- zookeeper会为每个ZNode维护一个称之为Stat的数据结构,记录了当前ZNode的三个数据版本
- version:当前版本
- cversion:当前znode的子节点的版本
- aversion:当前znode的ACL的版本
5、ACL:
- zookeeper使用ACL机制进行权限控制
- CREATE创建, READ读,WRITE写,DELETE删除,ADMIN管理
6、锁控制机制
版本访问控制机制有两种: 乐观锁机制和悲观锁机制
- 悲观锁机制是读取数据之前先请求锁再读取和修改操作。
- zookeeper使用的是乐观锁,乐观锁相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。而乐观锁机制在一定程度上解决了这个问题。
- 乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
- 为了避免数据干扰,当读取数据之后更新数据之前,会监控此数据是否有其他人读取更新,如果有更新则回滚操作,继续读取,此种occ机制只适合数据并发竞争不大的场景,zookeeper出现并发访问同一节点的情况很小
事件监听器(Watcher):
- zookeeper上,由用户指定的触发机制,在某些事件产生时,zookeeper能够将通知给相关的客户端;
- Watcher是一次性的触发机制,触发后还要注册。
7、ZAB协议:Zookeeper Atomic Broadcast
zookeeper的原子广播协议,作用是在Leader崩溃时候,选举出新的Leader,并保证数据完整性和一致性。
-
ZAB协议中存在三种状态:
- (1) Looking
:每一个节点启动后或新的主节点生成时,寻找leader时候的状态 - (2) Following:找到了集群中的leader,自动转变为从节点Follow状态,并开始同步
- (3) Leading:被选举的变成了leader状态,其他的变成了Follow状态
- (1) Looking
8、ZAB协议的四个阶段:
- 选举:election
- 发现:discovery
- 同步:sync
- 广播:Broadcast
9、zookeeper典型应用场景
- 数据发布/订阅
- 负载均衡
- 命名服务
- 分布式协调/通知
- 集群管理
- Master选举
10、zookeeper部署方式
zookeeper部署方式有三种:
单机模式
- 单个节点实际上不被使用
伪分布式模式
- 单节点上使用,安装多个分布式系统使用不同端口号,实验实验测试使用
分布式模式
- 多节点主机部署的分布式系统,推荐使用
二、安装zookeeper单机模式
1、安装jdk
[root@node-61 ~]# yum install epel-release -y
#安装jdk
[root@node-61 ~]# yum install java-1.8.0-openjdk-devel -y
#设置环境变量
[root@node-62 ~]# vim /etc/profile.d/java.sh
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin
[root@node-61 ~]# . /etc/profile.d/java.sh
#验证版本
[root@node-61 ~]# java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
2、下载解压zookeeper,下载地址http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.10/
#下载
[root@node-61 ~]# wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz
#解压到指定目录
[root@node-61 ~]# tar xf zookeeper-3.4.10.tar.gz -C /usr/local/
#创建软连接
[root@node-61 ~]# ln -sv /usr/local/zookeeper-3.4.10 /usr/local/zookeeper
‘/usr/local/zookeeper’ -> ‘/usr/local/zookeeper-3.4.10’
3、修改配置文件
[root@node-61 ~]# cp /usr/local/zookeeper/conf/zoo_sample.cfg /usr/local/zookeeper/conf/zoo.cfg
[root@node-61 ~]# vim /usr/local/zookeeper/conf/zoo.cfg
tickTime=2000 #向zk发送心跳的时长,单位毫秒,这里代表2秒
initLimit=10 #初始同步时候要经过多少个tickTime心跳时长
syncLimit=5 #发送一个请求时长要多少个tickTime心跳时长
dataDir=/data/zookeeper #数据目录
clientPort=2181 #自己监听的端口
#maxClientCnxns=60 #最大并发连接数
server.1=192.168.1.61:2888:3888 #集群内的主机地址端口
zoo.cfg配置文件的参数:
基本配置参数:
clientPort:端口默认是2181
dataDir:数据存储目录,建议使用自定义的目录
dataLogDir:事务日志文件路径,建议不要和数据目录在一起
tickTime:向zk发送心跳的时长,其他时间配置的基础单位
存储配置参数:
preAllocSize:为事务日志预先分配的磁盘空间两;默认是65535KB;
snapCount:没多少次事务执行一次快照操作:每事务的平均大小在100字节;
autopurget.snapRetaincount:快照的修剪
autopurget.purgeInterval:修剪操作的时间间隔,0代表不启动;
fsync.warnlngthresholdms:zk进行事务日志fsync操作时消耗的时长报警阈值;
weight.X=N:判断quorum时候投票权限,默认为1;
网络配置参数:
maxClientCnxns:每客户端IP的最大并发连接数;
clientPortAddress:zk监听IP的地址;
minSessionTimeout:会话的最短超时时长;
maxSessionTimeout:会话的最大超时时长;
集群配置参数:
initLimit:Follower连入Leader并完成数据同步的时长,这个值是 tickTime倍数,默认是10倍,取决于数据集大小和网络带宽;
syncLimit:心跳检测的最大延迟;
leaderServes:默认zk的leader接收读写请求,额外还要负责协调各Follower发来的事务等;因此,为使得leader集中处理zk集群内部信息,建议不让leader直接提供服务
cnxTimeout:Leader选举期间,个服务器创建TCP连接的超时时长 ;
ellectionAlg:选举算法,目前只支持
FastLeaderElection算法一种;
指定主机的语法格式:server.ID=[hostname]:port:port[:observer]
ID:各主机的数字标识,一般以1开始
hostname:各主机名,也可以是ip地址
第一个port:follower与leader进行通信和数据同步时候使用的端口;
第二个port:leader选举时候使用的端口;
observer:定义指定的服务器为observer;
4、启动zookeeper
#切换目录
[root@node-61 ~]# cd /usr/local/zookeeper/bin/
#查看启动脚本
[root@node-61 bin]# ls
README.txt zkCli.cmd zkEnv.cmd zkServer.cmd
zkCleanup.sh zkCli.sh zkEnv.sh zkServer.sh
#启动zookeeper
[root@node-61 bin]# . zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.10/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
#已启动
[root@node-61 ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 50 :::2181 :::*
三、连接测试和zkCli命令
- 常用的zkCli命令有:create,ls,ls2,stat,delete,rmr,get,set等
#连接
[root@node-61 ~]# . /usr/local/zookeeper/bin/zkCli.sh -h
......
[zk: localhost:2181(CONNECTED) 0] ? #?号显示命令
ZooKeeper -server host:port cmd args
stat path [watch]
set path data [version] #更新指定路径的值
ls path [watch]
delquota [-n|-b] path
ls2 path [watch] #列出指定目录下的所有一级节点,和属性信息
setAcl path acl #设置访问控制列表
setquota -n|-b val path
history #历史
redo cmdno
printwatches on|off
delete path [version] #删除路径
sync path #同步
listquota path
rmr path #递归删除指定路径
get path [watch] #获取内容
create [-s] [-e] path data acl #创建路径并赋予数据和访问控制列表acl,-s代表持久节点,-e代表临时节点
addauth scheme auth
quit #退出
getAcl path #获取acl
close
connect host:port #连接主机,主机名加端口
# create创建目录,这里不写-s、-e则代表持久节点
[zk: localhost:2181(CONNECTED) 1] create /test "test"
Created /test
[zk: localhost:2181(CONNECTED) 2] ls /
[zookeeper, test]
# ls2查询
[zk: localhost:2181(CONNECTED) 3] ls2 /test
[]
cZxid = 0x2
ctime = Wed Feb 27 23:03:08 CST 2019
mZxid = 0x2
mtime = Wed Feb 27 23:03:08 CST 2019
pZxid = 0x2
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
#get获取指定路径内容
[zk: localhost:2181(CONNECTED) 4] get /test
test
cZxid = 0x2
ctime = Wed Feb 27 23:03:08 CST 2019
mZxid = 0x2
mtime = Wed Feb 27 23:03:08 CST 2019
pZxid = 0x2
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
#set更新指定路径的值
[zk: localhost:2181(CONNECTED) 5] set /test "hello"
cZxid = 0x2
ctime = Wed Feb 27 23:03:08 CST 2019
mZxid = 0x3
mtime = Wed Feb 27 23:11:30 CST 2019
pZxid = 0x2
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
#delete删除指定路径
[zk: localhost:2181(CONNECTED)7] delete /test
#rmr递归删除
[zk: localhost:2181(CONNECTED) 8] ls /test/node
[]
[zk: localhost:2181(CONNECTED) 10] rmr /test
节点信息
[zk: localhost:2181(CONNECTED) 13] stat /test
cZxid = 0x7 #这个值是当前会话事物创建产生ID
ctime = Wed Feb 27 23:28:00 CST 2019 #创建时间
mZxid = 0x7 #最近更新节点的事物ID
mtime = Wed Feb 27 23:28:00 CST 2019 #最近修改时间
pZxid = 0x7 #该节点的子节点最后修改的事物ID
cversion = 0 #子节点的版本号
dataVersion = 0 #数据的版本号
aclVersion = 0 #acl的版本号
ephemeralOwner = 0x0 #创建此临时节点的会话ID
dataLength = 4 #数据长度
numChildren = 0 #子节点的个数
版本号一般表示数据被修改的次数
四、zookeeper的监控命令
- 一般称为四字命令,因为命令只有四个字符,用来实现对zookeeper里面的数据进行简单的监控、更新和修改。
- 常用的监控zk的四字命令有:ruok,stat,srvr,conf,cons,wchs,envi(监控java环境)
#安装Telnet工具
[root@node-61 ~]# yum install telnet -y
#连接本机端口,测试是否安装zookeeper
[root@node-61 ~]# telnet localhost 2181
Trying ::1...
Connected to localhost.
Escape character is '^]'.
ruok #输入
imokConnection closed by foreign host.
#连接本机端口,获取主机信息
[root@node-61 ~]# telnet localhost 2181
Trying ::1...
Connected to localhost.
Escape character is '^]'.
stat #输入
Zookeeper version: 3.4.10-39d3a4f269333c922ed3db283be479f9deacaa0f, built on 03/23/2017 10:13 GMT #版本和构建时间
Clients:
/0:0:0:0:0:0:0:1:40946[0](queued=0,recved=1,sent=0) #客户端信息
Latency min/avg/max: 0/0/27 #延迟的最小值、平均值、最大值
Received: 361
Sent: 360
Connections: 1
Outstanding: 0
Zxid: 0xa
Mode: standalone
Node count: 5
Connection closed by foreign host.
#连接本机端口,获取server信息
[root@node-61 ~]# telnet localhost 2181
Trying ::1...
Connected to localhost.
Escape character is '^]'.
srvr
Zookeeper version: 3.4.10-39d3a4f269333c922ed3db283be479f9deacaa0f, built on 03/23/2017 10:13 GMT #版本和构建时间
Latency min/avg/max: 0/0/27 #延迟的最小值、平均值、最大值
Received: 362
Sent: 361
Connections: 1
Outstanding: 0
Zxid: 0xa
Mode: standalone
Node count: 5
Connection closed by foreign host.
#连接本机端口,获取配置信息
[root@node-61 ~]# telnet localhost 2181
Trying ::1...
Connected to localhost.
Escape character is '^]'.
conf #输入
clientPort=2181
dataDir=/data/zookeeper/version-2
dataLogDir=/data/zookeeper/zk_log/version-2
tickTime=2000
maxClientCnxns=60
minSessionTimeout=4000
maxSessionTimeout=40000
serverId=0
Connection closed by foreign host.
五、遇到的问题:
- 一般使用yum安装jdk无需配置java变量,yum会自动配置java环境变量,编译安装jdk需手动配置。
zookeeper启动报错:
[root@node-62 ~]# . /usr/local/zookeeper/bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config:
Starting zookeeper ... [1]+ Exit 127 nohup "$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" -cp "$CLASSPATH" $JVMFLAGS $ZOOMAIN "$ZOOCFG" > "$_ZOO_DAEMON_OUT" 2>&1 < /dev/null
STARTED
原因是java环境变量路径设置问题
解决方法:
#指明安装的openjdk路径
[root@node-61 ~]# vim /etc/profile.d/java.sh
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk