本文章基于B站UP主:编程不良人 视频教程《Zookeeper》进行整理记录,仅用于个人学习/交流,使用
视频教程:
参考资料:
zooKeeper(动物园管理者)简称ZK,一个分布式的,开放源码的分布式应用程序协调服务
,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。ZooKeeper使用Java所编写,但是支持Java和C两种编程语言。
模型的特点:
每个子目录如/node1都被称作一个znode(节点),这个znode是被它所在的路径唯一标识
znode可以有子节点目录,并且每个znode可以存储数据
znode是有版本的,每个 znode中存储的数据可以有多个版本
,也就是一个访问路径中可以存储多份数据
znode可以被监控
,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端
持久节点(PERSISTENT)
是指在节点创建后,就一直存在
,直到有删除操作来主动删除这个节点一一不会因为创建该节点的客户端会话失效而消失
持久顺序节点(PERSISTENT_SEQUENTtAL)
这类节点的基本特性和上面的节点类型是一致的。额外的特性是,在ZK中,每个父节点会为他的第一级子节点维护一份时序
,会记录每个子节点创建的先后顺序
。基于这个特性,在创建子节点的时候,可以设置这个属性,那么在创建节点过程中,Z会自动为给定节点名加上一个数字后缀
,作为新的节点名。这个数字后缀的范围是整型的最大值。
临时节点(EPHEMERAL)
和持久节点不同的是,临时节点的生命周期和客户端会话绑定
。也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。注意,这里提到的是会话 失效,而非连接断开
。另外。在临时节点下面不能创建子节点
。
临时顺序节点(EPHEMERAL_SEQUENTIAL)
具有临时节点特点,额外的特性是,每个父节点会为他的第一级子节点维护一份时序
。这点和刚才提到的持久顺序节点类似
配置文件位置:apache-zookeeper-3.7.0\conf\zoo.cfg
说明:
ls2 指令= ls + stat
stat指令详细信息
delete指令 和 rmr指令
客户端可以监测znode节点的变化。Zonode节点的变化触发相应的事件,然后清除对该节点的监测。当监测一个znode节点时候,Zookeeper会发送通知给监测节点。
一个Watch事件是一个一次性的触发器
,当被设置了Watch的数据和目录发生了改变的时候,则服务器将这个改变发送给设置Watch的客户端以便通知它们。
1.1s /path true
监听节点目录的变化
2.get /path true
监听节点数据的变化。
<dependency>
<groupId>com.101tecgroupId>
<artifactId>zkclientartifactId>
<version>0.11version>
dependency>
@Test
public void testConnection(){
//1. zk server 服务器 ip地址、端口号
//2、会话超时时间
//3、连接超时时间
//4、序列化方式(对象序列化的方式)
ZkClient zkClient = new ZkClient("106.55.100.58:2181", 60000 * 30, 60000, new SerializableSerializer());
System.out.println(zkClient);
//释放资源
//调用close方法之后,相当于关闭连接,创建的==临时节点会消失==
zkClient.close();
}
public static ZkClient zkClient;
@BeforeAll //初始化客户端对象
public static void Before(){
zkClient = new ZkClient("106.55.100.58:2181", 60000 * 30, 60000, new SerializableSerializer());
}
@AfterAll //释放资源
public static void After(){
zkClient.close();
}
//1.创建节点
@Test
public void testCreateNode(){
//1.1 持久节点
zkClient.create("/node1","zhangsan", CreateMode.PERSISTENT);
//1.2 持久顺序节点
zkClient.create("/node1/name","lisi",CreateMode.PERSISTENT_SEQUENTIAL);
//1.3 临时节点
zkClient.create("/node2","wangwu",CreateMode.EPHEMERAL);
//1.4 临时顺序节点
zkClient.create("/node2/name1","zhaoliu",CreateMode.EPHEMERAL_SEQUENTIAL);
}
//2.删除节点
@Test
public void testDeleteNode(){
//2.1 删除没有子节点的节点
boolean delete = zkClient.delete("/node1");
System.out.println(delete);
//2.2 递归删除节点
boolean b = zkClient.deleteRecursive("/node1");
System.out.println(b);
}
//3.查询某个结点下的所有节点
@Test
public void testFindNodes(){
List<String> children = zkClient.getChildren("/node1");
children.forEach(System.out::println);
}
//4.查看某个节点的数据
@Test
public void testFindNodeData(){
Object node1 = zkClient.readData("/node1");
System.out.println(node1);
}
//5.查看节点的状态信息
@Test
public void testNodeDataAndStat(){
Stat stat=new Stat();
Object readData = zkClient.readData("/node1", stat);
System.out.println(readData);
System.out.println(stat.getCversion());
System.out.println(stat.getCtime());
System.out.println(stat.getCzxid());
}
//6.修改节点数据
@Test
public void testWriteData(){
User user=new User();
user.setId(1).setName("zhangsan").setAge(18).setBir(new Date());
zkClient.writeData("/node1",user);
//读测试
User user1 = zkClient.readData("/node1");
System.out.println(user1);
}
Tips1:查看某个节点数据时,要保证数据序列化方式一致
Tips2:保存自定义对象数据时,要让自定义对象实现序列化
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain = true)
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
private Date bir;
}
Tips3:调用close方法之后,相当于关闭连接
,创建的临时节点会消失
Java能够实现永久监听
,Shell中只能一次监听
使用Java代码监听
只能监听对Java代码对节点的操作,不能监听Shell对节点的操作
使用Shell监听节点时,能够监听Java代码对节点的操作
使用代码对目录监听是永久监听,假设监听node1,即使删除node1后,在创建一个新的node1,这个node1依旧能被监听
//7.监听节点数据变化
@Test
public void testWatchDataChange() throws IOException {
zkClient.subscribeDataChanges("/node1",new IZkDataListener(){
//当前节点数据变化时触发对应的这个方法
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
System.out.println("当前节点路径: "+dataPath);
System.out.println("当前节点变化后的数据是: "+data);
}
//当前节点删除时触发这个方法
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("当前节点路径: "+dataPath+",已被删除");
}
});
//阻塞当前监听
System.in.read();
}
//8.监听节点目录变化
@Test
public void testWathchPathChange() throws IOException {
zkClient.subscribeChildChanges("/node1", new IZkChildListener() {
//当节点发生变化时,会自动调用这个方法
//参数1:父节点的名称
//参数2:父节点中的所有子节点的名称
@Override
public void handleChildChange(String nodeName, List<String> list) throws Exception {
System.out.println("父节点名称:" +nodeName);
System.out.println("发生变更后子节点名称:");
list.forEach(System.out::println);
}
});
System.in.read();
}
推荐博客:https://my.oschina.net/longkingxu/blog/1802140
1.集群
集合同一种软件服务的多个节点同时提供服务
2.集群解决问题
单节点的并发访问的压力问题
单节点故障问题(如硬件老化,自然灾害等)
zab,原子广播协议
数据一致性,高度一致:
当我们连接ZK集群中的任意一个节点之后,对他写入数据,但这个节点并不会立即写入自己的节点,而是向Leader节点进行通信
,发起一次确认,当主节点确认可以写之后,做原子广播
,其他节点同步的写入数据,如果某个客户端写入失败,则直接报错给客户端(所有已经写入数据的节点,撤销回滚
),直至集群中的所有节点都确认这个数据之后,这个数据才会成为集群数据的一部分
following原子同步leader节点中数据
leader节点宕机之后,following节点会选举
1.填写ZK集群中的任意一个节点的IP地址,既可以使用集群
2.填写ZK集群总所有节点的IP地址,防止(1)中当前节点宕机,但集群依旧可以的情况