资讯专栏INFORMATION COLUMN

【zookeeper源码阅读】数据模型Znode

cikenerd / 1690人阅读

摘要:当服务端的一些操作触发了事件监听,就会向指定的客户端发送事件通知。因此,使用的监听机制实现的发布订阅系统使用的推拉结合的方式。

本文主要对zookeeper的数据模型Znode进行的简要说明 主要内容:
1. zk的主要应用场景
2. zk的数据节点的概述

数据节点的类型

节点的数据结构

节点上的监听机制

1. zk的主要应用场景

数据的发布与订阅

负载均衡

统一命名服务

分布式协调与通知

集群管理

master选举

分布式锁与分布式队列

具体将在后续的文章中给出具体的应用介绍。

2. zk的数据节点的概述

在介绍数据节点之前,先给大家说明一下zk中事务的概念。zk中的事务指的是能够改变zk服务器状态的操作,包括

数据节点的删除,创建和内容更新等

客户端会话的创建与失效

zk中还有一个事务id的概念,会为每次事务请求分配一个全局唯一的id,关于事务id的特点简要说明如下:

64位数字

高32是Leader统治时期的标识,说明该事务是在哪个Leader时期进行的

低32位是事务的id号

通过这64位数字可以确定一个事务请求的全局唯一的顺序

2.1 zk数据节点的类型

zk中的数据节点是有生命周期的概念的,根据生命周期的不同可以划分为两种类型的节点

持久节点(Persistent)

最常见的一种节点类型,也叫做regular节点。数据节点一旦被创建,就会一直存在于zk服务器上,直到有删除事务操作主动清除该节点

临时节点(Ephemeral)

临时节点的生命周期是和客户端会话绑定在一起的,只要客户端会话失效,那么临时节点就会被清除。这里的客户端会话失效和客户端tcp连接断开是不一样的。
临时节点只能是leaf节点

顺序节点(Sequential)

zk会给创建的节点自动加上一个数字后缀,作为一个完整的节点名称,这种方式可以维护节点之间的一种顺序性

持久节点+顺序节点

临时节点+顺序节点

2.2 节点的数据结构

数据节点的类结构代码如下:

public class DataNode implements Record {
    byte data[];                    //节点上存储的数据
    Long acl;                        //权限控制列表版本号
    public StatPersisted stat;        //节点状态信息
    private Set children = null; //节点的子节点列表
}

StatPersisted stat是该节点的状态信息类,类结构代码如下:

public class StatPersisted implements Record {
  private long czxid;                //创建该节点的事务id
  private long mzxid;                //最后一次修改节点的事务id
  private long ctime;                //节点的创建时间
  private long mtime;                //最后一次更新节点内容的时间
  private int version;                //数据节点的版本号,version=0表示该节点被创建之后,更新过0次,在实现乐观锁的时候有用
  private int cversion;                //子节点的版本号,只有当子节点列表被更改后,才会+1
  private int aversion;                //子节点的acl列表版本号
  private long ephemeralOwner;        //如果是临时节点,该值表示创建该节点的临时会话的sessionID,如果是持久节点的话,该值为0
  private long pzxid;                //子节点列表最后一次被修改时的事务id,一定是子节点列表被修改,子节点的内容被修改是不会改变这个属性的值的
}
2.3 节点上的监听机制

zookeeper允许客户端对象在数据节点上注册事件监听,可以实现数据的发布与订阅。

当zk服务端的一些操作触发了事件监听Watcher,就会向指定的客户端发送事件通知。

zk中的事件监听机制由三部分组成:

zk服务端

客户端线程

客户端的WatcherManager

客户端线程在zk服务器上注册事件监听之后,会将这个watcher对象存储在WatcherManager中,当zk服务器触发这个事件之后,会向客户端发送通知,客户端线程会从WatcherManager中取出对应的Watcher对象来执行回调逻辑。

监听器的接口类Watcher代码如下
public interface Watcher{
    public interface Event{
        public enum KeeperState{ 
            Disconnected(0),   //断开连接
            SyncConnected(3),  //此时客户端与zk服务器处于连接状态
            AuthFailed(4),        //权限检查失败
            ConnectedReadOnly(5) //客户端和一台只读server处于连接状态,what is readonly server? 就是只和集群中的一小部分服务器处于连接的服务器
            Expired(-122)        //会话超时
        }
        public enum EventType{
            None (-1),
            NodeCreated (1),    //watcher监听的数据节点被创建
            NodeDeleted (2),    //watcher监听的数据节点被删除
            NodeDataChanged (3), //watcher监听的数据节点内容被更新
            NodeChildrenChanged (4), //watcher监听的数据节点的子节点列表被更新了
            DataWatchRemoved (5), 
            ChildWatchRemoved (6);
        }
    }
    public enum WatcherType{
        Children (1),
        Data (2),
        Any (3);
    }
    abstract public void process(WatchedEvent event);
}

主要有以下几个部分组成

Watcher.Event.KeeperState: 表示通知状态

Watcher.Event.EventType: 表示通知的事件类型

Watcher.WatcherType: 监听器的类型

process(WatchedEvent event) 事件的回调函数

在处理监听事件的回调函数process中,参数event是一个org.apache.zookeeper.WatchedEvent类型的参数。WatchedEvent说明如下

public class WatchedEvent {
    final private KeeperState keeperState;    //通知的状态
    final private EventType eventType;        //事件类型
    private String path;                     //参与该事件的节点路径
    /**
    *实现WatchedEvent到WatcherEvent的转换
    */
    public WatcherEvent getWrapper() {
    return new WatcherEvent(eventType.getIntValue(), 
                            keeperState.getIntValue(), 
                            path);
    }
    /**
    *实现WatcherEvent到WatchedEvent的转换
    */
    public WatchedEvent(WatcherEvent eventMessage) {
        keeperState = KeeperState.fromInt(eventMessage.getState());
        eventType = EventType.fromInt(eventMessage.getType());
        path = eventMessage.getPath();
    }
}

从WatchedEvent的代码中可以看出一个监听事件由三个部分组成的:

Watcher.Event.KeeperState:通知状态

Watcher.Event.EventType:通知类型

String path:参与该事件的节点路径

并且,与WatchedEvent对应的还有一个类WatcherEvent,这个WatcherEvent和WatchedEvent相比,只是实现了序列化,方便通过网络在服务端和客户端之间传输。
序列化使用的是jute

整个监听通知的机制过程描述如下:

客户端在服务器数据节点上注册相应的监听事件Watcher,注册的方式后面阐述

服务端操作触发该事件,生成WatchedEvent事件对象

调用getWrapper方法将WatchedEvent包装称为一个实现序列化的、可在网络上传输的WatcherEvent对象

通过网络将WatcherEvent对象发送到client

client将WatcherEvent对象还原成为一个WatchedEvent对象,并传递给process方法进行处理

客户端接受到的服务器传送过来的监听事件的格式如下:

KeeperState:SyncConnected
EventType:NodeDataChanged
Path:    /zk-book

显然,从接收到的事件中,客户端是无法获取到该节点在更新前后的数据的,因此客户端是要主动再向服务器获取数据。因此,使用zk的监听机制实现的发布订阅系统使用的"推拉"结合的方式。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74052.html

相关文章

  • 可能是全网把 ZooKeeper 概念讲的最清楚的一篇文章

    摘要:的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。具有不可分割性即原语的执行必须是连续的,在执行过程中不允许被中断。 该文已加入开源文档:JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识)。地址:https://github.com/Snailclimb... showImg(https:...

    DrizzleX 评论0 收藏0
  • 分布式协调服务:zookeeper

    摘要:协调服务的功能在分布式架构中,每个服务器或者服务之间信息的协调和管理是非常有必要的常见的分布式协调服务有的,的因为谷歌的是不开源的,后来雅虎模仿它开发了,并捐赠给,并将其开源供大家使用我们先从的几个功能来了解名称服务什么是名称服务比如将域名 协调服务的功能 在分布式架构中,每个服务器或者服务之间信息的协调和管理是非常有必要的 常见的分布式协调服务有Google的Chubby,Apach...

    cocopeak 评论0 收藏0
  • 大牛整理的ZooKeeper笔记

    摘要:除此之外,它严格的序列访问控制意味着复杂的控制原语可以应用在客户端上。版本号对节点的每一个操作都将致使这个节点的版本号增加。事件是一次性的触发器,当的对象状态发生改变时,将会触发此对象上所对应的事件。节点事件节点的建立,删除,数据的修改。 目录 一、ZooKeeper概述 二、ZooKeeper数据模型 三、ZooKeeper服务中操作 四、Watch触发器 五、ZooKeeper应用...

    Noodles 评论0 收藏0
  • Zookeeper学习系列【一】 教会你Zookeeper的一些基础概念

    摘要:具有不可分割性即原语的执行必须是连续的,在执行过程中不允许被中断。提供服务主要就是通过数据结构原语集机制达到的。子节点的版本号数据节点版本号版本号创建该节点的会话的。后位则为递增序列。 前言 最近加入了部门的技术兴趣小组,被分配了Zookeeper的研究任务。在研究过程当中,发现Zookeeper由于其开源的特性和其卓越的性能特点,在业界使用广泛,有很多的应用场景,而这些不同的应用场景...

    DevWiki 评论0 收藏0
  • 快速了解zookeeper

    摘要:之后服务器等待其他服务器的反馈,一旦超过半数的服务器进行了正确的反馈,那么就会再次向所有的服务器分发消息,要求其将前一个进行提交。协议包括两种基本的模式,分别是崩溃恢复和消息广播。 前言 zookeeper本质上就是一个分布式协调服务,用来解决分布式一致性的问题。 本文适合有一定分布式基础的读者阅读。什么叫相关的基础呢?起码你得知道系统架构为何从集中式演变成了分布式,分布式有哪些优点...

    imccl 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<