【大数据】ZooKeeper(下)

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 【大数据】ZooKeeper
  1. 节点类型


Znode有两种,分别为临时节点和永久节点。


节点的类型在创建时即被确定,并且不能改变。


临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话结束,临时节点将被自动删除,当然可以也可以手动删除。临时节点不允许拥有子节点。


永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。


Znode还有一个序列化的特性,如果创建的时候指定的话,该Znode的名字后面会自动追加一个不断增加的序列号。序列号对于此节点的父节点来说是唯一的,这样便会记录每个子节点创建的先后顺序。它的格式为“%10d”(10位数字,没有数值的数位用0补充,例如“0000000001”)。


81a4708bbb0c459db746e600cda874f3.png

这样便会存在四种类型的Znode节点,分别对应:

PERSISTENT:永久节点

EPHEMERAL:临时节点

PERSISTENT_SEQUENTIAL:永久节点、序列化

EPHEMERAL_SEQUENTIAL:临时节点、序列化


  1. 节点属性

每个znode都包含了一系列的属性,通过命令get,可以获得节点的属性。


67a9dca1509c4dd8b8d77cfb1230cfa2.png


dataVersion:数据版本号,每次对节点进行set操作,dataVersion的值都会增加1(即使设置的是相同的数据),可有效避免了数据更新时出现的先后顺序问题。


cversion :子节点的版本号。当znode的子节点有变化时,cversion 的值就会增加1。


cZxid :Znode创建的事务id。


mZxid :Znode被修改的事务id,即每次对znode的修改都会更新mZxid。


对于zk来说,每次的变化都会产生一个唯一的事务id,zxid(ZooKeeper Transaction Id)。通过zxid,可以确定更新操作的先后顺序。例如,如果zxid1小于zxid2,说明zxid1操作先于zxid2发生,zxid对于整个zk都是唯一的,即使操作的是不同的znode。


ctime:节点创建时的时间戳.


mtime:节点最新一次更新发生时的时间戳.


ephemeralOwner:如果该节点为临时节点, ephemeralOwner值表示与该节点绑定的session id. 如果不是, ephemeralOwner值为0.


在client和server通信之前,首先需要建立连接,该连接称为session。连接建立后,如果发生连接超时、授权失败,或者显式关闭连接,连接便处于CLOSED状态, 此时session结束。


  1. ZooKeeper Watcher(监听机制)


ZooKeeper提供了分布式数据发布/订阅功能,一个典型的发布/订阅模型系统定义了一种一对多的订阅关系,能让多个订阅者同时监听某一个主题对象,当这个主题对象自身状态变化时,会通知所有订阅者,使他们能够做出相应的处理。


ZooKeeper中,引入了Watcher机制来实现这种分布式的通知功能。ZooKeeper允许客户端向服务端注册一个Watcher监听,当服务端的一些事件触发了这个Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。


触发事件种类很多,如:节点创建,节点删除,节点改变,子节点改变等。


总的来说可以概括Watcher为以下三个过程:客户端向服务端注册Watcher、服务端事件发生触发Watcher、客户端回调Watcher得到触发事件情况


  1. Watch机制特点


一次性触发


事件发生触发监听,一个watcher event就会被发送到设置监听的客户端,这种效果是一次性的,后续再次发生同样的事件,不会再次触发。


事件封装


ZooKeeper使用WatchedEvent对象来封装服务端事件并传递。


WatchedEvent包含了每一个事件的三个基本属性:


通知状态(keeperState),事件类型(EventType)和节点路径(path)


event异步发送  


watcher的通知事件从服务端发送到客户端是异步的。


先注册再触发


Zookeeper中的watch机制,必须客户端先去服务端注册监听,这样事件发送才会触发监听,通知给客户端。


  1. 通知状态和事件类型

同一个事件类型在不同的通知状态中代表的含义有所不同,下表列举了常见的通知状态和事件类型。

57e3761e07874b2e8c13de6f17dd89a4.png


其中连接状态事件(type=None, path=null)不需要客户端注册,客户端只要有需要直接处理就行了。


  1. 监听器原理

dd483638efaa4bcbbf7a3e6dc5dd04d2.png


  1. Shell 客户端设置watcher

设置节点数据变动监听:

e8906d013ad04e89af18381a369e5260.png


通过另一个客户端更改节点数据:


c949d77980eb4ddda9dafab1f65586af.png

此时设置监听的节点收到通知:

e9b9dd785d8a4850978098bd748a175c.png

  1. Zookeeper的Api应用


Zookeeper 是在 Java 中客户端主类,负责建立与 zookeeper 集群的会话,并提供方法进行操作。org.apache.zookeeper.Watcher


Watcher 接口表示一个标准的事件处理器,其定义了事件通知相关的逻辑,


包含 KeeperState 和 EventType 两个枚举类,分别代表了通知状态和事件类型,


同时定义了事件的回调方法:process(WatchedEvent event)。


process 方法是 Watcher 接口中的一个回调方法,当 ZooKeeper 向客户端发送一个 Watcher 事件通知时,客户端就会对相应的 process 方法进行回调,从而实现对事件的处理。


  1. 创建Maven工程,导入依赖
  1. 创建一个Maven工程

2)添加pom文件


<dependencies>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.8.0</version>
</dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
    </dependency>
</dependencies>


3)拷贝log4j.properties文件到项目根目录


需要在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入。


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  


  1. 创建ZooKeeper客户端

创建包com.czxy.zk,在包下创建zkClinet类

5.2.1初始化客户端连接


   private String connectString="hadoop01:2181,hadoop02:2181,hadoop03:2181";
    private int sessionTimeout=2000;
    private ZooKeeper zkClient;
    @Test
    public void init() throws IOException {
        zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            public void process(WatchedEvent event) {
            }
        });


5.2.2创建子节点


 @Test
    //注意init方法要改为@Before
    public void create() throws KeeperException, InterruptedException {
// 参数1:要创建的节点的路径; 参数2:节点数据 ; 参数3:节点权限 ;参数4:节点的类型
        String nodeCreate = zkClient.create("/czxy", "bigdata".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}


5.2.3获取子节点监听节点变化

修改代码init方法,注册监听,创建getChildren方法并设置监听

@Before
    public void init() throws IOException {
        zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            public void process(WatchedEvent event) {
                System.out.println("=========================");
                List<String> children = null;
                try {
                    children = zkClient.getChildren("/", true);
                    for (String child : children) {
                        System.out.println(child);
                    }
                    System.out.println("=========================");
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
    // 获取子节点
    @Test
    public void getChildren() throws Exception {
        List<String> children = zkClient.getChildren("/", true);
        for (String child : children) {
            System.out.println(child);
        }
        // 延时阻塞
        Thread.sleep(Long.MAX_VALUE);
}

5.2.4判断Znode是否存在


  @Test
    public void exist() throws Exception {
        Stat stat = zkClient.exists("/czxy", false);
        System.out.println(stat == null ? "not exist" : "exist");
    }
  1. ZooKeeper选举机制

Zookeeper默认的算法是FastLeaderElection,采用投票数大于半数则胜出的逻辑。

  1. 相关概念

服务器ID


比如有三台服务器,编号分别是1,2,3。


编号越大在选择算法中的权重越大。


选举状态


LOOKING,竞选状态。


FOLLOWING,随从状态,同步leader状态,参与投票。


OBSERVING,观察状态, 同步leader状态,不参与投票。


LEADING,领导者状态。


数据ID


服务器中存放的最新数据version。


值越大说明数据越新,在选举算法中数据越新权重越大。


逻辑时钟


也叫投票的次数,同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加,然后与接收到的其它服务器返回的投票信息中的数值相比,根据不同的值做出不同的判断。


  1. 全新集群选举

假设目前有5台服务器,每台服务器均没有数据,它们的编号分别是1,2,3,4,5,按编号依次启动,它们的选择举过程如下:


c295fad0462c47ecb87828f13bc916d3.png

服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于LOOKING。

服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是LOOKING。

服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1,2成为小弟。

服务器4启动,给自己投票,同时与之前启动的服务器1,2,3交换信息,尽管服务器4的编号大,但之前服务器3已经胜出,所以服务器4只能成为小弟。

服务器5启动,后面的逻辑同服务器4成为小弟


  1. 非全新集群选举


对于运行正常的zookeeper集群,中途有机器down掉,需要重新选举时,选举过程就需要加入数据ID、服务器ID和逻辑时钟。


数据ID:数据新的version就大,数据每次更新都会更新version。


服务器ID:就是我们配置的myid中的值,每个机器一个。


逻辑时钟:这个值从0开始递增,每次选举对应一个值。 如果在同一次选举中,这个值是一致的。


这样选举的标准就变成:


1、逻辑时钟小的选举结果被忽略,重新投票;


2、统一逻辑时钟后,数据id大的胜出;


3、数据id相同的情况下,服务器id大的胜出;


根据这个规则选出leader。


相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
10月前
|
大数据 开发工具
|
1月前
|
存储 分布式计算 大数据
【云计算与大数据技术】分布式协同系统Chubby锁、ZooKeeper在HDFS中的使用讲解(图文解释 超详细)
【云计算与大数据技术】分布式协同系统Chubby锁、ZooKeeper在HDFS中的使用讲解(图文解释 超详细)
105 0
|
9月前
|
存储 大数据 Java
大数据Zookeeper组件 2
大数据Zookeeper组件
148 0
|
9月前
|
大数据 关系型数据库 MySQL
大数据Zookeeper组件 1
大数据Zookeeper组件
48 0
|
11月前
|
大数据 容器
大数据平台搭建(容器环境)——Zookeeper安装部署
大数据平台搭建(容器环境)——Zookeeper安装部署
|
10月前
|
存储 数据采集 分布式计算
hadoop离线01--大数据导论、Apache Zookeeper
hadoop离线01--大数据导论、Apache Zookeeper
|
分布式计算 Java Hadoop
flink hadoop 从0~1分布式计算与大数据项目实战(4)zookeeper内部原理流程简介以及java curator client操作集群注册,读取
flink hadoop 从0~1分布式计算与大数据项目实战(4)zookeeper内部原理流程简介以及java curator client操作集群注册,读取
flink hadoop 从0~1分布式计算与大数据项目实战(4)zookeeper内部原理流程简介以及java curator client操作集群注册,读取
|
存储 监控 算法
【大数据】ZooKeeper(上)
【大数据】ZooKeeper
100 0
【大数据】ZooKeeper(上)
|
Ubuntu Java 大数据
大数据Zookeeper-03.集群环境安装
Zookeeper集群环境安装
153 0
大数据Zookeeper-03.集群环境安装
|
Ubuntu Java 大数据
大数据Zookeeper-02.伪分布式安装
Zookeeper伪分布式安装
205 0
大数据Zookeeper-02.伪分布式安装