ZooKeeper入门

ZooKeeper是一种用于分布式应用系统的分布式开源协调服务中间件。主要是用来解决分布式应用中经常遇到的一些问题。官网地址:http://zookeeper.apache.org/doc/current/zookeeperOver.html

设计目标

  • 简单的数据模型
  • 高可靠
  • 有序
  • 高性能

简单的数据模型

在这里插入图片描述

zk允许各分布式应用通过一个共享的命名空间相互联系,该命名空间类似于一个标准的文件系统(只是类似):由若干注册了的数据节点构成(用zk的术语叫znode),这些节点类似于文件和目录。与专为存储而设计的典型文件系统不同,zk的数据保存在内存中,这意味着zk可以实现高吞吐量和低延迟数量。

高可靠

在这里插入图片描述

就像zk需要协调的分布式系统一样,它本身就具有冗余结构,它构建在一系列主机之上,构成zk服务的各服务器之间必须相互知道,它们维护者一个状态信息的内存映像,以及在持久化存储中维护着事务日志和快照。只要大部分服务器正常工作,zk服务就能正常工作。客户端通过TCP连接到一台zk服务器,通过这个连接,客户端可以发送请求,得到应答,得到监视事件以及发送心跳。如果这个连接断了,客户端可以连接到另一个zk服务器

  1. 客户端随机连接到集群中任何一台server
  2. 集群内所有server基于Zab(ZooKeeper Atomic Broadcast)协议进行通信
  3. 集群内部根据算法自动选举出一个leader,负责向follower(其它server)广播所有变化消息
  4. 集群中每个follower都和leader通信

         • Follower接收来自leader的所有变化消息,保存在自己内存
         • Follower转发来自客户端的写请求给leader
         • 客户端的读请求会在follower端直接服务,无需转发给leader

ZK集群角色

Leader

  1. Leader服务器是zk集群工作机制的核心
  2. 事务请求的唯一调度者和处理者,保证集群事务请求处理的顺序性

Follower

  1. follower服务器是zk集群状态的跟随者
  2. 处理非事务请求,转发事务请求给Leader服务器
  3. 参与事务请求的proposal投票
  4. 参与Leader选举投票

Observer

Observer是一种新型的zk节点,Observer服务器只提供非事务服务。通常用于不影响集群事务处理能力的前提下提升集群的非事务处理能力,Observer有另外一个优势,因为它不参与投票,所以它们不属于zk集群的关键部位,即使它们Failed或者从集群断开,也不会影响集群的可用性。

有序性

zk给每次更新附加一个数字标签,表明zk中的事务顺序,后续操作可以利用这个顺序来完成更高层次的抽象功能,例如同步原语操作。

高性能

zk特别适合于以读为主要负荷的场合。zk可以运行在数千台机器上,如果大部分操作为读,例如读写比例为10:1,zk的效率会很高。下面了解一下数据模型的一些操作:

数据模型

和文章刚开始讲的简单的数据模型一样,zk提供的名称空间非常类似于标准文件系统。名称是由斜杠(/)分隔的路径元素序列。zk名称空间中的每个节点都由路径标识。

节点介绍

在zk中每个命名空间(Namespace)被称为znode,每个znode包含一个路径和与之相关的元数据,以及继承自该节点的子节点列表(临时节点下不能创建子节点),zk旨在存储协调数据:状态信息,配置,位置信息等。因此存储在每个节点的数据通常很小,在字节到千字节范围内。

一个znode维护了一个属性结构,该结构包括:版本号、ACL变更、时间戳。每次znode数据发生变化,版本号都会递增,这样客户端的读请求可以基于版本号来检索状态相关数据。

每个znode都有一个ACL,用来限制是否可以访问该znode。

在一个命名空间中,对znode上存储的数据执行读和写请求操作都是原子的。

节点类型

注意:节点类型在创建时就被确定且不可改变

  • 临时节点(EPHEMERAL):临时创建的,会话结束节点自动被删除,也可以手动删除,临时节点不能拥有子节点
  • 持久节点(PERSISTENT):创建后永久存在,除非主动删除。

以上两种节点为Non-sequence节点,只有一个可以创建成功,其它均失败,并且创建出的节点名称与创建时指定的节点名称完全一样。

  • 临时顺序节点(EPHEMERAL_SEQUENTIAL):具有临时节点特征,但是它会有序列号。
  • 持久顺序节点(PERSISTENT_SEQUENTIAL):具有持久节点特征,但是它会有序列号。

以上两种节点为sequence节点,创建出的节点名在指定的名称之后带有10位10进制的序号,多个客户端创建同一名称的节点时,都能创建成功,只是序号不同。

  • 容器节点(CONTAINER):如果节点中最后一个子Znode被删除,将会触发删除该Znode;
  • 持久定时节点(PERSISTENT_WITH_TTL):客户端断开连接后不会自动删除Znode,如果该Znode没有子Znode且在给定TTL时间内无修改,该Znode将会被删除;TTL单位是毫秒,必须大于0且小于或等于 EphemeralType.MAX_TTL
  • 持久顺序定时节点(PERSISTENT_SEQUENTIAL_WITH_TTL):同PERSISTENT_WITH_TTL,且Znode命名末尾自动添加递增编号;

以上三种节点是在3.5.3-beta版中才有的

节点信息

每一个znode都有对应的stat结构,和文件系统类似。stat状态主要包含以下信息:

  • cZxid 节点被创建时的事务ID
  • mZxid 节点最后一次被修改时候的事务ID
  • pZxid 该节点的子节点最后一次被修改时的事务ID。子节点删除或添加才会影响pZxid
  • ctime 节点被创建的时间
  • mtime 节点被修改的世界
  • dataVersion 这个节点数据改变的次数
  • cversion 子节点被改变的次数
  • aclVersion 节点的ACL(访问控制列表被改变的次数)
  • ephemeralOwner 创建该临时节点的 session ID。如果是持久节点,设置为0
  • dataLength 数据内容长度
  • numChildren 当前节点子节点的个数

可以使用ls2和stat命令查看ZooKeeper节点下的信息

节点的访问控制(ACL)

zk提供了ACL来控制znode节点的访问,只有符合了ACL控制,才可以操作该节点,否则将无法操作。

Zookeeper支持可配置的认证机制。它利用一个三元组来定义客户端的访问权限(scheme:expression, perms) 。其中:

Schema 代表权限控制模式,分别为:

  • World 任何人
  • Auth 不需要ID
  • Digest 用户名和密码方式的认证
  • IP Address IP地址方式的认证

perms(权限),ZooKeeper支持如下权限

  • CREATE: 创建子节点
  • READ: 获取子节点与自身节点的数据信息
  • WRITE:在Znode节点上写数据
  • DELETE:删除子节点
  • ADMIN:设置ACL权限

注意:Znode的Acl只是针对某个节点,不会作用到它的子节点上,任何连接到ZooKeeper的客户端都可以使用exist操作,exist是不需要权限的。

zk的特性

顺序一致性

客户端的更新顺序与它们被发送的顺序一致。

原子性

更新操作要么成功,要么失败,没有第三种结果。

单系统映像

无论客户端连接到哪一个服务器,他都将看到相同的zk视图。

可靠性

一旦一个更新操作被应用,那么在客户端再次更新之前,其值不会再改变。

实时性

zk保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。 但由于网络延时等原因,zk不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。

zk的Watch机制

zk支持监听, 客户端能够设置监听znode节点. 当znode节点变更时可能触发或者移除监听.当监听事件被触发了,客户端将会收到数据通知包,告诉客户端节点数据被修改了. 同时如果当前客户端和zk节点的连接被断开了.客户端将收到一个本地通知.

Watcher事件类型

  • NodeChildrenChanged: zNode的子节点创建或删除的时候
  • NodeCreated: 新的Znode节点被创建的时候
  • NodeDataChanged: Znode节点的数据改变了的时候
  • NodeDeleted: Znode节点被删除的时候。

Watcher操作特点

  • 主动推送 Watch被触发时,由 zk 服务器主动将更新推送给客户端,而不需要客户端轮询。
  • 一次性 数据变化时,Watch 只会被触发一次。如果客户端想得到后续更新的通知,必须要在 Watch 被触发后重新注册一个 Watch。
  • 可见性 如果一个客户端在读请求中附带 Watch,Watch 被触发的同时再次读取数据,客户端在得到 Watch 消息之前肯定不可能看到更新后的数据。换句话说,更新通知先于更新结果。
  • 顺序性 如果多个更新触发了多个 Watch ,那 Watch 被触发的顺序与更新顺序一致。避免安装大量watches侦听在同一个节点

zk的Session

客户端和server间采用长连接,连接建立后,server产生session ID(64位)返还给客户端。客户端定期发送ping包来检查和保持和server的 连接。一旦session结束或超时,所有ephemeral节点会被删除。客户端可根据情况设置合适的session超时时间。客户端能够异步接收来自服务端的Watcher事件通知。

ZooKeeper典型8大应用场景及对应的特性

配置管理服务

例如当当的configtoolkit配置中心,就是将配置信息放到了zk上,假如你有20个节点,需要修改配置文件的时候,你总不能一个节点一个节点去更改吧。那假如有100个节点呢?在分布式系统中,有很多实例中的大多数配置项是相同的(比如数据库连接等),需要改变配置项,如果有zk的话,不需要在每个实例去修改。所有实例在启动时,都会去zk拉取节点信息,当节点信息修改的时候会通知到每一个实例,某些配置项也可以达到热配置的效果。

集群管理(Master选举)

在分布式的集群中,经常会由于各种原因,比如硬件故障,软件故障,网络问题,有些节点会进进出出。有新的节点加入进来,也有老的节点退出集群。这个时候,集群中其他机器需要感知到这种变化,然后根据这种变化做出对应的决策。比如我们是一个分布式存储系统,有一个中央控制节点负责存储的分配,当有新的存储进来的时候我们要根据现在集群目前的状态来分配存储节点。这个时候我们就需要动态感知到集群目前的状态。还有,比如一个分布式的SOA架构中,服务是一个集群提供的,当消费者访问某个服务时,就需要采用某种机制发现现在有哪些节点可以提供该服务(这也称之为服务发现,比如Alibaba开源的SOA框架Dubbo就采用了zk作为服务发现的底层机制)。还有开源的Kafka队列就采用了zk作为Cosnumer的上下线管理。
还有一个场景:集群选master,一旦master挂掉能够马上能从slave中选出一个master,这个实现和上面实现一样。

命名服务

命名服务就是指通过指定的名字来获取资源或者服务的地址。zk会在自己的文件系统上(树结构的文件系统)创建一个以路径为名称的节点,它可以指向提供的服务的地址,远程对象等。分布式服务框架Dubbo中使用ZooKeeper来作为其命名服务,维护全局的服务地址列表。

分布式计数器

在分布式环境下,获取唯一id,功能和redis自增返回值一样,指定一个Zookeeper数据节点作为计数器,多个应用实例在分布式锁的控制下,通过更新该数据节点的内容来实现计数功能。

分布式协调通知

说分布式协调通知就有点广了,上面所说的配置服务和集群管理就是用到了分布式协调通知,分布式协调/通知服务是分布式系统中不可缺少的一个环节,是将不同的分布式组件有机结合起来的关键所在。
利用zk中特有的Watcher注册与异步通知机制,能够很好的实现分布式环境下不同机器,甚至是不同系统之间的协调与通知,从而实现对数据变更的实时处理。
利用zk的心跳机制和临时节点特性,可以让不同的机器都在zk的一个指定节点下创建临时子节点,不同的机器之间可以根据这个临时节点来判断对应的客户端机器是否存活。通过这种方式,检测系统和被检测系统之间并不需要直接相关联,而是通过zk上的某个节点进行关联,大大减少了系统耦合。

发布订阅

发布/订阅模式是一对多的关系,多个订阅者对象同时监听某一主题对象,这个主题对象在自身状态发生变化时会通知所有的订阅者对象。使它们能自动的更新自己的状态。发布/订阅可以使得发布方和订阅方独立封装、独立改变。当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象需要改变时可以使用发布/订阅模式。发布/订阅模式在分布式系统中的典型应用有配置管理和服务发现、注册。

配置管理是指如果集群中的机器拥有某些相同的配置并且这些配置信息需要动态的改变,我们可以使用发布/订阅模式把配置做统一集中管理,让这些机器格子各自订阅配置信息的改变,当配置发生改变时,这些机器就可以得到通知并更新为最新的配置。

服务发现、注册是指对集群中的服务上下线做统一管理。每个工作服务器都可以作为数据的发布方向集群注册自己的基本信息,而让某些监控服务器作为订阅方,订阅工作服务器的基本信息,当工作服务器的基本信息发生改变如上下线、服务器角色或服务范围变更,监控服务器可以得到通知并响应这些变化。

分布式锁

每个客户端对某个方法加锁时,在zk上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。 判断是否获取锁的方式很简单,只需要判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听/lock的子节点变更消息,获得子节点变更通知后重复此步骤直至获得锁。

队列管理

zk队列不太适合要求高性能的场合,可以考虑在数据量不大的情况下使用。毕竟引进一个消息中间件会增加系统的复杂性和运维的压力。当然了,首先已有项目中要使用zk。
使用zk实现先进先出队列就是在特定的目录下创建PERSISTENT_EQUENTIAL(永久、序列化)节点,创建成功时Watcher通知等待的队列,队列删除序列号最小的节点用以消费。此场景下zk的znode用于消息存储,znode存储的数据就是消息队列中的消息内容,SEQUENTIAL序列号就是消息的编号,按序取出即可。由于创建的节点是持久化的,所以不必担心队列消息的丢失问题。
SEQUENTIAL:一旦节点被标记上SEQUENTIAL这个属性,那么在这个节点被创建的时候,ZooKeeper 就会自动在其节点后面追加上一个整型数字,这个整型数字是一个由父节点维护的自增数字。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值