ZooKeeper程序员指南

时间:2020-05-01 14:41:29   收藏:0   阅读:60

本文内容主要来自官网的翻译https://zookeeper.apache.org/doc/r3.6.1/zookeeperProgrammers.html

ZooKeeper数据模型

ZooKeeper具有层次结构的名称空间,非常类似于分布式文件系统。唯一的区别是,名称空间中的每个节点都可以具有与其关联的数据以及子级。就像拥有一个文件系统一样,该文件系统也允许文件成为目录。到节点的路径始终表示为规范,绝对,斜杠分隔的路径。没有相对参考。遵循以下约束,可以在路径中使用任何unicode字符:

Z节点

ZooKeeper树中的每个节点都称为znode。Znodes维护一个统计信息结构,其中包括用于数据更改和acl更改的版本号。统计信息结构还带有时间戳。版本号以及时间戳允许ZooKeeper验证缓存并协调更新。znode的数据每次更改时,版本号都会增加。

分布式应用程序工程中,节点一词可指代通用主机,服务器,集合体的成员,客户端进程等。在ZooKeeper文档中,znodes指代数据节点。服务器是指组成ZooKeeper服务的机器;仲裁对等体是指组成集合的服务器;客户端是指使用ZooKeeper服务的任何主机或进程。

Znodes是程序员访问的主要实体。它们具有几个特征

手表

客户端可以在znodes上设置监视。对该znode的更改将触发手表,然后清除手表。监视触发时,ZooKeeper向客户端发送通知。

资料存取

原子地读取和写入存储在名称空间中每个znode上的数据。读取将获取与znode关联的所有数据字节,而写入将替换所有数据。每个节点都有一个访问控制列表(ACL),用于限制谁可以执行操作。

ZooKeeper并非设计为通用数据库或大型对象存储。相反,它管理协调数据。这些数据可以采用配置,状态信息,集合点等形式。各种形式的协调数据的共同属性是它们相对较小:以千字节为单位。ZooKeeper客户端和服务器实现具有健全性检查,以确保znode的数据少于1M,但数据应比平均少得多。在相对大的数据量上进行操作将导致某些操作比其他操作花费更多的时间,并且会影响某些操作的延迟,因为需要更多时间才能通过网络将更多数据移动到存储介质上。如果需要大数据存储,则处理此类数据的通常方式是将其存储在大容量存储系统上

临时节点

ZooKeeper还具有短暂节点的概念。只要创建znode的会话处于活动状态,这些znode就存在。会话结束时,将删除znode。由于这种行为,短暂的znode不允许有孩子。可以使用getEphemerals() api 检索会话的临时列表。

getEphemerals()
检索会话为给定路径创建的临时节点列表。如果路径为空,它将列出该会话的所有临时节点。用例 -如果需要收集会话的临时节点列表以进行重复数据输入检查,并且以顺序方式创建节点,因此您不知道重复检查的名称,则为示例用例。在这种情况下,可以使用getEphemerals()api获取会话的节点列表。这可能是服务发现的典型用例。

序列节点-唯一命名

创建znode时,您还可以要求ZooKeeper在路径末尾附加一个单调递增的计数器。该计数器对于父级znode是唯一的。计数器的格式为%010d,即填充10(零)填充的10位数字(以简化排序的方式格式化计数器),即“0000000001“。注意:用于存储下一个序列号的计数器是父节点维护的带符号的int(4字节),当计数器的计数值超过2147483647时,计数器将溢出(导致名称 ”-2147483648“)。

容器节点

在3.6.0中添加
ZooKeeper具有容器znodes的概念。容器znode是特殊用途的znode,可用于诸如领导者,锁等配方。删除容器的最后一个子容器时,容器将成为服务器将来要删除的候选对象。

给定此属性,您应该准备在容器znodes中创建子级时获取KeeperException.NoNodeException。例如,在容器znode内创建子znode时,请始终检查KeeperException.NoNodeException并在发生时重新创建容器znode。

TTL节点

在3.6.0中添加
创建PERSISTENT或PERSISTENT_SEQUENTIAL znode时,可以选择为znode以毫秒为单位设置TTL。如果znode在TTL中未修改且没有子级,则它将成为服务器将来某个时候要删除的候选者。

注意:TTL节点必须通过“系统”属性启用,因为默认情况下它们是禁用的。如果您尝试在没有设置正确的系统属性的情况下创建TTL节点,则服务器将抛出KeeperException.UnimplementedException。

在ZooKeeper中的时间

ZooKeeper通过多种方式跟踪时间:

ZooKeeper统计结构

ZooKeeper中每个znode的Stat结构由以下字段组成:

ZooKeeper会话

ZooKeeper客户端通过使用语言绑定创建服务的句柄来与ZooKeeper服务建立会话。创建句柄之后,该句柄将开始处于CONNECTING状态,并且客户端库尝试连接到组成ZooKeeper服务的服务器之一,然后将其切换为CONNECTED状态。在正常操作期间,客户端句柄将处于这两种状态之一。如果发生不可恢复的错误,例如会话到期或身份验证失败,或者如果应用程序显式关闭了句柄,则该句柄将移至CLOSED状态。

创建客户端会话,应用程序代码必须提供一个连接字符串,其中包含用逗号分隔的host:port对列表,每个对与ZooKeeper服务器相对应(例如“ 127.0.0.1:4545”或“ 127.0.0.1:3000,127.0.0.1” :3001,127.0.0.1:3002“)。ZooKeeper客户端库将选择一个任意服务器并尝试连接到该服务器。如果此连接失败,或者客户端由于任何原因与服务器断开连接,则客户端将自动尝试列表中的下一个服务器,直到(重新)建立连接为止。

在3.2.0中添加:也可以将可选的“ chroot”后缀附加到连接字符串中。这将在解释相对于该根目录的所有路径时运行客户端命令(类似于unix chroot命令)。如果使用该示例,则该示例将类似于:“ 127.0.0.1:4545/app/a”或“ 127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a”,该客户端将以该目录为根“ / app / a”,所有路径都相对于此根目录-即,获取/设置/等...“ / foo / bar”将导致操作在“ / app / a / foo / bar”上运行(来自服务器角度)。此功能在多租户环境中特别有用,在该环境中,特定ZooKeeper服务的每个用户都可以植根于不同的用户。这使重用变得更加简单,因为每个用户都可以将自己的应用程序编码为“ /”,

当客户端获得ZooKeeper服务的句柄时,ZooKeeper会创建一个分配给客户端的ZooKeeper会话(表示为64位数字)。如果客户端连接到其他ZooKeeper服务器,它将发送会话ID作为连接握手的一部分。为了安全起见,服务器会为任何ZooKeeper服务器都可以验证的会话ID创建一个密码。当客户端建立会话时,该密码将以会话ID发送给客户端。每当客户端与新服务器重新建立会话时,客户端都会使用会话ID发送此密码。

创建一个ZooKeeper会话的ZooKeeper客户端库调用的参数之一是会话超时(以毫秒为单位)。客户端发送请求的超时,服务器以其可以给客户端的超时作为响应。当前的实现要求超时至少是tickTime的2倍(在服务器配置中设置),最大是tickTime的20倍。ZooKeeper客户端API允许访问协商的超时。

当客户端(会话)从ZK服务群集中进行分区时,它将开始搜索在会话创建过程中指定的服务器列表。最终,当客户端与至少一台服务器之间的连接重新建立时,会话将再次转换为“已连接”状态(如果在会话超时值内重新连接),或者将转换为“已过期”状态(如果会话超时后重新连接)。不建议创建一个新的会话对象(在c绑定中一个新的ZooKeeper.class或zookeeper句柄)来断开连接。ZK客户端库将为您处理重新连接。特别是,我们在客户端库中内置了启发式方法,以处理“群效应”等问题。

会话到期由ZooKeeper群集本身管理,而不是由客户端管理。当ZK客户端与群集建立会话时,它将提供上面详述的“超时”值。群集使用此值来确定客户端会话何时过期。当群集在指定的会话超时时间内未收到客户端的消息(即无心跳)时,就会发生过期。在会话期满时,群集将删除该会话拥有的任何/所有临时节点,并立即将任何更改通知所有/所有连接的客户端(任何监视这些znode的人)。此时,过期会话的客户端仍与群集断开连接,除非/除非它能够重新建立与群集的连接,否则会话过期将不会收到通知。

过期会话的观察者可以看到过期会话的状态转换示例:

ZooKeeper会话建立调用的另一个参数是默认观察者。当客户端中发生任何状态更改时,将向观察者通知。例如,如果客户端失去与服务器的连接,则将通知客户端,或者客户端的会话到期,等等。。。此观察者应考虑将初始状态断开(即,在任何状态更改事件之前,将事件发送给观察者)。客户端库)。在新连接的情况下,发送给观察者的第一个事件通常是会话连接事件。

客户端发送的请求使会话保持活动状态。如果会话空闲一段时间会使会话超时,则客户端将发送PING请求以使会话保持活动状态。此PING请求不仅允许ZooKeeper服务器知道客户端仍处于活动状态,而且还允许客户端验证其与ZooKeeper服务器的连接仍处于活动状态。PING的时间足够保守,以确保有合理的时间来检测死连接并重新连接到新服务器。

成功建立(连接)到服务器的连接后,基本上有两种情况,当同步或同步时,客户端库会生成连接丢失(c绑定中的结果代码,Java中的异常-有关绑定的详细信息,请参阅API文档)。执行异步操作,并且保留以下条件之一:

在3.2.0中添加-SessionMovedException。客户端通常看不到一个内部异常,称为SessionMovedException。发生此异常的原因是,在连接上收到了针对已在其他服务器上重新建立的会话的请求。导致此错误的正常原因是客户端向服务器发送请求,但是网络数据包被延迟,因此客户端超时并连接到新服务器。当延迟的数据包到达第一台服务器时,旧服务器将检测到会话已移动,并关闭客户端连接。客户端通常不会看到此错误,因为它们不会从那些旧连接中读取。(通常会关闭旧的连接。)可以看到这种情况的一种情况是,两个客户端尝试使用保存的会话ID和密码来重新建立相同的连接。

更新服务器列表。我们允许客户端通过提供一个新的以逗号分隔的host:port对列表来更新连接字符串,每个对对应于ZooKeeper服务器。该函数调用概率负载平衡算法,该算法可能导致客户端从其当前主机断开连接,以期在新列表中实现每个服务器的预期统一连接数。如果客户端连接的当前主机不在新列表中,则此调用将始终导致连接断开。否则,将基于服务器数量是增加还是减少以及增加多少来做出决定。

例如,如果以前的连接字符串包含3个主机,而现在列表中包含这3个主机和2个其他主机,则连接到3个主机中的每一个的40%的客户端将移动到其中一个新主机,以平衡负载。该算法将导致客户端以0.4的概率断开其与之连接的当前主机的连接,在这种情况下,将导致客户端连接至随机选择的2个新主机之一。

另一个示例-假设我们有5台主机,现在更新列表以删除其中2台主机,连接到其余3台主机的客户端将保持连接状态,而连接到2台删除主机的所有客户端将需要移动到其中一台3个主机,随机选择。如果断开连接,客户端将进入一种特殊模式,在该模式下,客户端将选择一个新服务器使用概率算法进行连接,而不仅仅是轮询。

在第一个示例中,每个客户端决定以0.4的概率断开连接,但是一旦做出决定,它将尝试连接到随机的新服务器,并且只有当它无法连接到任何新服务器时,它才会尝试连接到旧服务器。那些。找到服务器或尝试新列表中的所有服务器并无法连接后,客户端将返回到正常操作模式,在该模式下,客户端从connectString中选择任意服务器并尝试连接至该服务器。如果失败,它将继续循环尝试其他随机服务器。(请参见上文最初用于选择服务器的算法)

当地会议。在3.5.0中添加,主要由ZOOKEEPER-1147实现。

背景:在ZooKeeper中创建和关闭会话非常昂贵,因为它们需要仲裁确认,当需要处理数千个客户端连接时,它们成为ZooKeeper集成的瓶颈。因此,在3.5.0之后,我们引入了一种新的会话类型:本地会话,它不具有普通(全局)会话的全部功能,因此可以通过打开localSessionsEnabled来使用此功能。

当localSessionsUpgradingEnabled禁用时:

启用localSessionsUpgradingEnabled时:

+----------------+ +--------------------+ +---------------------+ | | --> | | ----> | LocalSessionTracker | | SessionTracker | | SessionTrackerImpl | +---------------------+ | | | | +-----------------------+ | | | | +-------------------------> | LeaderSessionTracker | +----------------+ +--------------------+ | +-----------------------+ | | | | | | | +---------------------------+ +---------> | | | UpgradeableSessionTracker | | | | | ------------------------+ +---------------------------+ | | | v +-----------------------+ | LearnerSessionTracker | +-----------------------+

问答环节

ZooKeeper Watches

ZooKeeper中的所有读取操作-getData(),getChildren()和exist() -都可以选择将Watches设置为副作用。这是ZooKeeper对手表的定义:Watches事件是一次触发,发??送给设置Watches的客户端,该事件在设置Watches的数据更改时发生。在Watches的定义中,需要考虑三个关键点:

Watches在客户端连接到的ZooKeeper服务器上本地维护。这使watches的重量可以轻巧地设置,维护和调度。当客户端连接到新服务器时,将监视所有会话事件。与服务器断开连接时,不会收到watches。当客户端重新连接时,任何以前注册的watches将被重新注册并在需要时触发。通常,所有这些都是透明发生的。在某些情况下,可能会丢失监视:如果在断开连接的情况下创建并删除了znode,则会丢失尚未创建的znode的监视。

3.6.0中的新增功能:客户端还可以在znode上设置永久性的递归监视,这些监视在触发时不会删除,并且会以递归方式触发已注册znode以及所有子znode的更改。

Watches的语义

我们可以通过三个调用来读取ZooKeeper状态的调用来设置Watches:exist,getData和getChildren。以下列表详细说明了手表可以触发的事件以及启用它们的调用:

持久递归Watches

3.6.0中的新增功能:上述标准Watches现在有所变化,您可以设置不会触发时被移除的Watches。此外,这些监视会触发事件类型NodeCreated,NodeDeleted和NodeDataChanged,并且(可选)从注册该监视的znode处递归地为所有znode递归触发。请注意,持久性递归监视不会触发NodeChildrenChanged事件,因为这将是多余的。

使用方法addWatch()设置持久Watches。触发语义和保证(一次性触发除外)与标准Watches表相同。关于事件的唯一例外是,递归持久性观察者永远不会触发子更改事件,因为它们是多余的。使用具有观察者类型WatcherType.Any的removeWatches()可以删除持久性观察。

删除Watches

我们可以通过调用removeWatches来删除在znode上注册的Watches。另外,即使没有服务器连接,ZooKeeper客户端也可以通过将本地标志设置为true来在本地删除Watches。以下列表详细说明了成功删除Watches后将触发的事件。

ZooKeeper对Watches的保证

关于Watches,ZooKeeper保持以下保证:

Watches须知

使用ACL的ZooKeeper访问控制

ZooKeeper使用ACL来控制对其znode(ZooKeeper数据树的数据节点)的访问。ACL实现与UNIX文件访问权限非常相似:它使用权限位来允许/禁止对节点及其所作用域的各种操作。与标准UNIX权限不同,ZooKeeper节点不受用户(文件所有者),组和世界(其他)的三个标准范围的限制。ZooKeeper没有znode所有者的概念。而是,ACL指定一组ID和与这些ID关联的权限。

还请注意,ACL仅与特定的znode有关。特别是它不适用于child。例如,如果/ app仅可被ip:172.16.16.1读取,并且/ app / status是世界可读的,则任何人都可以读取/ app / status;ACL不是递归的。

ZooKeeper支持可插入身份验证方案。使用格式scheme:expression指定ID ,其中scheme是ID对应的身份验证方案。有效表达式集由方案定义。例如,ip:172.16.16.1是使用ip方案的地址为172.16.16.1的主机的ID ,而digest:bob:password是使用摘要方案的名称为bob的用户的ID 。

当客户端连接到ZooKeeper并对其进行身份验证时,ZooKeeper会将与客户端相对应的所有ID与客户端连接相关联。当客户端尝试访问节点时,将根据znodes的ACL检查这些ID。ACL由(scheme:expression,perms)对组成。表达式的格式特定于该方案。例如,该对(ip:19.22.0.0/16,READ)为IP地址以19.22开头的任何客户端提供READ权限。

ACL权限

ZooKeeper支持以下权限:

在CREATE和DELETE权限已被打破了出来写的更细粒度的访问控制权限。对于案件CREATE和DELETE有以下几方面:

您希望A能够在ZooKeeper节点上进行设置,但不能创建或删除子级。

创建不删除:客户端通过在父目录中创建ZooKeeper节点来创建请求。您希望所有客户端都能添加,但是只有请求处理器可以删除。(这有点像文件的APPEND权限。)

另外,由于ZooKeeper没有文件所有者的概念,因此具有ADMIN权限。从某种意义上说,ADMIN权限将实体指定为所有者。ZooKeeper不支持LOOKUP许可权(对目录执行许可权,即使您无法列出目录也可以使您进行LOOKUP许可)。每个人都隐式具有LOOKUP权限。这使您可以统计节点,但仅此而已。(问题是,如果要在不存在的节点上调用zoo_exists(),则没有检查权限。)

就ACL而言,ADMIN权限也具有特殊作用:为了检索znode用户的ACL,必须具有READ或ADMIN权限,但没有ADMIN权限,摘要哈希值将被屏蔽。

一致性保证

ZooKeeper是一项高性能,可扩展的服务。读取和写入操作都被设计为快速的,尽管读取比写入快。原因是在读取的情况下,ZooKeeper可以提供较旧的数据,这又是由于ZooKeeper的一致性保证:

使用这些一致性保证很容易仅在ZooKeeper客户端上构建高层功能,例如领导者选举,障碍,队列和读/写可撤消锁(ZooKeeper不需要添加)。

原文:https://www.cnblogs.com/farmersun/p/12813442.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!