ZooKeeper程序员指南
本文内容主要来自官网的翻译https://zookeeper.apache.org/doc/r3.6.1/zookeeperProgrammers.html
ZooKeeper数据模型
ZooKeeper具有层次结构的名称空间,非常类似于分布式文件系统。唯一的区别是,名称空间中的每个节点都可以具有与其关联的数据以及子级。就像拥有一个文件系统一样,该文件系统也允许文件成为目录。到节点的路径始终表示为规范,绝对,斜杠分隔的路径。没有相对参考。遵循以下约束,可以在路径中使用任何unicode字符:
- 空字符(\ u0000)不能是路径名的一部分。(这会导致C绑定出现问题。)
- 以下字符不能使用,因为它们不能很好地显示或以混乱的方式呈现:\ u0001-\ u001F和\ u007F
- \ u009F。
- 不允许使用以下字符:\ ud800-uF8FF,\ uFFF0-uFFFF。
- “。” 字符可以用作其他名称的一部分,但“。” 和“ ..”不能单独用于指示路径上的节点,因为ZooKeeper不使用相对路径。以下内容将无效:“ / a / b /./ c”或“ /a/b/../c”。
- 令牌“ zookeeper”被保留。
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通过多种方式跟踪时间:
- Zxid对ZooKeeper状态的每次更改都会以zxid(ZooKeeper交易ID)的形式接收戳记。这将向ZooKeeper公开所有更改的总顺序。每个更改将具有唯一的zxid,并且如果zxid1小于zxid2,则zxid1在zxid2之前发生。
- 版本号对节点的每次更改都会导致该节点的版本号之一增加。这三个版本号分别是版本(znode的数据更改数量),cversion(znode的子级更改数量)和aversion(znode的ACL更改数量)。
- 如果客户端请求的会话超时时间小于最小会话超时时间,则服务器将告知客户端该会话超时时间实际上是最小会话超时时间。
8 实时 ZooKeeper完全不使用实时时间或时钟时间,只是在创建znode和修改znode时将时间戳记放入stat结构中。
ZooKeeper统计结构
ZooKeeper中每个znode的Stat结构由以下字段组成:
- czxid导致创建此znode的更改的zxid。
- mzxid上次修改此znode的更改的zxid。
- pzxid上次修改此znode子级的更改的zxid。
- ctime创建此znode时从纪元开始的时间(以毫秒为单位)。
- mtime上次修改此znode的时间,以纪元为单位的时间。
- 版本此znode的数据更改数。
- cversion此znode的子级更改的数量。
- aversion此znode的ACL的更改数。
- ephemeralOwner如果znode是一个临时节点,则此znode的所有者的会话ID。如果它不是临时节点,则它将为零。
- dataLength此znode的数据字段的长度。
- numChildren此znode的子级数。
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的人)。此时,过期会话的客户端仍与群集断开连接,除非/除非它能够重新建立与群集的连接,否则会话过期将不会收到通知。
过期会话的观察者可以看到过期会话的状态转换示例:
- connected:会话已建立,客户端正在与集群通信(客户端/服务器通信正常运行)
- ....客户端已从群集中分区
- connected:客户端失去与群集的连接
- .... time elapses,在“超时”时间段之后,群集使会话过期,由于客户端与群集断开连接,因此客户端看不到任何内容
- .... time elapses,客户端重新获得与群集的网络级别连接
- 'expired':最终客户端重新连接到集群,然后通知其到期
ZooKeeper会话建立调用的另一个参数是默认观察者。当客户端中发生任何状态更改时,将向观察者通知。例如,如果客户端失去与服务器的连接,则将通知客户端,或者客户端的会话到期,等等。。。此观察者应考虑将初始状态断开(即,在任何状态更改事件之前,将事件发送给观察者)。客户端库)。在新连接的情况下,发送给观察者的第一个事件通常是会话连接事件。
客户端发送的请求使会话保持活动状态。如果会话空闲一段时间会使会话超时,则客户端将发送PING请求以使会话保持活动状态。此PING请求不仅允许ZooKeeper服务器知道客户端仍处于活动状态,而且还允许客户端验证其与ZooKeeper服务器的连接仍处于活动状态。PING的时间足够保守,以确保有合理的时间来检测死连接并重新连接到新服务器。
成功建立(连接)到服务器的连接后,基本上有两种情况,当同步或同步时,客户端库会生成连接丢失(c绑定中的结果代码,Java中的异常-有关绑定的详细信息,请参阅API文档)。执行异步操作,并且保留以下条件之一:
- 应用程序在不再有效/有效的会话上调用操作
- 当对该服务器有待处理的操作时,即存在一个待处理的异步调用,ZooKeeper客户端将从服务器断开连接。
在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禁用时:
-
本地会话无法创建临时节点
-
一旦本地会话丢失,用户将无法使用会话ID /密码重新建立会话,该会话及其监视永久消失。注意:丢失tcp连接并不一定意味着会话已丢失。如果可以在会话超时之前与同一zk服务器重新建立连接,则客户端可以继续(它根本无法移动到另一台服务器)。
-
当本地会话连接时,会话信息仅在与其连接的Zookeeper服务器上维护。领导者不知道此类会话的创建,并且没有状态写入磁盘。
-
ping,到期和其他会话状态维护由当前会话连接到的服务器处理。
启用localSessionsUpgradingEnabled时:
-
本地会话可以自动升级到全局会话。
-
创建新会话后,它将被本地保存在已包装的LocalSessionTracker中。随后可以根据需要将其升级到全局会话(例如,创建临时节点)。如果请求升级,则将会话从本地集合中删除,同时保留相同的会话ID。
-
当前,仅操作:创建临时节点需要将会话从本地升级到全局。原因是临时节点的创建在很大程度上取决于全局会话。如果本地会话可以在不升级到全局会话的情况下创建临时节点,则将导致不同节点之间的数据不一致。领导者还需要了解会话的生命周期,以清理关闭/到期的临时节点。这需要全局会话,因为本地会话绑定到其特定服务器。
-
会话在升级过程中既可以是本地会话,也可以是全局会话,但是不能由两个线程同时调用升级操作。
-
ZooKeeperServer(独立)使用SessionTrackerImpl;LeaderZookeeper使用LeaderSessionTracker,后者保存SessionTrackerImpl(全局)和LocalSessionTracker(如果启用);FollowerZooKeeperServer和ObserverZooKeeperServer使用LearnerSessionTracker持有LocalSessionTracker。关于会话的UML类图:
+----------------+ +--------------------+ +---------------------+ | | --> | | ----> | LocalSessionTracker | | SessionTracker | | SessionTrackerImpl | +---------------------+ | | | | +-----------------------+ | | | | +-------------------------> | LeaderSessionTracker | +----------------+ +--------------------+ | +-----------------------+ | | | | | | | +---------------------------+ +---------> | | | UpgradeableSessionTracker | | | | | ------------------------+ +---------------------------+ | | | v +-----------------------+ | LearnerSessionTracker | +-----------------------+
问答环节
-
使用config选项禁用本地会话升级的原因是什么?
在想要处理大量客户端的大型部署中,我们知道客户端通过观察者连接,而观察者应该仅是本地会话。因此,这更像是防止有人意外创建大量临时节点和全局会话的防护措施。 -
会话何时创建?
在当前实现中,它将在处理ConnectRequest以及createSession请求到达FinalRequestProcessor时尝试创建本地会话。 -
如果为会话创建的会话是在服务器A上发送的,并且客户端断开与其他服务器B的连接,而服务器B最终又再次发送了该消息,然后断开并重新连接回服务器A,该怎么办?
当客户端重新连接到B时,其sessionId将不在B的本地会话跟踪器中。因此,B将发送验证数据包。如果在验证数据包到达之前提交了由A发出的CreateSession,则客户端将可以连接。否则,客户端将使会话过期,因为仲裁尚未知道该会话。如果客户端也尝试再次连接回A,则该会话已从本地会话跟踪器中删除。因此,A将需要将验证数据包发送给领导者。根据请求的时间,结果应与B相同。
ZooKeeper Watches
ZooKeeper中的所有读取操作-getData(),getChildren()和exist() -都可以选择将Watches设置为副作用。这是ZooKeeper对手表的定义:Watches事件是一次触发,发送给设置Watches的客户端,该事件在设置Watches的数据更改时发生。在Watches的定义中,需要考虑三个关键点:
-
一次性触发器数据更改后,一个监视事件将发送到客户端。例如,如果客户端执行getData(“ / znode1”,true),然后/ znode1的数据被更改或删除,则客户端将获得/ znode1的监视事件。如果/ znode1再次更改,则除非客户端进行了另一次读取来设置新的监视,否则不会发送任何监视事件。
-
发送给客户端这意味着事件正在传递给客户端,但是可能未成功到达更改操作的返回码到达发起更改的客户端之前,该事件尚未到达客户端。手表被异步发送给观察者。ZooKeeper提供了订购保证:客户端在第一次看到监视事件之前,将永远不会看到为其设置了监视的更改。网络延迟或其他因素可能导致不同的客户端在不同的时间看到监视并从更新中返回代码。关键是不同客户看到的所有内容将具有一致的顺序。
-
为其设置Watches的数据这是指节点可以更改的不同方式。可以将ZooKeeper视为维护两个手表列表:data watches and child watches.。getData()和exist()设置data watches。getChildren()设置child watches。或者,可以考虑根据返回的数据类型设置watches。getData()和exist()返回有关节点数据的信息,而getChildren()返回子级列表。因此,setData()将触发数据监视是否设置了znode(假设设置成功)。成功的create()将触发正在创建的znode的数据监视,并触发父znode的子监视。成功的delete()会触发要删除的znode的数据监视和子监视(因为不可能有更多的子监视)以及父znode的子监视。
Watches在客户端连接到的ZooKeeper服务器上本地维护。这使watches的重量可以轻巧地设置,维护和调度。当客户端连接到新服务器时,将监视所有会话事件。与服务器断开连接时,不会收到watches。当客户端重新连接时,任何以前注册的watches将被重新注册并在需要时触发。通常,所有这些都是透明发生的。在某些情况下,可能会丢失监视:如果在断开连接的情况下创建并删除了znode,则会丢失尚未创建的znode的监视。
3.6.0中的新增功能:客户端还可以在znode上设置永久性的递归监视,这些监视在触发时不会删除,并且会以递归方式触发已注册znode以及所有子znode的更改。
Watches的语义
我们可以通过三个调用来读取ZooKeeper状态的调用来设置Watches:exist,getData和getChildren。以下列表详细说明了手表可以触发的事件以及启用它们的调用:
- Created event: Enabled with a call to exists.已创建的事件:已启用,并调用存在。
- Deleted event: Enabled with a call to exists, getData, and getChildren.已删除事件:已启用,并调用了exist,getData和getChildren。
- Changed event: Enabled with a call to exists and getData.更改的事件:通过调用exist和getData启用。
- Child event: Enabled with a call to getChildren.子事件:通过调用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后将触发的事件。
- 子项删除事件:添加了对getChildren的调用的监视程序。
- 数据删除事件:通过添加对存在或getData的调用的监视程序。
- 持久删除事件:已添加呼叫以添加持久监视的监视程序。
ZooKeeper对Watches的保证
关于Watches,ZooKeeper保持以下保证:
-
监视是针对其他事件,其他监视和异步答复而排序的。ZooKeeper客户端库可确保按顺序分派所有内容。
-
客户端将看到它正在监视的znode的监视事件,然后才能看到与该znode对应的新数据。
-
ZooKeeper中监视事件的顺序与ZooKeeper服务所看到的更新顺序相对应。
Watches须知
-
标准Watches是一次触发。如果您收到监视事件,并且希望收到有关将来更改的通知,则必须设置另一个监视。
-
因为标准Watches是一次触发,并且在获取事件和发送新请求以获取手表之间存在延迟,所以您无法可靠地看到ZooKeeper中发生在节点上的所有更改。准备处理znode在获取事件和重新设置手表之间多次更改的情况。(您可能不在乎,但至少意识到可能会发生。)
-
对于给定的通知,监视对象或功能/上下文对将仅触发一次。例如,如果为一个存在注册了相同的监视对象,并且对同一文件进行了getData调用,然后删除了该文件,则监视对象将仅使用该文件的删除通知被调用一次。
-
与服务器断开连接时(例如,服务器发生故障时),直到重新建立连接后,您才能获得任何监视。因此,会话事件将发送到所有出色的监视处理程序。使用会话事件进入安全模式:断开连接后,您将不会收到事件,因此您的进程应在该模式下谨慎行事。
使用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支持以下权限:
- 创建:您可以创建一个子节点
- 阅读:您可以从节点获取数据并列出其子节点。
- WRITE:您可以为节点设置数据
- 删除:您可以删除一个子节点
- 管理:您可以设置权限
在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的一致性保证:
-
顺序一致性:来自客户端的更新将按照发送的顺序应用。
-
原子性:更新成功或失败-没有部分结果。
-
单个系统映像:无论客户端连接到哪个服务器,客户端都将看到该服务的相同视图。也就是说,即使客户端故障转移到具有相同会话的其他服务器,客户端也永远不会看到系统的较旧视图。
-
可靠性:一旦应用了更新,它将一直持续到客户端覆盖更新为止。此保证有两个推论:
如果客户获得成功的返回码,则将应用更新。在某些故障(通信错误,超时等)上,客户端将不知道更新是否已应用。我们会采取措施以最大程度地减少失败,但是只有成功的返回码才能提供保证。(这在Paxos中称为单调性条件。)
从服务器故障中恢复时,客户端通过读取请求或成功更新看到的任何更新都不会回滚。 -
及时性:保证系统的客户视图在特定的时间范围内(约数十秒)是最新的。客户端可以在此范围内看到系统更改,或者客户端将检测到服务中断。
使用这些一致性保证很容易仅在ZooKeeper客户端上构建高层功能,例如领导者选举,障碍,队列和读/写可撤消锁(ZooKeeper不需要添加)。