Dubbo 通过注册中心在分布式环境中实现服务的注册与发现,而注册中心通常采用 ZooKeeper,研究注册中心相关源码绕不开 ZooKeeper,所以学习了 ZooKeeper 的基本概念以及相关 API 操作。

ZooKeeper 相关概念

session

客户端与服务端采用 TCP 长连接,服务端在为客户端创建 Session 会分配一个唯一 sessionId。在 Session timeout 时间内,客户端可以向服务端发送请求以及接受 watcher 事件通知。

数据结构

Zookeeper 将所有数据存储在内存中,数据模型是一棵树(Znode Tree),由斜杠(/)的进行分割的路径,就是一个Znode,例如/foo/path1。

Znode

Znode 将会保存数据内容以及相关属性信息。在 Znode 中使用 Stat 数据结保存相关属性信息。Stat 属性中有三种版本信息,分别为 version:当前节点版本信息,cversion:当前节点子节点版本,aversion 当前节点的 ACL 版本。每次发生改动,版本数值将会单调递增。

更新,删除 Znode 可以传入版本数值,如果版本数值不对,将会导致删除/更新失败,这个特性类似于 CAS 操作。

Znode 有以下几种类型:

  1. 永久节点

一旦创建,将会一直存在,除非手动删除。dubbo 目录节点为永久节点。

  1. 临时节点

临时节点基于客户端 Session,Session 有效期内将会一直存在,Session 失效,节点将会自动删除。

利用这个机制,Dubbo 服务者创建的节点就是临时节点。如果 Dubbo 服务者程序意外宕机,在 Session 超时之后,也能自动删除服务节点,自动下线有问题的服务。

3 顺序节点

创建顺序节点将会自动在名字后追加整形数字,默认长度为 10 位。顺序节点也分为永久与临时。

利用临时顺序节点,我们可以用来实现分布式锁 七张图彻底讲清楚ZooKeeper分布式锁的实现原理【石杉的架构笔记】

Watcher 机制

客户端可以在指定节点注册监听器(Watcher),在触发特定事件后,ZooKeeper 服务端会将事件通知到客户端。在 Dubbo 中消费者基于 watcher 机制可以动态感知到新的服务者加入。

ZooKeeper 可以在三种请求中设置监听,分别为:

  • getData(),获取节点数据
  • getChildren() 获取子节点
  • exists() 判断节点是否存在

通知事件类型分为,增删改事件,以及子节点变动事件。

需要注意的是,watcher 通知过一次之后将会失效,若想继续监听通知,需要重新注册。

ZooKeeper 原生 API 操作

ZooKeeper 官方提供 Java API 实现,提供相关操作的方法。

创建连接


ZooKeeper zk=new ZooKeeper("127.0.0.1:2181", 150000, new Watcher() { @Override
public void process(WatchedEvent watchedEvent) { System.out.println("已经触发了" + watchedEvent.getType() + "事件"+watchedEvent); } });

创建连接需要传入 ZooKeeper 服务端地址,然后设定 session 超时时间,另外还需要创建一个 Watcher,用于监听连接事件。建立连接之后,就可以使用该客户端操作。

CURD 操作


// 创建永久节点,需要传入 ACL 权限列表,以及指定节点类型
zk.create("/test","test".getBytes(), ZooDefs.Ids.CREATOR_ALL_ACL,CreateMode.PERSISTENT); // 修改节点值。更新节点值需要传入节点的版本,如果版本与服务端版本不一致,更新失败,类似 CAS 机制。-1 代表不比较节点版本
zk.setData("/test","test1".getBytes(),-1);
// 删除节点.删除节点也需要传入节点版本
zk.delete("/test",-1);
// 创建临时节点
zk.create("/ephemeral","ephemeral".getBytes(), ZooDefs.Ids.CREATOR_ALL_ACL,CreateMode.EPHEMERAL);

ZooKeeper 客户端相关 CRUD 操作如上。可以看到相关操作比较繁琐,需要传入参数较多。

watcher

 // 在 exists 注册 watcher,创建节点,删除节点,改变节点将会触发回调

        zk.exists("/test", new Watcher() {

            @Override
public void process(WatchedEvent event) {
System.out.println("回调实例,类型为:"+event.getType());
}
});
// 获取节点数据,可以注册 watcher,删除节点以及改变节点数据可以触发回调
zk.getData("/test", new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println("回调实例,类型为:"+event.getType());
}
},new Stat()); // 获取子节点,注册 watcher,一级子节点变动后将会触发回调
zk.getChildren("/test", new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println("回调实例,类型为:"+event.getType());
}
});

ZooKeeper API 可以为三种操作注册 watcher,一旦相关节点变动将会触发事件通知。

Curator

从上面代码示例可以看到 ZooKeeper 提供 API 比较复杂且难用。可以使用 Curator 或者 zkclient 这种第三方框架代替原生 API。这类框架封装 ZooKeeper 原生 API,抽象化相关接口,简化操作难度。

dubbo 抽象相关 ZooKeeper 操作,并分别使用 Curator 或者 zkclien 实现。在 dubbo 2.6.1 版本之后将会默认使用 Curator,之前版本默认使用 zkclient 。

下面我们使用 Curator 操作 ZooKeeper 。

建立连接

 // 设置重试策略
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
// 默认 session 超时时间 60 s
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", retryPolicy);

Curator 创建连接与原生 API 大致相关,不过需要设置重试策略,第一次连接失败,Curator 可以重新尝试连接,直到超过最大连接次数。

节点 CURD 操作

        // 创建目录节点

        client.create().forPath("/test", "123456789".getBytes());
// 创建普通节点
client.create().forPath("/test/normal", "123121".getBytes());
// 修改普通节点内容
client.setData().forPath("/test/normal", "1121231231".getBytes());
// 删除节点
client.delete().forPath("/test/normal"); // 创建临时节点
client.create().withMode(CreateMode.EPHEMERAL).forPath("/ephemeral");
// 创建永久顺序节点
client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/sequential"); // 获取所有子节点
List<String> nodes = client.getChildren().forPath("/parent");

Curator CRUD 操作比较简单,无需设置相关属性参数。

设置监听

Curator 相关监听 API 封装 zookeeper 原生API,内部增加重复注册等功能,从而使监听可以重复使用。

Curator 存在三种类型 API。

  • NodeCache:针对节点增删改操作。
  • PathChildrenCache:针对节点一级目录下节点增删改监听
  • TreeCache:结合 NodeCachePathChildrenCache 操作,不仅可以监听当前节点,还可以监听节点下任意子节点(支持多级)变动。
	//   `NodeCache`使用方式
NodeCache nodeCache=new NodeCache(client,"/test1",false);
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println("当前节点:"+nodeCache.getCurrentData()); }
});
nodeCache.start(); // PathChildrenCache 使用方式
PathChildrenCache pathChildrenCache=new PathChildrenCache(client,"/test2",false);
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
System.out.println(event);
}
});
pathChildrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
System.out.println("注册watcher成功...");
// TreeCache 使用方式
TreeCache treeCache=new TreeCache(client,"/tree");
treeCache.getListenable().addListener(new TreeCacheListener() {
@Override
public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
System.out.println(event);
}
});
treeCache.start();
System.out.println("注册watcher成功...");

ZooKeeper 相关概念以及使用小结的更多相关文章

  1. 【入门】ZooKeeper 相关概念总结

    1. 前言 相信大家对 ZooKeeper 应该不算陌生.但是你真的了解 ZooKeeper 到底有啥用不?如果别人/面试官让你给他讲讲对于 ZooKeeper 的认识,你能回答到什么地步呢? 拿我自 ...

  2. 【进阶】ZooKeeper 相关概念总结

    1. 开卷有益 学习是一种习惯,只有把这种习惯保持下来,每天不学习一点就感觉浑身不自在,达到这样的境界,那么你成为大佬也就不远了买,正如我们标题所写的"开卷有益".人生匆匆,要想过 ...

  3. zookeeper相关知识与集群搭建

    Zookeeper Zookeeper相关概念 Zookeeper概述 Zookeeper是一个分布式协调服务的开源框架,主要用来解决分布式集群中应用系统的一致性问题. Zookeeper本质上是一个 ...

  4. 基于zookeeper实现分布式配置中心(二)

    上一篇(基于zookeeper实现分布式配置中心(一))讲述了zookeeper相关概念和工作原理.接下来根据zookeeper的特性,简单实现一个分布式配置中心. 配置中心的优势 1.各环境配置集中 ...

  5. ZooKeeper相关资料集锦

    1.ZooKeeper相关概念总结 https://github.com/Snailclimb/JavaGuide/blob/master/docs/system-design/framework/Z ...

  6. (1)Zookeeper在linux环境中搭建集群

    1.简介 ZooKeeper是Apache软件基金会的一个软件项目,它为大型分布式计算提供开源的分布式配置服务.同步服务和命名注册.ZooKeeper的架构通过冗余服务实现高可用性.Zookeeper ...

  7. zookeeper 笔记-小结

    1.zookeeper为分布式应用设计的分布式开源协调服务 2.分布式应用可以建立在同步配置管理,选举,分布式锁,分组和命名等服务的更高级别的实现基础上 3.znode维护数据,ACL时间戳等交换版本 ...

  8. Zookeeper运维小结--CancelledKeyException

    https://www.jianshu.com/p/73eec030db86 项目中用到storm+kafka+zookeeper,在实际应用中zk和kafka常出问题,这里记录下在使用zk过程中的问 ...

  9. 类(class)相关概念小结

    参考在线文档,整理php中类的相关概念如下   $this 在类的内部可以使用伪变量$this,这个伪变量为一个到主叫对象(经个人测试理解这应该是在运行时的真实对象,不是类,运行时绑定)的引用,所以一 ...

随机推荐

  1. 洛谷 P1463、POI2002、HAOI2007 反素数

    题意: 求最小的$x\in[1,N]$,使得$x$为$g(x)$最大的数 中最小的一个. 分析: 1.$x$不会有超过$10$个不同质因子.理由:$2 \times 3\times 5...\time ...

  2. Dubbo服务注册与发现

    目录 一.分布式基本理论 1.1.分布式基本定义 1.2 架构发展演变 1.3.RPC简介 二.Dubbo理论简介 三.Dubbo环境搭建 3.1 Zookeeper搭建 3.2 Dubbo管理页面搭 ...

  3. JS高级程序设计第4章--精简版

    前言:纯手打!!!按照自己思路重写!!!这次是二刷了,想暑假做一次完整的笔记,但用本子来写笔记的话太贵了,可能哪天还丢了..所以还是博客好== 第四章:变量.作用域和内存问题 4.1 基本类型和引用类 ...

  4. 个人永久性免费-Excel催化剂功能第45波-逻辑判断函数增强

    自定义函数的最大的作用是可以按需定制,在Excel的原生函数不提供的场景时,传统方法需要使用大量的嵌套函数去实现,实在太累,今天Excel催化剂再次送上一波绝对十分常用的函数逻辑判断类函数给大家使用! ...

  5. java高并发系列 - 第16天:JUC中等待多线程完成的工具类CountDownLatch,必备技能

    这是java高并发系列第16篇文章. 本篇内容 介绍CountDownLatch及使用场景 提供几个示例介绍CountDownLatch的使用 手写一个并行处理任务的工具类 假如有这样一个需求,当我们 ...

  6. idea 警告:Warning:java: 源值1.5已过时, 将在未来所有发行版中删除

    在pom.xml文件中添加 <properties>         <maven.compiler.source>1.8</maven.compiler.source& ...

  7. c语言进阶5-递归算法

    一.  什么是递归 程序调用自身的编程技巧称为递归( recursion). 递归做为一种算法在程序设计语言中广泛应用. 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型 ...

  8. CentOS7 升级 Python2.x 到 Python3.x

    CentOS 7 中默认安装了 Python,版本比较低(2.7.5),为了使用新版 3.x,需要对旧版本进行升级.由于很多基本的命令.软件包都依赖旧版本,比如:yum.所以,在更新 Python 时 ...

  9. npm常用命令(原创)

    1.对于我们下载下来的node包,假设该包存在依赖情况执行: npm install(或者npm i) 下载依赖包: 下载依赖成功过后,文件夹内会产生package-lock.json文件: 2.下载 ...

  10. SpringBoot日志相关

    SpringBoot使用的是SLF4j当门面,Logback当实现完成 日志级别 数字越大,级别越高,框架只会输出大于等于当前日志级别的信息 ERROR 40 WARN 30 INFO 20 DEBU ...