《ZooKeeper:分布式过程协同技术详解》——第2章 了解ZooKeeper2.1 ZooKeeper基础

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介:

本节书摘来自华章计算机《ZooKeeper:分布式过程协同技术详解》一书中的第2章,第2.1节,作者:Flavio Junqueira, Benjamin Reed 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

第2章 了解ZooKeeper

前一章从较高的层面讨论了分布式应用的需求,同时也讨论了在协作方面的共性需求。我们以实际应用中使用很广泛的主-从架构(master-worker)为例子,从中摘取了一些常用原语。本章将开始讨论ZooKeeper,看一看这个服务如何实现这些协作方面的原语。

2.1 ZooKeeper基础

很多用于协作的原语常常在很多应用之间共享,因此,设计一个用于协作需求的服务的方法往往是提供原语列表,暴露出每个原语的实例化调用方法,并直接控制这些实例。比如,我们可以说分布式锁机制组成了一个重要的原语,同时暴露出创建(create)、获取(acquire)和释放(release)三个调用方法。
这种设计存在一些重大的缺陷:首先,我们要么预先提出一份详尽的原语列表,要么提供API的扩展,以便引入新的原语;其次,以这种方式实现原语的服务使得应用丧失了灵活性。
因此,在ZooKeeper中我们另辟蹊径。ZooKeeper并不直接暴露原语,取而代之,它暴露了由一小部分调用方法组成的类似文件系统的API,以便允许应用实现自己的原语。我们通常使用菜谱(recipes)来表示这些原语的实现。菜谱包括ZooKeeper操作和维护一个小型的数据节点,这些节点被称为znode,采用类似于文件系统的层级树状结构进行管理。图2-1描述了一个znode树的结构,根节点包含4个子节点,其中三个子节点拥有下一级节点,叶子节点存储了数据信息。


869bca31cc6bdfc73ebbe7a31d9b70ddd9b78bcb

针对一个znode,没有数据常常表达了重要的信息。比如,在主-从模式的例子中,主节点的znode没有数据,表示当前还没有选举出主节点。而图2-1中涉及的一些其他znode节点在主-从模式的配置中非常有用:
/workers节点作为父节点,其下每个znode子节点保存了系统中一个可用从节点信息。如图2-1所示,有一个从节点(foot.com:2181)。
/tasks节点作为父节点,其下每个znode子节点保存了所有已经创建并等待从节点执行的任务的信息,主-从模式的应用的客户端在/tasks下添加一个znode子节点,用来表示一个新任务,并等待任务状态的znode节点。
/assign节点作为父节点,其下每个znode子节点保存了分配到某个从节点的一个任务信息,当主节点为某个从节点分配了一个任务,就会在/assign下增加一个子节点。
2.1.1 API概述
znode节点可能含有数据,也可能没有。如果一个znode节点包含任何数据,那么数据存储为字节数组(byte array)。字节数组的具体格式特定于每个应用的实现,ZooKeeper并不直接提供解析的支持。我们可以使用如Protocol Buffers、Thrift、Avro或MessagePack等序列化(Serialization)包来方便地处理保存于znode节点的数据格式,不过有些时候,以UTF-8或ASCII编码的字符串已经够用了。
ZooKeeper的API暴露了以下方法:
  • create /path data
  • 创建一个名为/path的znode节点,并包含数据data。
  • delete /path
  • 删除名为/path的znode。
  • exists /path
  • 检查是否存在名为/path的节点。
  • setData /path data
  • 设置名为/path的znode的数据为data。
  • getData /path
  • 返回名为/path节点的数据信息。
  • getChildren /path
  • 返回所有/path节点的所有子节点列表。

需要注意的是,ZooKeeper并不允许局部写入或读取znode节点的数据。当设置一个znode节点的数据或读取时,znode节点的内容会被整个替换或全部读取进来。
ZooKeeper客户端连接到ZooKeeper服务,通过API调用来建立会话(session)。如果你对如何使用ZooKeeper非常感兴趣,请跳转到后面的“会话”一节,在那一节会讲解如何通过命令行的方式来运行ZooKeeper指令。
2.1.2 znode的不同类型
当新建znode时,还需要指定该节点的类型(mode),不同的类型决定了znode节点的行为方式。
持久节点和临时节点
znode节点可以是持久(persistent)节点,还可以是临时(ephemeral)节点。持久的znode,如/path,只能通过调用delete来进行删除。临时的znode与之相反,当创建该节点的客户端崩溃或关闭了与ZooKeeper的连接时,这个节点就会被删除。
持久znode是一种非常有用的znode,可以通过持久类型的znode为应用保存一些数据,即使znode的创建者不再属于应用系统时,数据也可以保存下来而不丢失。例如,在主-从模式例子中,需要保存从节点的任务分配情况,即使分配任务的主节点已经崩溃了。
临时znode传达了应用某些方面的信息,仅当创建者的会话有效时这些信息必须有效保存。例如,在主从模式的例子中,当主节点创建的znode为临时节点时,该节点的存在意味着现在有一个主节点,且主节点状态处于正常运行中。如果主znode消失后,该znode节点仍然存在,那么系统将无法监测到主节点崩溃。这样就可以阻止系统继续进行,因此这个znode需要和主节点一起消失。我们也在从节点中使用临时的znode,如果一个从节点失效,那么会话将会过期,之后znode /workers也将自动消失。
一个临时znode,在以下两种情况下将会被删除:

  1. 当创建该znode的客户端的会话因超时或主动关闭而中止时。
  2. 当某个客户端(不一定是创建者)主动删除该节点时。
    因为临时的znode在其创建者的会话过期时被删除,所以我们现在不允许临时节点拥有子节点。在社区讨论中,已经讨论过关于允许临时znode拥有子节点的问题,其想法是使其子节点也均为临时节点。这个功能也许会出现在未来的发布版本中,但现在还是不可用的。
  3. 有序节点
    一个znode还可以设置为有序(sequential)节点。一个有序znode节点被分配唯一个单调递增的整数。当创建有序节点时,一个序号会被追加到路径之后。例如,如果一个客户端创建了一个有序znode节点,其路径为/tasks/task-,那么ZooKeeper将会分配一个序号,如1,并将这个数字追加到路径之后,最后该znode节点为/tasks/task-1。有序znode通过提供了创建具有唯一名称的znode的简单方式。同时也通过这种方式可以直观地查看znode的创建顺序。

总之, znode一共有4种类型:持久的(persistent)、临时的(ephemeral)、持久有序的(persistent_sequential)和临时有序的(ephemeral_sequential)。
2.1.3 监视与通知
ZooKeeper通常以远程服务的方式被访问,如果每次访问znode时,客户端都需要获得节点中的内容,这样的代价就非常大。因为这样会导致更高的延迟,而且ZooKeeper需要做更多的操作。考虑图2-2中的例子,第二次调用getChildren /tasks返回了相同的值,一个空的集合,其实是没有必要的。


<a href=https://yqfile.alicdn.com/e76748bd981d64d8e9ef1949d47d1af4167d2ce4.png" >

这是一个常见的轮询问题。为了替换客户端的轮询,我们选择了基于通知(notification)的机制:客户端向ZooKeeper注册需要接收通知的znode,通过对znode设置监视点(watch)来接收通知。监视点是一个单次触发的操作,意即监视点会触发一个通知。为了接收多个通知,客户端必须在每次通知后设置一个新的监视点。在图2-3
阐述的情况下,当节点/tasks发生变化时,客户端会收到一个通知,并从ZooKeeper读取一个新值。


4becc655449e841684eeb17704f15453f58dbfaa

当使用通知机制时,还有一些需要知道的事情。因为通知机制是单次触发的操作,所以在客户端接收一个znode变更通知并设置新的监视点时,znode节点也许发生了新的变化(不要担心,你不会错过状态的变化)。让我们看一个例子来说明它到底是怎么工作的。假设事件按以下顺序发生:

  1. 客户端c1设置监视点来监控/tasks数据的变化。
  2. 客户端c1连接后,向/tasks中添加了一个新的任务。
  3. 客户端c1接收通知。
  4. 客户端c1设置新的监视点,在设置完成前,第三个客户端c3连接后,向/tasks中添加了一个新的任务。
    客户端c1最终设置了新的监视点,但由c3添加数据的变更并没有触发一个通知。为了观察这个变更,在设置新的监视点前,c1实际上需要读取节点/tasks的状态,通过在设置监视点前读取ZooKeeper的状态,最终,c1就不会错过任何变更。

通知机制的一个重要保障是,对同一个znode的操作,先向客户端传送通知,然后再对该节点进行变更。如果客户端对一个znode设置了监视点,而该znode发生了两个连续更新。第一次更新后,客户端在观察第二次变化前就接收到了通知,然后读取znode中的数据。我们认为主要特性在于通知机制阻止了客户端所观察的更新顺序。虽然ZooKeeper的状态变化传播给某些客户端时更慢,但我们保障客户端以全局的顺序来观察ZooKeeper的状态。
ZooKeeper可以定义不同类型的通知,这依赖于设置监视点对应的通知类型。客户端可以设置多种监视点,如监控znode的数据变化、监控znode子节点的变化、监控znode的创建或删除。为了设置监视点,可以使用任何API中的调用来读取ZooKeeper的状态,在调用这些API时,传入一个watcher对象或使用默认的watcher。本章后续(主从模式的实现)及第4章会以主从模式的例子来展开讨论,我们将深入研究如何使用该机制。
注意: 谁来管理我的缓存

如果不让客户端来管理其拥有的ZooKeeper数据的缓存,我们不得不让ZooKeeper来管理这些应用程序的缓存。但是,这样会导致ZooKeeper的设计更加复杂。事实上,如果让ZooKeeper管理缓存失效,可能会导致ZooKeeper在运行时,停滞在等待客户端确认一个缓存失效的请求上,因为在进行所有的写操作前,需要确认所有的缓存数据是否已经失效。

2.1.4 版本
每一个znode都有一个版本号,它随着每次数据变化而自增。两个API操作可以有条件地执行:setData和delete。这两个调用以版本号作为转入参数,只有当转入参数的版本号与服务器上的版本号一致时调用才会成功。当多个ZooKeeper客户端对同一个znode进行操作时,版本的使用就会显得尤为重要。例如,假设客户端c1对znode /config写入了一些配置信息,如果另一个客户端c2同时更新了这个znode,此时c1的版本号已经过期,c1调用setData一定不会成功。使用版本机制有效避免了以上情况。在这个例子中,c1在写入数据时使用的版本无法匹配,使得操作失败,图2-4描述了这个情况。


8c6af276f79427ba03a8f79a493f612b92de500d
相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
7天前
|
监控 负载均衡 Cloud Native
ZooKeeper分布式协调服务详解:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入剖析ZooKeeper分布式协调服务原理,涵盖核心概念如Server、Client、ZNode、ACL、Watcher,以及ZAB协议在一致性、会话管理、Leader选举中的作用。讨论ZooKeeper数据模型、操作、会话管理、集群部署与管理、性能调优和监控。同时,文章探讨了ZooKeeper在分布式锁、队列、服务注册与发现等场景的应用,并在面试方面分析了与其它服务的区别、实战挑战及解决方案。附带Java客户端实现分布式锁的代码示例,助力提升面试表现。
27 2
|
1月前
|
监控 NoSQL Java
Zookeeper分布式锁
Zookeeper分布式锁
90 1
|
7天前
|
分布式计算 Hadoop 大数据
大数据技术与Python:结合Spark和Hadoop进行分布式计算
【4月更文挑战第12天】本文介绍了大数据技术及其4V特性,阐述了Hadoop和Spark在大数据处理中的作用。Hadoop提供分布式文件系统和MapReduce,Spark则为内存计算提供快速处理能力。通过Python结合Spark和Hadoop,可在分布式环境中进行数据处理和分析。文章详细讲解了如何配置Python环境、安装Spark和Hadoop,以及使用Python编写和提交代码到集群进行计算。掌握这些技能有助于应对大数据挑战。
|
20天前
|
设计模式 安全 Java
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
23 0
|
21天前
|
NoSQL Java Redis
【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的分布式锁的功能组件(二)
【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的分布式锁的功能组件
14 0
|
20天前
|
存储 监控 安全
金石推荐 | 【分布式技术专题】「单点登录技术架构」一文带领你好好认识以下Saml协议的运作机制和流程模式
金石推荐 | 【分布式技术专题】「单点登录技术架构」一文带领你好好认识以下Saml协议的运作机制和流程模式
20 0
|
20天前
|
存储 Java 应用服务中间件
【分布式技术专题】「架构实践于案例分析」盘点互联网应用服务中常用分布式事务(刚性事务和柔性事务)的原理和方案
【分布式技术专题】「架构实践于案例分析」盘点互联网应用服务中常用分布式事务(刚性事务和柔性事务)的原理和方案
42 0
|
21天前
|
canal 消息中间件 关系型数据库
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
66 0
|
21天前
|
缓存 应用服务中间件 数据库
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(多级缓存设计分析)
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(多级缓存设计分析)
26 1
|
1月前
|
存储 供应链 安全
新一代数据库技术:融合区块链与分布式存储的未来前景
传统的数据库技术在面对大规模数据存储和安全性方面存在诸多挑战,而新一代数据库技术正在崭露头角。本文将探讨如何融合区块链与分布式存储技术,为数据库领域带来全新的发展机遇,并分析其在实际应用中的潜力与前景。