什么是zookeeper应用场景基本的操作 安装部署shell客户端java端基本原理 选举机制数据一致性数据的读写流程1 zookeeper简介
zookeeper是一个底层的集群协调工具,(比如:NN和DN之间的状态感应;监控 通知)!
具备基本的功能有 ,记录用户的状态数据 (写), 返回用户的数据(读) ,监控和通知。zookeeper为了高可用和安全性是一个集群! 3台(每个节点的数据完全一致)!
2 应用场景写数据读取数据监控通知2.1 服务状态感知 2.2 分布式锁 2.3 分布式配置同步
2.4 统一域名
3 操作 3.1 安装分布式中统一CMD指令
分布式中服务器的状态感知
zookeeper在部署的时候选择奇数台!要求zk集群半数以上的机器在线才能正常工作!
上传解压
在zk安装目录下 创建文件夹 zkData mkdir zkData /opt/apps/zookeeper-3.4.6/zkData修改conf/下的配置模板配置文件名 mv zoo_sample.cfg zoo.cfg vi zoo.cfg配置
dataDir=/opt/apps/zookeeper-3.4.6/zkData# Set to "0" to disable auto purge feature#autopurge.purgeInterval=1server.1=linux01:2888:3888server.2=linux02:2888:3888server.3=linux03:2888:3888
在zkData文件夹下创建myid文件 echo 1 > zkData/myid同步安装包
scp -r zookeeper-3.4.6/ linux02:$PWDscp -r zookeeper-3.4.6/ linux03:$PWD
修改各个节点myid的值 linux02【2】 linux03【3】
启动集群
在各个节点上启动ZK服务
/opt/apps/zookeeper-3.4.6/bin/zkServer.sh start
查看进程 jps
[root@linux01 bin]# jps1697 QuorumPeerMain1720 Jps
查看集群状态 在每个节点执行
/opt/apps/zookeeper-3.4.6/bin/zkServer.sh status-------------------------------------------------------Mode: followerMode: leaderMode: follower
3.2 编写一键启动脚本#!/bin/bash# zk启停脚本 for hostname in linux01 linux02 linux03do echo "连接${hostname}..、...正在执行 $1"ssh ${hostname} "source /etc/profile ;/opt/apps/zookeeper-3.4.6/bin/zkServer.sh $1 ;exit"done
3.3 shell操作zookeeper中记录数据以Tree节点的形式存储数据的/类似于目录树!
目录叫znode : 节点的组织数据是 K V
基本操作指令
# 客户端连接 bin/zkCli.sh 连接到本地zk服务bin/zkCli.sh -server linux02:2181 连接到执行节点的服务quit 退出客户端 ctrl+c-------------------------------------------help 帮助命令 查看系统支持的所有的命令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 * addauth scheme auth quit * getAcl path close * connect host:port-------------------------------------------------------------------创建节点 节点必须以/开头 (路径必须是绝对路径)-- create [-s] [-e] path data aclcreate /a 1 create /b 2 create /a/a1 11create /a/a2 22create /a/a3 33 [-s] 在节点后面添加一个自增的id 防止节点名重复而创建失败[-e] 创建的节点是临时节点 , 只在当前连接中有效------节点分类-------临时节点 临时有序 -e 临时无序 -e -s--永久节点 永久有序 -s 永久无序 默认注意: 节点的创建不能层级创建查看节点列表 ls /a ls2 /a 显示数据版本 , 事务id 创建时间等信息修改数据 set /a 123获取数据 get /a 删除节点 delete /a 只能删除空节点rmr /a 可以删除任意节点
监听和通知
事件 : 触发了某种事件 通知
节点数据的变化子节点个数的变化 ls path [watch] 监控指定路径下数据的变化get path [watch] 监控指定路径数据的变化
注意: 监控和通知只能1次
打开两个zk客户端1) 一个监控 2) 一个修改数据 # 子节点个数变化窗口01 : ls / watch ->(WatchedEvent state:SyncConnected type:NodeChildrenChangedpath:/)窗口02 : rmr /a000000004 ---------------------------------------------------------------------------# 节点数据变化窗口01 : get /b watch ->(WatchedEvent state:SyncConnected type:NodeDataChanged path:/b)窗口02 : set /b 321
3.4 java操作添加依赖获取zk客户端 调用API释放资源
添加依赖
入门示例-[获取连接创建节点]
package com.doitedu.zk.cli;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.ZooDefs;import org.apache.zookeeper.ZooKeeper;import java.io.IOException;public class Demo01 { public static void main(String[] args) throws Exception { // 获取zk的客户端 ZooKeeper zk = new ZooKeeper("linux01:2181,linux02:2181,linux03:2181", 3000, null); // 调用API //1 创建节点 zk.create("/doitedu" , "JINGYINGDOIT30_".getBytes() , ZooDefs.Ids.OPEN_ACL_UNSAFE , CreateMode.EPHEMERAL_SEQUENTIAL); // System.out.println(zk); //释放资源 Thread.sleep(8000); zk.close(); }}
zookeeper-Java-API使用
package com.doitedu.zk.cli;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.ZooKeeper;import org.apache.zookeeper.data.Stat;import java.util.List;public class ClientApiDemo { public static void main(String[] args) throws Exception { // 获取客户端对象 ZooKeeper zk = ZookeeperUtil.getZookeeper(); // testGetData(zk); //修改数据 //testSetData(zk); //获取子节点列表 //testls(zk); // 只能删除空节点 递归 // zk.delete("/b" , -1); // 递归删除节点 ZookeeperUtil.rmr(zk,"/b") ; zk.close(); } // 查看路径下的子节点列表 public static void testls(ZooKeeper zk) throws KeeperException, InterruptedException { List
封装工具类
package com.doitedu.zk.cli;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.ZooKeeper;import java.io.IOException;import java.util.List;public class ZookeeperUtil { public static ZooKeeper getZookeeper() throws IOException { return new ZooKeeper("linux01:2181,linux02:2181,linux03:2181", 3000, null); } public static void rmr(ZooKeeper zk , String path) throws KeeperException, InterruptedException { // 遍历是否有子节点 List
监控和通知
连接成功 监听通知数据变化节点变化
例子
package com.doitedu.zk.cli;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.ZooKeeper;import java.io.IOException;public class TestWatcher01 { public static void main(String[] args) throws Exception { ZooKeeper zk = new ZooKeeper("linux11:2181", 2000, new Watcher() { public void process(WatchedEvent event) { System.out.println("获取连接成功......"); } }); System.out.println(zk); zk.close(); }}----------------------------------------------------------------------package com.doitedu.zk.cli;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.ZooKeeper;public class TestWatcher02 { public static void main(String[] args) throws Exception { final ZooKeeper zk = new ZooKeeper("linux01:2181", 2000, null); // 获取指定节点数据的时候 绑定监听器 监听此节点数据的变化 byte[] data = zk.getData("/b", new Watcher() { // /b节点数据变化就会执行这个方法 1次 public void process(WatchedEvent event) { try { System.out.println("/b的数据发生了变化...."); System.out.println(event.getType()); // 改变后的数据是 byte[] data1 = zk.getData("/b", this, null); System.out.println("变化后的的数据是: "+new String(data1)); } catch (Exception e) { e.printStackTrace(); } } }, null); System.out.println("变化以前的数据是: "+new String(data)); Thread.sleep(Integer.MAX_VALUE); zk.close(); }}-----------------------------------------------------------------------package com.doitedu.zk.cli;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.ZooKeeper;import java.util.List;public class TestWatcher03 { public static void main(String[] args) throws Exception { final ZooKeeper zk = new ZooKeeper("linux01:2181", 2000, null); List
在ZK中有三种状态 ;
Leader: 优先负责写数据
follower 存储数据 参与选举
observe 观察者 不参与选举 存储数据
每个服务器都有一个唯一的myid标记
ZK服务启动[linux01(myid=1)] , 发现集群中没有Leader .进入到选举状态 ; 投自己一票myid=1的机器获取1票 , 票数没有过半, 不能当选leaderlinux01, 广播投票结果linux02(myid=2)启动 ,发现集群中没有leader , 进入到选举状态 收到linux01的1票信息 , 发现linux02的myid > linux01的myid ;投自己一票 ,广播linux01收到广播 ,发现自己的myid小 ; 改投lnux02 1票 , 广播linux02 收到linux01的广播 ,自己的票数为2 , 过半 ,切换leader状态linux01 切换follower状态linux03启动 ,发现集群中有leader ;切换follower状态初始启动选举
运行过程中选举
注意: 要求整个集群中的数据是一致的! 有事务的保证! zxid事务id
1 先比较zxid的大小 , zxid大的优先当选
2 如果事务id一致 , 再比较myid
整个集群中有机器宕机 ,属于不正常的状态! 修复.........
数据一致性
zk中存储数据以KV的形式 ; K是以节点的组织的 以/开头
整个集群中所有的节点存储一样的数据
记录的数据一般为状态数据 ,配置数据 ,命令....数据量不大