zookeeper入门

几个关键点:

  • 最好集群部署,用于分布式协调

  • 重要的概念:znode/session/watcher(类似订阅发布/观察者模式)/zab协议/读写模式

  • 数据模型:类Linux形式的树形结构

zab协议:

  • z-automatic-broadcast(原子广播)是zk的关键

zab协议

  1. z-automatic-broadcast(原子广播) 是zk的关键
    • 原子广播分为两个步骤:
      1. 消息广播(同步)
      2. 崩溃恢复(选主)
  2. zab核心:定义了事务请求的处理方式
      1. 所有请求都由全局唯一的leader来处理
      1. leader把一个客户端事务请求,转换成一个事务proposal,并将之分发给所有的follower(也就是广播的过程)
      1. leader分发后等待所有的follower的ACK反馈。超过半数后会再向所有的follower发commited消息,要求将上一个事务proposal提交
    • 总结:zab让leader都经历了三个阶段:发现(选举),同步,广播。

znode(zk的节点)

zk的结构类似于Linux的树形目录结构,每个节点既是文件又是路径,即znode/path这种形式,呈树型分布。并以 key/value 形式存储数据。其中根路径以 / 开头。

$ ls /
$ ls /zookeeper
$ ls /zookeeper/quota
$ get /runoob

image
get /runoob后的内容解释:

  • 第一行显示的0是该节点的value值
  • mZxid 最后修改节点时的事务ID
  • pZxid 表示该节点的子节点列表最后一次修改的事务ID,添加子节点或删除子节点就会影响子节点列表,但是修改子节点的数据内容则不影响该ID(注意,只有子节点列表变更了才会变更pzxid,子节点内容变更不会影响pzxid)
  • cversion 子节点版本号,子节点每次修改版本号加1
  • dataversion 数据版本号,数据每次修改该版本号加1
  • numChildren 该节点拥有子节点的数量(只统计直接子节点的数量)

补充


image

此处详情参考znode 结构详解

zookeeper session的基本原理

重要
当之前的链接挂掉后,client访问其他节点的时候,会通过session判断出之前有连接和访问过。

客户端与服务端之间的连接是基于 TCP 长连接,client 端连接 server 端默认的 2181 端口,也就是 session 会话。

从第一次连接建立开始,客户端开始会话的生命周期,客户端向服务端的ping包请求,每个会话都可以设置一个超时时间。

session的创建

  • sessionID: 会话ID,用来唯一标识一个会话,每次客户端创建会话的时候,zookeeper 都会为其分配一个全局唯一的 sessionID。zookeeper 创建 sessionID 类 SessionTrackerImpl 中的源码。

  • 会话超时管理(分桶策略+会话激活)

  • 在 zookeeper 运行过程中,客户端会在会话超时过期范围内向服务器发送请求(包括读和写)或者 ping 请求,俗称心跳检测完成会话激活,从而来保持会话的有效性。

watcher事件机制原理

zk作为分布式的协调者,不能让人基于自旋去管理状态吧,所以订阅-发布这种功能就理所当然了,其实也就是我们常说的观察者模式。观察者会订阅一些感兴趣的主题,然后这些主题一旦变化了,就会自动通知到这些观察者。

zk的订阅发布功能,也就是watcher机制,实现的比较轻量级。因为它采用了一种推拉结合的模式。一旦服务端感知主题变了,那么只会发送一个事件类型和节点信息给关注的客户端,而不会包括具体的变更内容,所以事件本身是轻量级的,这就是所谓的“推”部分。然后,收到变更通知的客户端需要自己去拉变更的数据,这就是“拉”部分。

  1. watcher的目标是谁?
    答:znode/path;节点操作触发watch。(操作有:增删改查、是否存在)
  2. 可以注册watcher的方法:getData、exists、getChildren。
//   连接
     ZooKeeper connect = zookeeperConnection.connect("192.168.44.5:2181");
//   注册watch
     connect.getData("/alex",new GetMyWatch(),connect.exists("/alex",false));
//   因为是main方法,使用此方法保证线程不被停止
     System.in.read();
    /**
     * 自定义监听器
     */
    private static  class GetMyWatch implements Watcher{
        @Override
        public void process(WatchedEvent watchedEvent) {
            System.out.println(watchedEvent.getState());
            System.out.println("getData 数据回调");
        }
    }

可以触发watcher的方法:create、delete、setData。连接断开的情况下触发的watcher会丢失。

zookeeper Watcher机制的特点

  1. 一次性的触发器(one-time trigger)

    当数据改变的时候,Watch事件会产生并且被发送到客户端中。但是客户端只会收到一次这样的通知,如果以后这个数据再次发生改变的时候,之前设置Watch的客户端将不会再次收到改变的通知,因为Watch机制规定了它是一个一次性的触发器。 当设置监视的数据发生改变时,该监视事件会被发送到客户端。例如,如果客户端调用了 getData("/znode1", true) 并且稍后 /znode1 节点上的数据发生了改变或者被删除了,客户端将会获取到 /znode1 发生变化的监视事件,而如果 /znode1 再一次发生了变化,除非客户端再次对 /znode1 设置监视,否则客户端不会收到事件通知。

  2. 发送给客户端(Sent to the client)

    这个表明了Watch的通知事件是从服务器发送给客户端的,是异步的,这就表明不同的客户端收到的Watch的时间可能不同,但是ZooKeeper有保证:当一个客户端在看到Watch事件之前是不会看到结点数据的变化的。例如:A=3,此时在上面设置了一次Watch,如果A突然变成4了,那么客户端会先收到Watch事件的通知,然后才会看到A=4。 Zookeeper 客户端和服务端是通过 Socket 进行通信的,由于网络存在故障,所以监视事件很有可能不会成功地到达客户端,监视事件是异步发送至监视者的,Zookeeper 本身提供了保序性(ordering guarantee):即客户端只有首先看到了监视事件后,才会感知到它所设置监视的 znode 发生了变化(a client will never see a change for which it has set a watch until it first sees the watch event). 网络延迟或者其他因素可能导致不同的客户端在不同的时刻感知某一监视事件,但是不同的客户端所看到的一切具有一致的顺序。

  3. 被设置Watch的数据(The data for which the watch was set)

    这意味着 znode 节点本身具有不同的改变方式。你也可以想象 Zookeeper 维护了两条监视链表: 数据监视和子节点监视(data watches and child watches) getData() and exists() 设置数据监视getChildren() 设置子节点监视。 或者,你也可以想象 Zookeeper 设置的不同监视返回不同的数据,getData() 和 exists() 返回 znode 节点的相关信息,而 getChildren() 返回子节点列表。 因此, setData() 会触发设置在某一节点上所设置的数据监视(假定数据设置成功),而一次成功的 create() 操作则会出发当前节点上所设置的数据监视以及父节点的子节点监视。一次成功的 delete() 操作将会触发当前节点的数据监视和子节点监视事件,同时也会触发该节点父节点的child watch

大白话

watch监控回调: 有个/ooxxlock*,客户端都有自己的一个回调函数FC和自己的地址c,客户端会监控节点事件,就是把自己的地址和回调函数注册到
这个目录,这个目录未来会有事件,比如delete等,当发生后,这个目录会有一个callback的过程,因为知道客户端地址。调起后执行函数是在客户端执行,而非zk集群。

zookeeper 的 watcher 机制,可以分为四个过程:

  • 客户端注册 watcher。
  • 服务端处理 watcher。
  • 服务端触发 watcher 事件。
  • 客户端回调 watcher。

参考

zookeeper选举机制

选举流程简述

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

  • 服务器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成为小弟。
posted @ 2021-06-28 10:58  细雨骑驴入剑门  阅读(70)  评论(0编辑  收藏  举报