
cd /opt/software/
tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/module/
cd /opt/module
mv apache-zookeeper-3.5.7-bin zookeeper-3.5.7
cd /opt/module/zookeeper-3.5.7
mkdir zkData
cd /opt/module/zookeeper-3.5.7/zkData
vi myid
在文件中添加与server对应的编号,(注意:上下不要有空行,左右不要有空行,注意是否乱码)

分别在其他机器上修改对应的myid
cd /opt/module/zookeeper-3.5.7/conf
cp zoo_sample.cfg zoo.cfg
mv zoo_sample.cfg zoo_sample.cfg.bak
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/opt/module/zookeeper-3.5.7/zkData
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
#cluster config
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888
server.A=B:C:D
在每台服务器上分别执行
cd /opt/module/zookeeper-3.5.7/bin
./zkServer.sh start
在每台服务器上分别执行
cd /opt/module/zookeeper-3.5.7/bin
./zkServer.sh stop
当Zookeeper集群中的一台服务器出现以下两种情况时,会发起Leader选举。服务器初始化启动。 服务器运行期间无法和Leader保持联系。
SID:服务器ID。用来唯一标识一台ZooKeeper集群中的机器,每台机器不能重复,和myid一致。
ZXID:事务ID。ZXID是一个事务ID,用来标识一次服务器状态的变更。在某一时刻,集群中的每台机器的ZXID值不一定完全一致,这和ZooKeeper服务器对于客户端“更新请求”的处理逻辑有关。
Epoch:每个Leader任期的代号。没有Leader时同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加

当一台机器进入Leader选举流程时,当前集群也可能会有以下两种情况
对于已经存在Leader的情况,机器试图去选举Leader时,会被告知当前服务器的Leader信息,对于该机器说,仅仅需要和Leader建立连接,并进行状态同步即可。

选举原则:
<1> EPOCH大的直接胜出
<2> EPOCH相同,事务id(ZXID)大的胜出
<3> 事务id(ZXID)相同,服务器id(SID)大的胜出
#!/bin/bash
case $1 in
"start")
{
for i in hadoop102 hadoop103 hadoop104; do
echo "----------------- zookeeper $i start -----------------"
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh start"
done
}
;;
"stop")
{
for i in hadoop102 hadoop103 hadoop104; do
echo "----------------- zookeeper $i start -----------------"
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh stop"
done
}
;;
"status")
{
for i in hadoop102 hadoop103 hadoop104; do
echo "----------------- zookeeper $i status -----------------"
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh status"
done
}
;;
esac


创建节点的事务zxid
每次修改Zookeeper状态都会产生一个Zookeeper事务ID。事务ID是Zookeeper中所有修改总的次序,每次修改都有唯一的zxid。如果zxid1小于zxid2那么zxid1在zxid2之前发生。
znode被创建的毫秒数(从17990年开始)
znode最后更新的事务zxid。
znode最后修改的毫秒数(从17990年开始)
znode最后更新的子节点zxid。
znode子节点变化号,znode子节点修改次数。
znode数据变化号。
znode访问控制列表的变化号
如果是临时节点,这个是znode拥有者的sessionid。如果不是临时节点则是0。
znode的数据长度
znode的子节点数量

持久(Persistent):客户端与服务器端断开连接后,创建的节点不会删除
短暂(Ephemeral):客户端与服务器端断开连接后,创建的节点删除
客户端与Zookeeper断开连接后,该节点依旧存在
create /sanguo "diaochan"
create /sanguo/shuguo "liubei"

<1> 客户端与Zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号。
<2> 创建znode时设置顺序表示,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护。
<3> 在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序。
create /sanguo/weiguo "caocao"
create -s /sanguo/weiguo/zhangliang "zhangliang"
create -s /sanguo/weiguo/zhangliang "zhangliang"

客户端与Zookeeper断开连接后,该节点被删除
create -e /sanguo/wuguo "zhouyu"
重连前

重连后

客户端与Zookeeper断开连接后,该节点被删除, 只是Zookeeper给该节点名称进行顺序编号
create -e -s /sanguo/wuguo "liubei"
重连前

重连后

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、节点删除、子目录节点增加删除)时,ZooKeeper,会通知客户端。监听机制保证ZooKeeper保存的任何的数据的任何改变都能快速的响应到监听了该节点的应用程序。

<1> 创建一个mian()线程
<2> 在mian线程中创建Zookeeper客户端 ,这时就会创建连个线程。一个负责网络连接通信(connect),一个负责监听(listener)
<3> 通过connect线程将注册的监听事件发送给Zookeeper
<4> 在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中
<5> Zookeeper监听到有数据变化或者路径变化,就将这个消息发送给listener线程。
<6> listener线程内部调用process()方法
<1> 监听节点数据的变化 get path [watch]
<2> 监听子节点增减的变化 ls path [watch]
<1> 查看原始值

<2> 在103监听
get -w /sanguo
<3> 在104修改数据
set /sanguo "xishi"
<4> 在103查看监听结果

<5>在104修改数据
set /sanguo "sunshangxiang"
<6> 103 不再有监听
注册一次,只能监听一次,想要再次监听,需要再次注册。
<1> 查看原始子节点

<2> 在103监听
ls -w /sanguo
<3> 在104创建节点
create /sanguo/wuguo "wuguo"
<4> 在103查看监听结果

<5>在104创建节点
create /sanguo/wuguo1 "wuguo1"
<6> 103 不再有监听
注册一次,只能监听一次,想要再次监听,需要再次注册。
delete /sanguo/wuguo

deleteall /sanguo
stat /zookeeper

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.zookeepergroupId>
<artifactId>ZookeeperDemoartifactId>
<version>1.0-SNAPSHOTversion>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>RELEASEversion>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.8.2version>
dependency>
<dependency>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
<version>3.5.7version>
dependency>
dependencies>
project>
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

package com.zookeeper;
import org.apache.zookeeper.*;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
/**
* @author : hechaogao
* @createTime : 2022/9/15 10:47
*/
public class ZkClient {
/**
* 逗号前后不能有空格
*/
private final String CONNECTSTR = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
/**
* 单位毫秒
*/
private int SESSIONTIMEOUT = 2 * 1000;
/**
* zookeeper客户端
*/
private ZooKeeper zkClient;
@Test
public void init() throws IOException {
zkClient = new ZooKeeper(CONNECTSTR, SESSIONTIMEOUT, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
}
}
package com.zookeeper;
import org.apache.zookeeper.*;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
/**
* @author : hechaogao
* @createTime : 2022/9/15 10:47
*/
public class ZkClient {
/**
* 逗号前后不能有空格
*/
private final String CONNECTSTR = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
/**
* 单位毫秒
*/
private int SESSIONTIMEOUT = 2 * 1000;
/**
* zookeeper客户端
*/
private ZooKeeper zkClient;
@Before
public void init() throws IOException {
zkClient = new ZooKeeper(CONNECTSTR, SESSIONTIMEOUT, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
}
@Test
public void create() throws InterruptedException, KeeperException {
/**
* param1 创建的节点的目录
* param2 创建的节点的值
* param3 ACL访问权限
* param4 创建的节点类型,这里选择的持久类型
*
*/
String nodeCreasted = zkClient.create("/testpath", "testvalue".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
}
package com.zookeeper;
import org.apache.zookeeper.*;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
/**
* @author : hechaogao
* @createTime : 2022/9/15 10:47
*/
public class ZkClient {
/**
* 逗号前后不能有空格
*/
private final String CONNECTSTR = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
/**
* 单位毫秒
*/
private int SESSIONTIMEOUT = 2 * 1000;
/**
* zookeeper客户端
*/
private ZooKeeper zkClient;
@Before
public void init() throws IOException {
zkClient = new ZooKeeper(CONNECTSTR, SESSIONTIMEOUT, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
List<String> children = null;
try {
children = zkClient.getChildren("/", true);
System.out.println("__________________________________________");
children.stream().forEach(c -> {
System.out.println(c);
});
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
@Test
public void getChildren() throws InterruptedException, KeeperException {
/**
* param1 要获取的目录
* param2 true 使用init方法中的watcher
*/
List<String> children = zkClient.getChildren("/", true);
System.out.println("__________________________________________");
children.stream().forEach(c -> {
System.out.println(c);
});
Thread.sleep(Long.MAX_VALUE);
}
}
@Test
public void exists() throws InterruptedException, KeeperException {
/**
* param1 路径
* param2 是否监听
*/
Stat stat = zkClient.exists("/test2", false);
System.out.println(stat != null ? "exists" : "not exists");
}

