zookeeper 本地安装
1、集群操作
(1)集群安装
(2)选举机制
- 第一次启动:假设有五台服务器
①服务器1启动,先投给自己一票,然后发现没有超过半数以上(>=3)的服务器,选举无法完成,进入 LONGING 状态
②服务器2启动,先投给自己一票,然后发现没有超过半数以上的服务器,此时服务器1发现服务器2的myid比目前自己投票选举的(服务器1)大,更改投举为服务器2。此时服务器1票数为0,服务器2票数为2,没有超过半数以上,选举无法完成,服务器1、服务器2都进入Looking状态。
③服务器3启动,发起一次选举。此时服务器3投给自己,服务器1、2都会改选投为服务器3,超过半数以上,服务器3当选Leader。此时服务器1、2状态为FOLLWERING,服务器3状态为LEADING
④服务器4启动,发起一次选举。此时服务器1、2、3已经不是LOOKING状态了,不会随意更改投票,此时服务器4投给自己一票,而服务器3有3票,服务器4服从多数,更改选票为服务器3,并更改状态为FOLLOWING
⑤服务器5启动选举过程与服务器4一样
SID:服务器ID,用来唯一标识ZooKeeper集群中的机器,每台机器不能重复,和myid一致。
ZXID:事务ID。ZXID是一个事务ID,用来标识一次服务器状态的更改。
Epoch:每个Leader任期的代号。
- 非第一次启动:
当 Zookeeper 集群中的一台服务器出现以下两种情况之一时,就会开始进入 Leader 选举:- 服务器初始化启动
- 服务器运行期间无法和 Leader 保持连接
- 当一台服务器进入 Leader 选举流程时,当前集群也可能会处于以下两种状态:
- 集群中存在 Leader
对于集群中确实存在Leader,机器尝试去选举Leader,会被告知当前服务器的Leader信息,对于该机器来说,仅仅只需要和当前Leader建立连接,并进行状态同步即可。 - 集群中确实不存在 Leader
- 集群中存在 Leader
(3)ZK 集群启动停止脚本
ZooKeeper 启动
c
ZooKeeper 停止
bin/zkServer.sh stop
查看 ZooKeeper 状态
bin/zkServer.sh status
上面是命令直接启动停止,我们可以写个脚本可以方便一点:
#!/bin/bash
case $1 in
"start"){
for i in centos102 centos102 centos104
do
echo --------- zookeeper $i 启动 ---------
ssh $i "/opt/module/zookeeper-3.5.7/bin zkServer.sh start"
done
}
;;
"stop"){
for i in centos102 centos102 centos104
do
echo --------- zookeeper $i 停止 ---------
ssh $i "/opt/module/zookeeper-3.5.7/bin zkServer.sh stop"
done
}
;;
"status"){
for i in centos102 centos102 centos104
do
echo --------- zookeeper $i 状态 ---------
ssh $i "/opt/module/zookeeper-3.5.7/bin zkServer.sh status"
done
};;
esac
2、客户端命令行操作
客户端启动:
bin/zkCli.sh
但是我们可以看到这里是相当于本地客户端启动,我们需要102、103、104启动
bin/zkCli.sh -server [想启动的服务器]:[该服务器端口号]
对应服务器启动成功
节点信息
ls /
出现一个节点
ls -s /
以下出现的信息都是什么意思呢?
- czxid:创建节点的事务ID
- ctime:znode 被创建的毫秒数(从1970年开始)
- mzxid:
节点类型
持久:客户端和服务器断开连接后,创建的节点不删除
短暂:客户端和服务器断开连接后,创建的节点自己删除
持久化目录节点:客户端和ZooKeeper断开连接后,该节点依然存在
持久化顺序编号目录节点:客户端和ZooKeeper断开连接后,该节点依然存在,只是ZooKeeper给该节点名称进行顺序编号。
临时目录节点:客户端和ZooKeeper断开连接后,该节点被删除
临时顺序编号目录节点:客户端和ZooKeeper断开连接后,该节点被删除,只是ZooKeeper给该节点名称进行顺序编号。
创建永久节点
create /[节点名称] "添加的信息"
查看节点,多出了一个 snaguo 的节点
多目录的创建节点,在 snaguo 节点下创建 shuguo 节点,添加信息为 liubei
查看节点的信息
get -s /[节点名称]
上面是创建节点不带序号的,接下来我们创建永久九点带序号的:
create -s /[节点名称] "添加的信息"
创建的节点自动带上了序号
有序号的节点有什么好处,如图,再次创建 weiguo 的节点发现不能创建,重复,但是再次创建 zhangliao 带序号的节点便可以创建
创建临时节点
create -e /[节点名称] "添加的信息"
带序号的临时节点
create -e -s /[节点名称] "添加的信息"
接下来退出客户端,然后再重启,看看还有没有这两个节点
发现只有两个持久性节点,我们创建的两个临时节点不见了
修改节点数据值
set /[节点名称] "修改的信息"
监听器及节点删除
监听原理
注册监听器
前提:启动客户端103、104
get -w /[要监听的节点名称]
在centos104上注册监听器,现在就已经监听了 sanguo 这个节点
现在在centos103上修改这个节点的信息
回到centos104下,我们发现出现以下信息,告诉我们节点信息发生修改
注意:此时我们再次修改 sanguo 的值,监听器不会再告诉我们发生信息修改了,这是因为注册一次,只能监听一次;再次监听,需要再次注册。
节点的子节点变化监听(路径变化)
在centos104上设置监听器
创建一个新节点
可以看到提示我们节点修改
再次修改监听器不会再提示修改
节点删除以及查看
删除单个节点
delete /[节点]
不可以直接删除节点 sanguo,因为 sanguo 下有很多个节点,需要使用命令 deleteall /[节点名称]
,查看已经没有节点 sanguo 了
查看节点状态
stat /[节点名称]
接下来介绍以下命令
3、客户端 API 操作
前提:centos102、centos103、centos104 服务器都已经开启
pom.xml 依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
log4j.properties 配置
# 设置全局的日志记录级别为 INFO
log4j.rootLogger=INFO, stdout
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.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
zkClient.java 代码
// 注意:逗号后面不能有空格
private String connectString = "centos102:2181,centos103:2181,centos104:2181";
private int sessionTimeout = 2000;
private ZooKeeper zkClient;
// 创建客户端
@Before
public void init() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent event) {
}
});
}
// 创建子节点
@Test
public void create() throws InterruptedException, KeeperException {
String nodeCreated = zkClient.create("/frost", "cat".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
运行创建子节点,看看是否创建了该节点