写在前面:
之前学习配置ActiveMQ集群时,用到了ZooKeeper,但对ZK不熟悉,只听说过没接触到过。和它经常一起出现的还有Double,作为分布式框架的一对默契搭档。ZK早晚会接触到,既然现在接触到了那就顺便来学习一下ZooKeeper。老样子,把自己学习到的接触到的不熟悉的统统记录成册。日积月累,形成日后自己的技术栈。
一、入门简介
ZooKeeper=文件系统+通知机制
ZooKeeper:开源的分布式系统框架下的“协调调度通知机制”,以便达到消息一致性原则。
ZK可以用来做集中配置管理,存储在ZK集群中的配置。如果发生变更会主动推送到连接配置中心的应用节点,实现一处更新处处更新的效果。
★ZK提供了一套很好的分布式集群管理的机制。它这种基于层次型的目录树的数据结构。并对树中的节点进行有效管理,从而设计出多种多样的分布式的数据管理模型。作为分布式系统的沟通调度桥梁。
二、 安装配置
1.官网下载 tar –zxvfzookeeper-3.4.14.tar.gz
2.cp –r zookeeper-3.4.14.tar.gz/myzookeeper
3.进入conf文件夹,拷贝zoo_sample.cfg改为zoo.cfg做为备份
4.zoo,cfg解读
tickTime:心跳检测时间(毫秒)≈服务器之间或客户端与服务器之间维持间隔
initLimit初始通讯时间 ≈“电话打通前的等待时间”
syncLimit:同步通信时限≈“电话拨通后的等待时间”
dataDir:数据存放目录
clientPort:默认端口2181
5.常见服务命令 /bin目录下
./zkServer.shstart 启动
./zkServer.shstop 关闭
./zkCli.sh 客户端启动
quit 客户端退出服务端的连接
6.四字命令
支持某些特定的四字命令,大多用来查询ZK的当前状态及相关信息。
运行公式:echo 四字命令 | nc 主机ip 2181
例如,测试是否启动了服务。
echo ruok | nc 127.0.0.1 2181 回复imok则表示已经启动。
还有,查看当前运行环境配置信息
echo envi | nc 127.0.0.1 2181
★初次运行 可能会报找不到nc。需要安装一下。
7.永远的helloworld
三、数据模型/znode节点深入
查看+获得zookeeper服务器上的数据存储信息
1.Znode的数据模型:Stat结构体
2.ZooKeeper维护了一个类似文件系统的数据结构。这套存储结构为一个树形结构,其上每一个节点,都称为znode。每一个zonde都默认存储1MB,都有唯一的路径标识。
Znode =path + pathValue + Stat
3.Znode中存在的类型--------临时&持久
create [-s] [-e] path data acl
【-s】sequential持久化顺序编号目录节点。由ZK对节点进行顺序编号。
【-e】ephemeral临时节点
【-p】persistent持久化
【-s】【-e】可以同时使用【-p】啥都不写 默认持久
四、基础命令和Java客户端操作
1.zkcl的常用命令操作:和redis的KV键值对类似,只不过key变成了一个路径节点值,v就是data。
help
ls:只露出[zookpper]
ls2:2比l更详细,还露出其结构体
stat查看结构体
delete有且只能删除当前节点且节点下无别的节点
rmr递归删除节点
2.Java客户端操作 pom.xml主要的jar包
<!-- https://mvnrepository.com/artifact/com.101tec/zkclient -->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</version>
<type>pom</type>
</dependency>
五、通知机制
1.Session:连接
2.Watch:(哨兵)客户端可以在znode节点上设置一个观察,如果被观察服务端Znode节点有变更,那么watch所属客户端将接收到一个通知包,被告知节点已经发生变化,把相应的事件通知给设置Watch的Client端。
Zookeeper里的所有读取操作:getData()、getChildren()、exists()都有设置watch的选项。一句话:异步+回调的触发机制 |
*ZK设计模式理解
是一个基于观察者模式设计的分布式服务管理框架。它负责存储和管理大家都关心的数据。然后接受观察者的注册,一旦这些数据的状态发生改变,zk就将负责通知已经在zk上注册的那些观察者做出相应的反应。
3.HelloZK
public class HeloZK {
private static final String CONNECTION_STRING = "192.168.91.130:2181";
private static final String PATH = "/atguigu";
private static final int SESSIONT_IMEOUT = 50*1000;
public ZooKeeper startZK() throws IOException {
return new ZooKeeper(CONNECTION_STRING, SESSIONT_IMEOUT, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
}
public void stopZK(ZooKeeper zk) throws InterruptedException {
if(null != zk) zk.close();
}
public void createZnode(ZooKeeper zk,String nodePath,String nodeValue) throws KeeperException, InterruptedException {
zk.create(nodePath,nodeValue.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
public String getZnode(ZooKeeper zk,String nodePath) throws KeeperException, InterruptedException {
String result = null;
byte[] data = zk.getData(nodePath, false, new Stat());
result = new String(data);
return result;
}
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
HeloZK heloZK = new HeloZK();
ZooKeeper zk = heloZK.startZK();
if(zk.exists(PATH,false)==null){
heloZK.createZnode(zk,PATH,"12138");
String znode = heloZK.getZnode(zk, PATH);
System.out.println("returnValue" + znode);
}else {
System.out.println("该节点已经存在");
}
heloZK.stopZK(zk);
}
}
4.WatchOne
*ZooKeeper自带的Bug,若不传watcher将报空指针异常。
public ZooKeeper startZK() throws IOException {
return new ZooKeeper(CONNECTION_STRING, SESSIONT_IMEOUT, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
}
Zookeeper里的所有读取操作:getData()、getChildren()、exists()都有设置watch的选项。
public String getZnode(String nodePath) throws KeeperException, InterruptedException {
String result = null;
byte[] data = zk.getData(nodePath, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
try {
targetValue(nodePath);
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
}
}, new Stat());
result = new String(data);
return result;
}
public String targetValue(String nodePath) throws KeeperException, InterruptedException {
String result = null;
byte[] data = zk.getData(nodePath, false, new Stat());
result = new String(data);
System.out.println("*******************节点值被修改为了" + result + "当前仅当记录这一次改变 后面再改变 不记录");
return result;
}
监控/atguigu节点 获得初次值后设置watch 只要发生新的变化 打印出最新的值 一次性watcher。
5.WatchMore
public String getZnode(String nodePath) throws KeeperException, InterruptedException {
String result = null;
byte[] data = zk.getData(nodePath, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
try {
targetValue(nodePath);
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
}
}, new Stat());
result = new String(data);
oldValue = result;
return result;
}
public boolean targetValue(String nodePath) throws KeeperException, InterruptedException {
String result = null;
byte[] data = zk.getData(nodePath, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
try {
targetValue(nodePath);
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
}
}, new Stat());
result = new String(data);
String newValue = result;
if(oldValue.equals(newValue)){
System.out.println("*******************no changges*******************");
return false;
}else{
System.out.println("oldValue===="+oldValue+"newValue==="+newValue);
oldValue = newValue;
return true;
}
}
6.watchChild
public ZooKeeper startZK() throws IOException {
return new ZooKeeper(CONNECTION_STRING, SESSIONT_IMEOUT, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
if(watchedEvent.getType() == Event.EventType.NodeChildrenChanged && watchedEvent.getPath().equals(PATH)){
showChild(PATH);
}else {
showChild(PATH);
}
}
});
}
public void showChild(String nodePath){
List<String> children = null;
try {
children = zk.getChildren(nodePath,true);
System.out.println(children);
}catch (Exception e){
e.printStackTrace();
}
}
六、ZooKeeper集群
server.N (服务器编号)= YYY(服务器IP):A(主master从slave):B(选举端口) |
(正式)集群中每个服务器A,B端口都一样 伪集群 IP地址都一样 A和B端口也不一样
步骤
1.复制3个
cp –r zookeeper-3.4.14 /myzookeeper/zk01 ..zk02 ..zk03
2.进入zk01、zk02、zk03各自conf文件夹 新建mydata,mylog
3.分别进入zk01、zk02、zk03各自conf文件夹新建zoo.cfg
4.分别编辑zk01、zk02、zk03的zoo.cfg
#dataDir=/tmp/zookeeper
dataDir=/myzookeeper/zk01/mydata
dataLogDir=/myzookeeper/zk01/mylog
server.1=127.0.0.1:2991:3991
server.2=127.0.0.1:2992:3992
server.3=127.0.0.1:2993:3993
5.zk01、zk02、zk03各自mydata文件夹下 创建myid文件里面写server.N的数字
2991:1
2992:2
2993:3
6.分别启动三个服务器
7.zkCli.sh连接server 带参数指定 –server
./zkCli.sh –server 127.0.0.1:2193 ----->zk03
zk03:./zkCli.sh –server 127.0.0.1:2193
create/atguigu hello
zk01:.get /atguigu
hello
分享最近路上拍到一张的夕阳晚霞~Good luck