
特点 数据结构Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。
Zookeeper从设计模式角度来理解,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生了变化,Zookeeper就负责通知已经在Zookeeper上注册的那些观察者做出相应的反应.
下载地址ZK中没有文件的概念,节点下直接存的就是内容
Zookeeper安装https://zookeeper.apache.org/
单机模式的安装以及简单操作本次使用的版本是:apache-zookeeper-3.5.7-bin.tar.gz
本地单机安装步骤
① 把软件包上传的Linux的 /opt/software 下
② 加压ZK到 /opt/module 下
③ 将加压后的目录名称修改一下:apache-zookeeper-3.5.7(选做)
④ 将zk的安装目录下 conf/zoo_sample.cfg 文件改名为 zoo.cfg
⑤ 在ZK的安装目录下创建一个新的目录zkData,作为zk的数据持久化目录
⑤ 修改zoo.cfg配置文件 dataDir=/opt/module/zookeeper-3.5.7/zkData
⑥ 配置ZK的环境变量 (选做)
启停zk服务端 和 zk客户端
# 启动zk server zkServer.sh start # 启动zk client zkCli.sh -server host:port #查看一下zk的服务端和客户端对应的进程: jps QuorumPeerMain --> 服务端 ZooKeeperMain --> 客户端 # 退出客户端 quit
配置参数解读
# 通信心跳数,Zookeeper服务器与客户端心跳时间,单位毫秒,用于心跳机制,并且设置最小的session超时时间为两倍心跳时间,4s tickTime=2000 # 集群中的Follower跟随者服务器与Leader领导者服务器之间初始连接时能容忍的最多心跳数(tickTime的数量),用它来限定集群中的Zookeeper服务器连接到Leader的时限。 initLimit=10 #集群中Leader与Follower之间的最大响应时间单位,假如响应超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer。 syncLimit=5 dataDir=/opt/module/zookeeper-3.5.7/zkData clientPort=2181搭建Zookeeper集群以及封装群启脚本
注意事项:如果不是第一次搭建集群,那么就把zk安装目录下的zkData目录
删除,并且把logs目录也删除
1. 在ZK的安装目录下创建 zkData 2. 修改zoo.cfg 配置文件 -- dataDir=/opt/module/zookeeper-3.5.7/zkData -- server.2=hadoop102:2888:3888 server.3=hadoop103:2888:3888 server.4=hadoop104:2888:3888 3. 在ZK的安装目录下的zkData目录中创建一个myid的文件 用于标记当前服务器的编号 hadoop102 --> 2 5. 将hadoop102的整个ZK的安装目录分发到103,104 [atguigu@hadoop102 module]$ my_rsync zookeeper-3.5.7/ 6. 在不同机器上修改myid文件中的值 hadoop103 --> 3 hadoop104 --> 4
至此,zk集群的配置完毕,简单把
各自启动zkServer
# bin/zkServer.sh start [atguigu@hadoop102 zookeeper-3.5.7]$ bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [atguigu@hadoop102 zookeeper-3.5.7]$ my_jps.sh hadoop102,hadoop103,hadoop104进程启动情况 =================hadoop102 jps情况================= 1207 Jps 1143 QuorumPeerMain =================hadoop103 jps情况================= 1204 Jps 1150 QuorumPeerMain =================hadoop104 jps情况================= 1612 Jps 1565 QuorumPeerMain # 查看当前zk的状态 [atguigu@hadoop102 zookeeper-3.5.7]$ bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Mode: follower # 发现为follower 从机 [atguigu@hadoop102 zookeeper-3.5.7]$
群启zk脚本
[atguigu@hadoop102 bin]$ pwd /home/atguigu/bin [atguigu@hadoop102 bin]$ touch zk_cluster.sh [atguigu@hadoop102 bin]$ # 编写如下群启脚本
#!/bin/bash if [ $# -lt 1 ] then echo '参数不能为空!' exit fi for host in hadoop102 hadoop103 hadoop104 do case $1 in "start") echo "$1===========$host===========ZK" ssh $host /opt/module/zookeeper-3.5.7/bin/zkServer.sh $1 ;; "stop") echo "$1===========$host===========ZK" ssh $host /opt/module/zookeeper-3.5.7/bin/zkServer.sh $1 ;; "status") echo "$1===========$host===========ZK" ssh $host /opt/module/zookeeper-3.5.7/bin/zkServer.sh $1 ;; *) echo "$1===========参数错误===========" exit ;; esac done
# 授权 [atguigu@hadoop102 bin]$ chmod 744 zk_cluster.sh [atguigu@hadoop102 bin]$ ll 总用量 16 -rwxr--r--. 1 atguigu atguigu 945 9月 20 22:43 my_cluster.sh -rwxr--r--. 1 atguigu atguigu 219 9月 20 17:15 my_jps.sh -rwxr--r--. 1 atguigu atguigu 672 9月 20 00:31 my_rsync.sh -rwxr--r--. 1 atguigu atguigu 544 9月 27 00:57 zk_cluster.sh
群启集群
[atguigu@hadoop102 module]$ zk_cluster.sh start start===========hadoop102===========ZK ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg Starting zookeeper ... STARTED start===========hadoop103===========ZK ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg Starting zookeeper ... STARTED start===========hadoop104===========ZK ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [atguigu@hadoop102 module]$ zk_cluster.sh status status===========hadoop102===========ZK ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Mode: follower status===========hadoop103===========ZK ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Mode: leader status===========hadoop104===========ZK ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Mode: follower [atguigu@hadoop102 module]$Zookeeper实战 分布式安装部署 客户端命令行操作
# 启动zk集群 [atguigu@hadoop102 module]$ zk_cluster.sh start # 开启客户端连接zk [atguigu@hadoop102 module]$ bin/zkCli.sh -server hadoop102:2181
基本命令
| 命令基本语法 | 功能描述 |
|---|---|
| help | 显示所有操作命令 |
| ls path | 使用 ls 命令来查看当前znode的子节点-w 监听子节点变化-s 附加次级信息 |
| create | 普通创建-s 含有序列-e 临时(重启或者超时消失) |
| get path | 获得节点的值-w 监听节点内容变化-s 附加次级信息 |
| set | 设置节点的具体值 |
| stat | 查看节点状态 |
| delete | 删除节点 |
| deleteall | 递归删除节点 |
1)启动客户端 [atguigu@hadoop103 zookeeper-3.5.7]$ bin/zkCli.sh 2)显示所有操作命令 [zk: localhost:2181(CONNECTED) 1] help 3)查看当前znode中所包含的内容 [zk: localhost:2181(CONNECTED) 0] ls / [zookeeper] 4)查看当前节点详细数据 [zk: localhost:2181(CONNECTED) 1] ls -s / [zookeeper] cZxid = 0x0 ctime = Thu Jan 01 08:00:00 CST 1970 mZxid = 0x0 mtime = Thu Jan 01 08:00:00 CST 1970 pZxid = 0x0 cversion = -1 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 0 numChildren = 1 5)分别创建2个普通节点 [zk: localhost:2181(CONNECTED) 3] create /sanguo "diaochan" Created /sanguo [zk: localhost:2181(CONNECTED) 4] create /sanguo/shuguo "liubei" Created /sanguo/shuguo 6)获得节点的值 [zk: localhost:2181(CONNECTED) 5] get /sanguo diaochan [zk: localhost:2181(CONNECTED) 6] get -s /sanguo diaochan cZxid = 0x100000003 ctime = Wed Aug 29 00:03:23 CST 2018 mZxid = 0x100000003 mtime = Wed Aug 29 00:03:23 CST 2018 pZxid = 0x100000004 cversion = 1 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 7 numChildren = 1 [zk: localhost:2181(CONNECTED) 7] [zk: localhost:2181(CONNECTED) 7] get -s /sanguo/shuguo liubei cZxid = 0x100000004 ctime = Wed Aug 29 00:04:35 CST 2018 mZxid = 0x100000004 mtime = Wed Aug 29 00:04:35 CST 2018 pZxid = 0x100000004 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 6 numChildren = 0 7)创建临时节点 [zk: localhost:2181(CONNECTED) 7] create -e /sanguo/wuguo "zhouyu" Created /sanguo/wuguo (1)在当前客户端是能查看到的 [zk: localhost:2181(CONNECTED) 3] ls /sanguo [wuguo, shuguo] (2)退出当前客户端然后再重启客户端 [zk: localhost:2181(CONNECTED) 12] quit [atguigu@hadoop104 zookeeper-3.5.7]$ bin/zkCli.sh (3)再次查看根目录下短暂节点已经删除 [zk: localhost:2181(CONNECTED) 0] ls /sanguo [shuguo] 8)创建带序号的节点 (1)先创建一个普通的根节点/sanguo/weiguo [zk: localhost:2181(CONNECTED) 1] create /sanguo/weiguo "caocao" Created /sanguo/weiguo (2)创建带序号的节点 [zk: localhost:2181(CONNECTED) 2] create /sanguo/weiguo "caocao" Node already exists: /sanguo/weiguo [zk: localhost:2181(CONNECTED) 3] create -s /sanguo/weiguo "caocao" Created /sanguo/weiguo0000000000 [zk: localhost:2181(CONNECTED) 4] create -s /sanguo/weiguo "caocao" Created /sanguo/weiguo0000000001 [zk: localhost:2181(CONNECTED) 5] create -s /sanguo/weiguo "caocao" Created /sanguo/weiguo0000000002 [zk: localhost:2181(CONNECTED) 6] ls /sanguo [shuguo, weiguo, weiguo0000000000, weiguo0000000001, weiguo0000000002, wuguo] [zk: localhost:2181(CONNECTED) 6] 如果节点下原来没有子节点,序号从0开始依次递增。如果原节点下已有2个节点,则再排序时从2开始,以此类推。 9)修改节点数据值 [zk: localhost:2181(CONNECTED) 6] set /sanguo/weiguo "caopi" 10)节点的值变化监听 (1)在hadoop104主机上注册监听/sanguo节点数据变化 [zk: localhost:2181(CONNECTED) 26] [zk: localhost:2181(CONNECTED) 8] get -w /sanguo (2)在hadoop103主机上修改/sanguo节点的数据 [zk: localhost:2181(CONNECTED) 1] set /sanguo "xishi" (3)观察hadoop104主机收到数据变化的监听 WATCHER:: WatchedEvent state:SyncConnected type:NodeDataChanged path:/sanguo 11)节点的子节点变化监听(路径变化) (1)在hadoop104主机上注册监听/sanguo节点的子节点变化 [zk: localhost:2181(CONNECTED) 1] ls -w /sanguo [aa0000000001, server101] (2)在hadoop103主机/sanguo节点上创建子节点 [zk: localhost:2181(CONNECTED) 2] create /sanguo/jin "simayi" Created /sanguo/jin (3)观察hadoop104主机收到子节点变化的监听 WATCHER:: WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/sanguo 12)删除节点 [zk: localhost:2181(CONNECTED) 4] delete /sanguo/jin 13)递归删除节点 [zk: localhost:2181(CONNECTED) 15] deleteall /sanguo/shuguo 14)查看节点状态 [zk: localhost:2181(CONNECTED) 17] stat /sanguo cZxid = 0x100000003 ctime = Wed Aug 29 00:03:23 CST 2018 mZxid = 0x100000011 mtime = Wed Aug 29 00:21:23 CST 2018 pZxid = 0x100000014 cversion = 9 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 4 numChildren = 1Zookeeper内部原理 节点类型
持久(Persistent)
客户端和服务器端断开连接后,创建的节点不删除
短暂(Ephemeral)
客户端和服务器端断开连接后,创建的节点自己删除
(1)持久化目录节点 客户端与zk断开连接后,该节点依旧存在 (2)持久化顺序编号目录节点 客户端与zk断开连接后,该节点依旧存在,只是zk给该节点名称进行顺序编号 (3)临时目录节点 客户端与zk断开连接后,该节点被删除 (4)临时顺序编号目录节点 客户端与zk断开连接后,该节点被删除,只是zk给该节点名称进行顺序编号Stat结构体
使用 stat 路径命令可获得一个结构体对象
[zk: hadoop102:2181(CONNECTED) 6] stat / cZxid = 0x0 ctime = Thu Jan 01 08:00:00 CST 1970 mZxid = 0x0 mtime = Thu Jan 01 08:00:00 CST 1970 pZxid = 0x200000018 cversion = 7 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 0 numChildren = 1
# 属性解释 (1)czxid-创建节点的事务zxid 每次修改ZooKeeper状态都会收到一个zxid形式的时间戳,也就是ZooKeeper事务ID。 事务ID是ZooKeeper中所有修改总的次序。每个修改都有唯一的zxid,如果zxid1小于zxid2,那么zxid1在zxid2之前发生。 (2)ctime - znode被创建的毫秒数(从1970年开始) (3)mzxid - znode最后更新的事务zxid (4)mtime - znode最后修改的毫秒数(从1970年开始) (5)pZxid-znode最后更新的子节点zxid (6)cversion - znode子节点变化号,znode子节点修改次数 (7)dataversion - znode数据变化号 (8)aclVersion - znode访问控制列表的变化号 (9)ephemeralOwner- 如果是临时节点,这个是znode拥有者的session id。如果不是临时节点则是0。 (10)dataLength- znode的数据长度 (11)numChildren - znode子节点数量监听器原理
总结大致原理
zookeeper其实本质上就是一个文件系统加通知机制的这么一个框架,咱们通常用的都是管理一些框架的综合信息来协调我们整个各个服务之间的一个工作,首先呢,我们这个服务会到zookeeper去注册自己,注册的时候呢,其实就是在这个zookeeper的这个监听列表里边也添加一个监听事件。然后呢,我们在获取zookeeper连接对象的时候,在这个watcher对象里边去写这个提供好这个process的方法,只要我们将来啊,只要将来这个zookeeper上维护的数据发生了变化,它立刻会通过这个监听列表找到我,然后调用我listener这个线程啊。从而调用我的process方法,然后通知到我,做相应的变化就可以了。选举机制
选举机制总原则:集群中的每台机器都参与投票,通过交换选票得到每台机器的最终得票,一旦出现得票数超过机器总数一半以上数量,当前机器即为leader。
举例说明
场景1:以5台机器为例,集群的机器顺时启动,当前集群中没有任何数据。
①. server1 启动,首先server1给自己投一票,然后看当前票数是否超过半数,结果没有超过, 这时候leader就没选出来,当前选举状态是Locking状态。 ②. server2 启动,首先server2先给自己投一票,因为当前集群已经有两台机器已启动,所以server1,server2会交换选票,交换后发现各自有一票,接下来比较myid 发现server2的myid值 > server2的myid值,此时server2胜出,最后server2有两票。最后再看当前票数是否半,发现未过半,集群的选举状态.集训保持locking状态。 ③. server3启动, 首先自己投自己一票,server1和server2也会投自己一票,然后交换选票发现都一样, 接着比较myid 最后server3胜出,此时server3就有3票,同时server3的票数超过半数。所以server3成为 leader。 ④. server4启动,发现当前集群已经有leader 它自己自动成为follower ⑤. server5启动,发现当前集群已经有leader 它自己自动成为follower
场景2:以5台机器为例,当前集群正在使用(有数据/没数据),leader突然宕机的情况。
当集群中的leader挂掉,集群会重新选出一个leader,此时首先会比较每一台机器的czxid, czxid最大的被选为leader。极端情况,czxid都相等的情况,那么就会直接比较myid。
一般情况下ZK集群更推荐使用奇数台机器原因?
在ZK集群中 奇数台 和 偶数台(接近的台数) 机器的容错能力是一样的,所以在考虑资源节省的情况,我们推荐使用奇数台方案写数据流程
1. 客户端会向ZK集群中的一台机器server1发送写数据的请求。 2. server1接收到请求后,马上会通知leader 有写数据的请求来了 3. leader拿到请求后,进行广播,让集群每一台机器都准备要写数据 4. 集群中的所有机机器接收到leader广播后都回应一下leader 5. leader再次进行广播 开始写数据,其他机器接收到广播后也开始写数据 6. 数据成功写入后,回应leader,最后由leader来做整个事务提交 7. 当数据成功写入后,有最初和客户端发生连接的 server1 回应客户端数据写入成功。