问题导读:

1.ZooKeeper的数据模型是什么 ?
2.ZooKeeper应用有哪些陷阱 ?
3.每个节点(ZNode)中存储的是什么?
4.一个ZNode维护了一个状态结构都包含了什么?
5.ZNode组成结构是什么?
6.Watches的机制是什么?
7.ZooKeeper内置了哪4种方式实现ACL?

前言

ZooKeeper是一个开源的分布式服务框架,它是ApacheHadoop项目的一个子项目,主要用来解决分布式应用场景中存在的一些问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置管理等,它支持Standalone模式和分布式模式,在分布式模式下,能够为分布式应用提供高性能和可靠地协调服务,而且使用ZooKeeper可以大大简化分布式协调服务的实现,为开发分布式应用极大地降低了成本。
总体架构
ZooKeeper分布式协调服务框架的总体架构,如图所示:
<ignore_js_op> 
ZooKeeper集群由一组Server节点组成,这一组Server节点中存在一个角色为Leader的节点,其他节点都为Follower。当客户端Client连接到ZooKeeper集群,并且执行写请求时,这些请求会被发送到Leader节点上,然后Leader节点上数据变更会同步到集群中其他的Follower节点。
Leader节点在接收到数据变更请求后,首先将变更写入本地磁盘,以作恢复之用。当所有的写请求持久化到磁盘以后,才会将变更应用到内存中。
ZooKeeper使用了一种自定义的原子消息协议,在消息层的这种原子特性,保证了整个协调系统中的节点数据或状态的一致性。Follower基于这种消息协议能够保证本地的ZooKeeper数据与Leader节点同步,然后基于本地的存储来独立地对外提供服务。
当一个Leader节点发生故障失效时,失败故障是快速响应的,消息层负责重新选择一个Leader,继续作为协调服务集群的中心,处理客户端写请求,并将ZooKeeper协调系统的数据变更同步(广播)到其他的Follower节点。
设计要点
ZooKeeper是基于如下4个目标来进行权衡和设计的,我们从设计及其特性的角度来详细说明:
 
简单
分布式应用中的各个进程可以通过ZooKeeper的命名空间(Namespace)来进行协调,这个命名空间是共享的、具有层次结构的,更重要的是它的结构足够简单,像我们平时接触到的文件系统的目录结构一样容易理解,如图所示:
<ignore_js_op>
 
在ZooKeeper中每个命名空间(Namespace)被称为ZNode,你可以这样理解,每个ZNode包含一个路径和与之相关的元数据,以及继承自该节点的孩子列表。与传统文件系统不同的是,ZooKeeper中的数据保存在内存中,实现了分布式同步服务的高吞吐和低延迟。
在上图示例的ZooKeeper的数据模型中,有如下要点:
每个节点(ZNode)中存储的是同步相关的数据(这是ZooKeeper设计的初衷,数据量很小,大概B到KB量级),例如状态信息、配置内容、位置信息等。
一个ZNode维护了一个状态结构,该结构包括:版本号、ACL变更、时间戳。每次ZNode数据发生变化,版本号都会递增,这样客户端的读请求可以基于版本号来检索状态相关数据。
每个ZNode都有一个ACL,用来限制是否可以访问该ZNode。
在一个命名空间中,对ZNode上存储的数据执行读和写请求操作都是原子的。
客户端可以在一个ZNode上设置一个监视器(Watch),如果该ZNode数据发生变更,ZooKeeper会通知客户端,从而触发监视器中实现的逻辑的执行。
每个客户端与ZooKeeper连接,便建立了一次会话(Session),会话过程中,可能发生CONNECTING、CONNECTED和CLOSED三种状态。
ZooKeeper支持临时节点(EphemeralNodes)的概念,它是与ZooKeeper中的会话(Session)相关的,如果连接断开,则该节点被删除。
 
冗余
ZooKeeper被设计为复制集群架构,每个节点的数据都可以在集群中复制传播,使集群中的每个节点数据同步一致,从而达到服务的可靠性和可用性。前面说到,ZooKeeper将数据放在内存中来提高性能,为了避免发生单点故障(SPOF),支持数据的复制来达到冗余存储,这是必不可少的。
 
有序
ZooKeeper使用时间戳来记录导致状态变更的事务性操作,也就是说,一组事务通过时间戳来保证有序性。基于这一特性。ZooKeeper可以实现更加高级的抽象操作,如同步等。
 
快速
ZooKeeper包括读写两种操作,基于ZooKeeper的分布式应用,如果是读多写少的应用场景(读写比例大约是10:1),那么读性能更能够体现出高效。
数据模型
ZooKeeper有一个分层的命名空间,结构类似文件系统的目录结构,非常简单而直观。其中,ZNode是最重要的概念,前面我们已经描述过。另外,有ZNode有关的还包括Watches、ACL、临时节点、序列节点(Sequence Node)。
ZNode结构
ZooKeeper中使用Zxid(ZooKeeperTransaction Id)来表示每次节点数据变更,一个Zxid与一个时间戳对应,所以多个不同的变更对应的事务是有序的。下面是ZNode的组成结构,引用文档如下所示:
czxid – The zxid of the change that causedthis znode to be created.
mzxid – The zxid of the change that lastmodified this znode.
ctime – The time in milliseconds from epochwhen this znode was created.
mtime – The time in milliseconds from epochwhen this znode was last modified.
version – The number of changes to the dataof this znode.
cversion – The number of changes to thechildren of this znode.
aversion – The number of changes to the ACLof this znode.
ephemeralOwner – The session id of theowner of this znode if the znode is an ephemeral node. If it is not anephemeral node, it will be zero.
dataLength – The length of the data fieldof this znode.
numChildren – The number of children ofthis znode.
Watches(监视)
ZooKeeper中的Watch是只能触发一次。也就是说,如果客户端在指定的ZNode设置了Watch,如果该ZNode数据发生变更,ZooKeeper会发送一个变更通知给客户端,同时触发设置的Watch事件。如果ZNode数据又发生了变更,客户端在收到第一次通知后没有重新设置该ZNode的Watch,则ZooKeeper就不会发送一个变更通知给客户端。
ZooKeeper异步通知设置Watch的客户端。但是ZooKeeper能够保证在ZNode的变更生效之后才会异步地通知客户端,然后客户端才能够看到ZNode的数据变更。由于网络延迟,多个客户端可能会在不同的时间看到ZNode数据的变更,但是看到变更的顺序是能够保证有序一致的。
ZNode可以设置两类Watch,一个是DataWatches(该ZNode的数据变更导致触发Watch事件),另一个是Child Watches(该ZNode的孩子节点发生变更导致触发Watch事件)。调用getData()和exists() 方法可以设置Data Watches,调用getChildren()方法可以设置Child Watches。调用setData()方法触发在该ZNode的注册的Data Watches。调用create()方法创建一个ZNode,将触发该ZNode的Data Watches;调用create()方法创建ZNode的孩子节点,则触发ZNode的Child Watches。调用delete()方法删除ZNode,则同时触发Data Watches和Child Watches,如果该被删除的ZNode还有父节点,则父节点触发一个Child Watches。
另外,如果客户端与ZooKeeper Server断开连接,客户端就无法触发Watches,除非再次与ZooKeeper Server建立连接。
Sequence Nodes(序列节点)
在创建ZNode的时候,可以请求ZooKeeper生成序列,以路径名为前缀,计数器紧接在路径名后面,例如,会生成类似如下形式序列
qn-0000000001, qn-0000000002,qn-0000000003, qn-0000000004, qn-0000000005, qn-0000000006, qn-0000000007
对于ZNode的父节点来说,序列中的每个计数器字符串都是唯一的,最大值为2147483647。
ACLs(访问控制列表)
ACL可以控制访问ZooKeeper的节点,只能应用于特定的ZNode上,而不能应用于该ZNode的所有孩子节点上。它主要有如下五种权限:
CREATE 允许创建Child Nodes
READ 允许获取ZNode的数据,以及该节点的孩子列表
WRITE 可以修改ZNode的数据
DELETE 可以删除一个孩子节点
ADMIN 可以设置权限
ZooKeeper内置了4种方式实现ACL:
world 一个单独的ID,表示任何人都可以访问
auth 不使用ID,只有认证的用户可以访问
digest 使用username:password生成MD5哈希值作为认证ID
ip 使用客户端主机IP地址来进行认证
ZooKeeper Session
当客户端连接到ZooKeeper集群时,建立了会话。会话过程中的状态变迁,如图所示:
<ignore_js_op>
建立连接过程中,会话状态为CONNECTING;当连接建立成功后,会话状态变为CONNECTED。会话过程中,如果正常的话,会话的状态只能是CONNECTING和CONNECTED二者之一。如果在会话过程中连接断开,则变为CLOSED状态。
应用陷阱
并非任何分布式应用都适合使用ZooKeeper来构建协调服务,我们根据ZooKeeper提供的文档,给出哪些情况下使用会出现问题,又是如何应对这种问题的。总结如下:
 
丢失ZNode上的变更通知
客户端连接到ZooKeeper Server以后,会维护一个TCP连接。在CONNECTED状态下,客户端设置了某个ZNode的Watch监听器,可以收到来自该节点变更的通知(后续会触发一定的逻辑执行流程)。但是,如果由于网络异常,客户端断开了与ZooKeeper Server的连接,在断开的过程中,是无法收到ZooKeeper在ZNode上发送的节点数据变更通知的。
所以,如果使用ZooKeeper的Watch,必须要寻找保持CONNECTED的Watch,才能保证不会丢失该Watch监控的ZNode上的数据变更通知。
 
无效ZooKeeper集群节点列表
与ZooKeeper集群交互时,一般情况下客户端会持有一个ZooKeeper集群节点的列表,或者列表的子集,那么会存在如下两种情况:
一种情况是,如果客户端持有的列表或者列表子集,其中节点都处于Active状态,能够提供协调服务,那么客户端访问ZooKeeper集群没有任何问题。
另一种情况,客户端持有ZooKeeper集群节点列表或列表子集,如果列表中的某些节点因为故障退出了集群,如果客户端再次连接这一类失效的节点,就无法获取服务。
所以,我们在应用中使用ZooKeeper集群时,一定要明确这一点,或者跳过无效的节点,或者重新寻找有效的节点继续业务处理,或者检查ZooKeeper集群,使整个集群恢复正常。
 
配置导致的性能问题
如果设置Java堆内存(Heap)不合理,会导致ZooKeeper内存不足,会在内存与文件系统之间进行数据交换,导致ZooKeeper的性能极大地下降,从而可能会影响应用程序。
为了避免Swapping问题的出现,主要考虑设置足够的Java堆内存,同时减少被操作系统和Cache使用的内存,尽量避免在内存与文件系统之间发生数据交换,或者可以将交换限制在一定的范围之内。
 
事务日志存储设备性能
ZooKeeper会同步事务到存储设备,如果存储设备不是专用的,而是和其他I/O密集型应用共享同一磁盘,会导致ZooKeeper的效率。因为客户端请求ZNode数据变更而发生的事务,ZooKeeper会在响应之前将事务日志写入存储设备,如果存储设备是专用的,那么整个服务以至外部应用都会获得极大地性能提升。
ZNode存储大量数据导致性能问题
ZooKeeper的设计初衷是,每个ZNode只存放少量的同步数据,如果存储了大量数据,导致ZooKeeper每次节点发生变更时需要将事务写入存储设备,同时还要在集群内部复制传播,这将导致不可避免的延迟和性能问题。
所以,如果需要与大量的数据相关,可以将大量数据存储在其他设备中,而只是在ZooKeeper中存储一个简单的映射,如指针、引用等等。

文章转自:http://www.aboutyun.com/thread-7731-1-1.html

ZooKeeper架构设计及其应用要点的更多相关文章

  1. ZooKeeper架构设计及其应用

    ZooKeeper是一个开源的分布式服务框架,它是Apache Hadoop项目的一个子项目,主要用来解决分布式应用场景中存在的一些问题,如:统一命名服务.状态同步服务.集群管理.分布式应用配置管理等 ...

  2. 聊聊Zookeeper应用场景、架构设计、选主机制

    Zookeeper作为一个分布式协调系统提供了一项基本服务:分布式锁服务,分布式锁是分布式协调技术实现的核心内容.像配置管理.任务分发.组服务.分布式消息队列.分布式通知/协调等,这些应用实际上都是基 ...

  3. Java生鲜电商平台-SpringCloud微服务开发中的数据架构设计实战精讲

    Java生鲜电商平台-SpringCloud微服务开发中的数据架构设计实战精讲 Java生鲜电商平台:   微服务是当前非常流行的技术框架,通过服务的小型化.原子化以及分布式架构的弹性伸缩和高可用性, ...

  4. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  5. 架构设计:一种远程调用服务的设计构思(zookeeper的一种应用实践)

    在深入学习zookeeper我想先给大家介绍一个和zookeeper相关的应用实例,我把这个实例命名为远程调用服务.通过对这种应用实例的描述,我们会对zookeeper应用场景会有深入的了解. 远程调 ...

  6. 【转】Flume(NG)架构设计要点及配置实践

    Flume(NG)架构设计要点及配置实践   Flume NG是一个分布式.可靠.可用的系统,它能够将不同数据源的海量日志数据进行高效收集.聚合.移动,最后存储到一个中心化数据存储系统中.由原来的Fl ...

  7. 架构设计 | 分布式系统调度,Zookeeper集群化管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.框架简介 1.基础简介 Zookeeper基于观察者模式设计的组件,主要应用于分布式系统架构中的,统一命名服务.统一配置管理.统一集群管理 ...

  8. Hadoop YARN架构设计要点

    YARN是开源项目Hadoop的一个资源管理系统,最初设计是为了解决Hadoop中MapReduce计算框架中的资源管理问题,但是现在它已经是一个更加通用的资源管理系统,可以把MapReduce计算框 ...

  9. Dubbo架构设计详解-转

    Dubbo架构设计详解  2013-09-03 21:26:59    Yanjun Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解 ...

随机推荐

  1. MyBatis的一些基本操作

    在学校里只学过一点点的hibernate基础,但是这几天被熊哥叫去写好几个类的接口,所以就去百度了一下mybatis的接口方式怎么使用.1定义接口,并且定义其中要使用到的方法,这里必须注意到的是方法名 ...

  2. 内核移植和文件系统制作(3)Ramdisk简介和常见问题

    一,Ramdisk简介: Ramdisk是一种基于内存的虚拟文件系统(并非一个实际的文件系统),它将一部分固定大小(这个大小在编译内核的make menuconfig时配置)的内存当作硬盘一个分区来使 ...

  3. 实现跨域请求jsonp方式

    原理:http://madong.net.cn/index.php/2012/12/368/ 调用端: $.getJSON("http://192.168.220.85:8001/esb/a ...

  4. asp.net 发送邮件

    asp.net 发送邮件 System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();            msg.To. ...

  5. DWR的Reverse Ajax技术实现

    DWR的逆向ajax其实主要包括两种模式:主动模式和被动模式.其中主动模式包括Polling和Comet两种,被动模式只有Piggyback这一种. 所谓的Piggyback指的是如果后台有什么内容需 ...

  6. jquery重置html form

    很多时候在ajax提交或者对话框隐藏之后,我们希望重置默认值以便下次打开对话框时保持干净. 因为jquery选择器返回的是list,并且没有对此提供reset方法,所以需要针对单个元素进行reset. ...

  7. 从web移动端布局到react native布局

    在web移动端通常会有这样的需求,实现上中下三栏布局(上下导航栏位置固定,中间部分内容超出可滚动),如下图所示: 实现方法如下: HTML结构: <div class='container'&g ...

  8. ArcGIS10.2下调试10.1的程序

    听说:10.2比10.1好,诚然,安装了10.2打开一看是这样的,以为是下载的版本问题,后来才以现是显示设置的问题. 因为,我使用的两个显示器,屏幕有点大,所以,就改成中等了,不然怎么可截取下面的截图 ...

  9. Engine中如何实现先居中显示要素再闪烁

    [解决办法]:需要在要素居中显示之后.闪烁之前执行IScreenDisplay.UpdateWindow强制全刷,如: //居中显示要素 IActiveView actView = axMapCont ...

  10. English Training Material - 02

    OUTSIDE CORRESPONDENCE AND CONTACT   Jared: I'm glad you could come – and you're in for a treat. Thi ...