【Free Style】ZooKeeper总结材料分享(一)

举报
pappy 发表于 2017/11/03 18:36:46 2017/11/03
【摘要】 1 概述ZooKeeper是一个开源的的分布式服务框架,它是Apache Hadoop项目的一个子项目,主要用来解决分布式应用场景中存在的一些问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置管理等,它支持Standalone模式和分布式模式,在分布式模式下,能够为分布式应用提供高性能和可靠地协调服务,而且使用ZooKeeper可以大大简化分布式协调服务的实现,为开发分布式应

1      概述

ZooKeeper是一个开源的的分布式服务框架,它是Apache Hadoop项目的一个子项目,主要用来解决分布式应用场景中存在的一些问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置管理等,它支持Standalone模式和分布式模式,在分布式模式下,能够为分布式应用提供高性能和可靠地协调服务,而且使用ZooKeeper可以大大简化分布式协调服务的实现,为开发分布式应用极大地降低了成本。

1.1         总体架构

image.png

ZooKeeper集群由一组Server节点组成,这一组Server节点中存在一个角色为Leader的节点,其他节点都为Follower。当客户端Client连接到ZooKeeper集群,并且执行写请求时,这些请求会被发送到Leader节点上,然后Leader节点上数据变更会同步到集群中其他的Follower节点。
    Leader
节点在接收到数据变更请求后,首先将变更写入本地磁盘,以作恢复之用。当所有的写请求持久化到磁盘以后,才会将变更应用到内存中。
    ZooKeeper
使用了一种自定义的原子消息协议,在消息层的这种原子特性,保证了整个协调系统中的节点数据或状态的一致性。Follower基于这种消息协议能够保证本地的ZooKeeper数据与Leader节点同步,然后基于本地的存储来独立地对外提供服务。
    
当一个Leader节点发生故障失效时,失败故障是快速响应的,消息层负责重新选择一个Leader,继续作为协调服务集群的中心,处理客户端写请求,并将ZooKeeper协调系统的数据变更同步(广播)到其他的Follower节点。

1.2         常见概念

1.  ZooKeeper集群中,每个节点共有3种角色和4种状态:

l  角色: leaderfollowerobserver

l  状态: leadingfollowingobservinglooking

observerobserving3.3版本之后引入的,他们的引入是为了解决zookeeper集群扩大后,由于网络可靠性下降可能导致的拜占庭将军问题。observer的行为与follower差不多,只是他们不参加选举和投票,而仅仅接受(observing)选举和投票的结果。


2.  节点类型:

l  Persistent Nodes 永久有效的节点,除非client显示的删除,否则一直存在

l  Ephemeral Nodes:临时节点,仅在创建该节点client保持连接期间有效,一旦连接丢失,zookeeper会自动删除该节点

l  Sequence Nodes:顺序节点,client申请创建该节点时,ZooKeeper会自动在节点路径末尾添加递增,这种类型是实现分布式锁,分布式queue等特殊功能的关键


3.  WatchEvent类型

l  KeeperState DisconnectedSyncConnectedExpired

l  EventTypeNoneNodeCreatedNodeDeletedNodeDataChangedNodeChildrenChanged




1.3         设计要点

ZooKeeper的设计初衷

l  简单

分布式应用中的各个进程可以通过ZooKeeper的命名空间(Namespace)来进行协调,这个命名空间是共享的、具有层次结构的,更重要的是它的结构足够简单,像我们平时接触到的文件系统的目录结构一样容易理解,如图所示:

image.png

ZooKeeper中每个命名空间(Namespace)被称为ZNode,你可以这样理解,每个ZNode包含一个路径和与之相关的元数据,以及继承自该节点的孩子列表。与传统文件系统不同的是,ZooKeeper中的数据保存在内存中,实现了分布式同步服务的高吞吐和低延迟。
    
在上图示例的ZooKeeper的数据模型中,有如下要点:

1) 每个节点(ZNode)中存储的是同步相关的数据(这是ZooKeeper设计的初衷,数据量很小,大概BKB量级),例如状态信息、配置内容、位置信息等

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

3)每个ZNode都有一个ACL,用来限制是否可以访问该ZNode

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

5)客户端可以在一个ZNode上设置一个监视器(Watch),如果该ZNode数据发生变更,ZooKeeper会通知客户端,从而触发监视器中实现的逻辑的执行

6)每个客户端与ZooKeeper连接,便建立了一次会话(Session),会话过程中,可能发生CONNECTINGCONNECTEDCLOSED三种状态

7ZooKeeper支持临时节点(Ephemeral Nodes)的概念,它是与ZooKeeper中的会话(Session)相关的,如果连接断开,则该节点被删除


l  冗余

ZooKeeper被设计为复制集群架构,每个节点的数据都可以在集群中复制传播,使集群中的每个节点数据同步一致,从而达到服务的可靠性和可用性。前面说到,ZooKeeper将数据放在内存中来提高性能,为了避免发生单点故障(SPOF),支持数据的复制来达到冗余存储,这是必不可少的。


l  有序

ZooKeeper使用时间戳来记录导致状态变更的事务性操作,也就是说,一组事务通过时间戳来保证有序性。基于这一特性。ZooKeeper可以实现更加高级的抽象操作,如同步等。


l  快速

ZooKeeper包括读写两种操作,基于ZooKeeper的分布式应用,如果是读多写少的应用场景(读写比例大约是10:1),那么读性能更能够体现出高效。


1.4         数据模型

ZooKeeper有一个分层的命名空间,结构类似文件系统的目录结构,非常简单而直观。其中,ZNode是最重要的概念,前面我们已经描述过。另外,有ZNode有关的还包括WatchesACL、临时节点、序列节点(Sequence Node)。

l  ZNODE

ZooKeeper中使用ZxidZooKeeper Transaction Id)来表示每次节点数据变更,一个Zxid与一个时间戳对应,所以多个不同的变更对应的事务是有序的。下面是ZNode的组成结构,引用文档如下所示:

o    czxid – The zxid of the change that caused this znode to be created.

o    mzxid – The zxid of the change that last modified this znode.

o    ctime – The time in milliseconds from epoch when this znode was created.

o    mtime – The time in milliseconds from epoch when this znode was last modified.

o    version – The number of changes to the data of this znode.

o    cversion – The number of changes to the children of this znode.

o    aversion – The number of changes to the ACL of this znode.

o    ephemeralOwner – The session id of the owner of this znode if the znode is an ephemeral node. If it is not an ephemeral node, it will be zero.

o    dataLength – The length of the data field of this znode.

o    numChildren – The number of children of this znode.

1znode中的数据可以有多个版本,在查询该znode数据时就需要带上版本信息。如:set path version / delete path version

2znode可以是临时znode,由create -e 生成的节点,一旦创建这个znodeclientserver断开连接,该znode将被自动删除。

clientserver之间通过heartbeat来确认连接正常,这种状态称之为session,断开连接后session失效。

3)临时znode不能有子znode

4znode可以自动编号,由create -s 生成的节点,例如在 create -s /app/node 已存在时,将会生成/app/node00***001节点。

5znode可以被监控,该目录下某些信息的修改,例如节点数据、子节点变化等,可以主动通知监控注册的client。事实上,通过这个特性,可以完成许多重要应用,例如配置管理、信息同步、分布式锁等等。


l  Watches (监视)

ZooKeeper中的Watch是只能触发一次(触发的同时会删除这个监视)。也就是说,如果客户端在指定的ZNode设置了Watch,如果该ZNode数据发生变更,ZooKeeper会发送一个变更通知给客户端,同时触发设置的Watch事件。如果ZNode数据又发生了变更,客户端在收到第一次通知后没有重新设置该ZNodeWatch,则ZooKeeper就不会发送一个变更通知给客户端。
    ZooKeeper
异步通知设置Watch的客户端。但是ZooKeeper能够保证在ZNode的变更生效之后才会异步地通知客户端,然后客户端才能够看到ZNode的数据变更。由于网络延迟,多个客户端可能会在不同的时间看到ZNode数据的变更,但是看到变更的顺序是能够保证有序一致的。
    ZNode
可以设置两类Watch,一个是Data Watches(该ZNode的数据变更导致触发Watch事件),另一个是Child Watches(该ZNode的孩子节点发生变更导致触发Watch事件)。

调用getData()exists() 方法可以设置Data Watches

调用getChildren()方法可以设置Child Watches

调用setData()方法触发在该ZNode的注册的Data Watches

调用create()方法创建一个ZNode,将触发该ZNodeData Watches

调用create()方法创建ZNode的孩子节点,则触发ZNodeChild Watches

调用delete()方法删除ZNode,则同时触发Data WatchesChild Watches,如果该被删除的ZNode还有父节点,则父节点触发一个Child Watches
    
另外,如果客户端与ZooKeeper Server断开连接,客户端就无法触发Watches,除非再次与ZooKeeper Server建立连接。


l  Sequence Nodes (序列节点)

在创建ZNode的时候,可以请求ZooKeeper生成序列,以路径名为前缀,计数器紧接在路径名后面,例如,会生成类似如下形式序列:

image.png

对于ZNode的父节点来说,序列中的每个计数器字符串都是唯一的,最大值为2147483647 0x7fff ffff


l  ACLs(访问控制列表)

ACL可以控制访问ZooKeeper的节点,只能应用于特定的ZNode上,而不能应用于该ZNode的所有孩子节点上。它主要有如下五种权限:

o    CREATE 允许创建Child Nodes

o    READ 允许获取ZNode的数据,以及该节点的孩子列表

o    WRITE 可以修改ZNode的数据

o    DELETE 可以删除一个孩子节点

o    ADMIN 可以设置权限

ZooKeeper内置了4种方式实现ACL

o    world 一个单独的ID,表示任何人都可以访问

o    auth 不使用ID,只有认证的用户可以访问

o    digest 使用username:password生成MD5哈希值作为认证ID

o    ip 使用客户端主机IP地址来进行认证

l  ZooKeeeper Session

当客户端连接到ZooKeeper集群时,建立了会话。会话过程中的状态变迁,如图所示:

image.png

建立连接过程中,会话状态为CONNECTING;当连接建立成功后,会话状态变为CONNECTED。会话过程中,如果正常的话,会话的状态只能是CONNECTINGCONNECTED二者之一。如果在会话过程中连接断开,则变为CLOSED状态。


1.5          应用陷阱

并非任何分布式应用都适合使用ZooKeeper来构建协调服务,我们根据ZooKeeper提供的文档,给出哪些情况下使用会出现问题,又是如何应对这种问题的。总结如下:

1.    丢失ZNode上的变更通知

客户端连接到ZooKeeper Server以后,会维护一个TCP连接。在CONNECTED状态下,客户端设置了某个ZNodeWatch监听器,可以收到来自该节点变更的通知(后续会触发一定的逻辑执行流程)。但是,如果由于网络异常,客户端断开了与ZooKeeper Server的连接,在断开的过程中,是无法收到ZooKeeperZNode上发送的节点数据变更通知的。
所以,如果使用ZooKeeperWatch,必须要寻找保持CONNECTEDWatch,才能保证不会丢失该Watch监控的ZNode上的数据变更通知。

2.    无效ZooKeeper集群节点列表

ZooKeeper群 交 互时,一般情况下客户端会持有一个ZooKeeper集群节点的列表,或者列表的子集,那么会存在如下两种情况:
一种情况是,如果客户端持有的列表或者列表子集,其中节点都处于Active状态,能够提供协调服务,那么客户端访问ZooKeeper集群没有任何问题。
另一种情况,客户端持有ZooKeeper集群节点列表或列表子集,如果列表中的某些节点因为故障退出了集群,如果客户端再次连接这一类失效的节点,就无法获取服务。
所以,我们在应用中使用ZooKeeper集群时,一定要明确这一点,或者跳过无效的节点,或者重新寻找有效的节点继续业务处理,或者检查ZooKeeper集群,使整个集群恢复正常。

3.    配置导致的性能问题

如果设置Java堆内存(Heap)不合理,会导致ZooKeeper内存不足,会在内存与文件系统之间进行数据交换,导致ZooKeeper的性能极大地下降,从而可能会影响应用程序。
为了避免Swapping问题的出现,主要考虑设置足够的Java堆内存,同时减少被 操 作系统和Cache使用的内存,尽量避免在内存与文件系统之间发生数据交换,或者可以将交换限制在一定的范围之内。

4.    事务日志存储设备性能

ZooKeeper会同步事务到存储设备,如果存储设备不是专用的,而是和其他I/O密集型应用共享同一磁盘,会降低ZooKeeper的效率。因为客户端请求ZNode数据变更而发生的事务,ZooKeeper会在响应之前将事务日志写入存储设备,如果存储设备是专用的,那么整个服务以至外部应用都会获得极大地性能提升。

5.    ZNode存储大量数据导致性能问题

ZooKeeper的设计初衷是,每个ZNode只存放少量的同步数据,如果存储了大量数据,导致ZooKeeper每次节点发生变更时需要将事务写入存储设备,同时还要在集群内部复制传播,这将导致不可避免的延迟和性能问题。
所以,如果需要与大量的数据相关,可以将大量数据存储在其他设备中,而只是在ZooKeeper中存储一个简单的映射,如指针、引用等等。

1.6         API接口

这里只描述具体的功能接口

l  create

创建一个节点(node

l  delete

删除一个节点

l  exists

测试一个节点是否存在

l  get data

从一个节点中读数据

l  set data

向一个节点写数据

l  get children

获取子节点列表

l  sync

等待数据的同步

1.7         集群的组件

ZooKeeper集群当中,集群中的服务器角色有两种LeaderLearnerLearner角色又分为ObserverFollower,具体功能如下:

1.领导者(leader),负责进行投票的发起和决议,更新系统状态

2.学习者(learner),包括跟随者(follower)和观察者(observer),

3.follower用于接受客户端请求并向客户端返回结果,在选主过程中参与投票

4.Observer可以接受客户端请求,将写请求转发给leader,但observer不参加投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度。

5. 客户端(client),请求发起方


image.png

ZooKeeper的组件图中给出了ZooKeeper服务的高层次的组件。除了请求处理器(requestprocessor)外,构成ZooKeeper服务的每个服务器都有一个备份。复制的数据库(replicateddatabase)是一个内存数据库,包含整个数据树。为了可恢复,更新会被log到磁盘,并且在更新这个内存数据库之前,先序列化到磁盘。

每个ZooKeeper都为客户端提供服务。客户端只连接到一个服务器,并提交请求。读请求直接由本地的复制数据库提供数据。对服务状态进行修改的请求、写请求通过一个约定的协议进行通讯。

作为这个协议的一部分,所有的写请求都被传送到leader服务器,而其他的服务器,叫做followersfollowerleader接收信息修改的提议,并同意进行。当leader发生故障时,协议的信息层(messaginglayer)关注leader的替换,并同步到所有的follower

ZooKeeper采用一个自定义的信息原子操作协议,由于信息层的操作是原子性的,ZooKeeper能保证本地的复制数据库不会产生不一致。当leader接收到一个写请求,它计算出写之后系统的状态,把它变成一个事务。


1.8         其它用途

ZooKeeper本身的接口很简单,用户可以实现高层的抽象操作。如同步原语,group membershipownership等。


1.9         性能

ZooKeeper适合于读比写多的场景

image.png

上图展示横轴是读的占比,纵轴是吞吐率。

测试版本为3.2,硬件环境为双核 2G Xeon,两个15000转的硬盘

1.10     可靠性

image.png

上图ZooKeeper7台机器组成,并故意注入两个失败。横轴是实间线,纵轴是吞吐率(写占比为30%)。

一般选举一个新的leader大概需要200ms左右的时间。

1.11     业界使用公司

官网上主推雅虎。


因字数限制,下篇接着分享~~~

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。