ZooKeeper作为一款极具特色的分布式应用程序协同服务,发挥着十分重要的作用。本篇文章围绕ZooKeeper展开,详细介绍了它的安装配置过程、基本概念、zkCli 的使用方法,并且通过实际操作展示了如何利用 zkCli 来实现一个锁,希望能够帮助大家更好地理解和运用 ZooKeeper 这项技术。
一、什么是 ZooKeeper
ZooKeeper 是一款分布式的、开源的分布式应用程序协同服务。它的设计初衷非常明确,那就是将那些复杂且容易出错的分布式一致性服务进行封装,进而构建出一个高效可靠的原语集,并且通过一系列简单易用的接口提供给用户使用,大大降低了开发人员在处理分布式协同问题时的难度。
二、ZooKeeper发展历史
ZooKeeper 最早诞生于雅虎研究院的一个研究小组。当时,研究人员在雅虎内部的诸多大型系统中发现了一个共性问题,即很多系统都需要依赖类似的系统来完成分布式协同工作,然而这些系统普遍存在着分布式单点问题,这无疑给系统的稳定性和可靠性带来了隐患。
于是,雅虎的开发人员着手开发了一个通用的、不存在单点问题的分布式协调框架,这便是 ZooKeeper。后来,ZooKeeper 在开源界得到了大量应用,以下为大家列举 3 个著名开源项目对 ZooKeeper 的应用情况:
1、Hadoop:借助 ZooKeeper 实现 Namenode 的高可用,确保整个系统在关键节点方面的稳定性和容错能力。
2、HBase:利用 ZooKeeper 保证集群中只有一个 master,同时保存 hbase:meta 表的位置以及集群中的 RegionServer 列表,以此来维持集群的有序运行。
3、Kafka:通过 ZooKeeper 进行集群成员管理以及 controller 节点选举,保障集群在动态变化过程中的协调一致。
三、ZooKeeper应用场景
在分布式协调服务领域,ZooKeeper 有着广泛的用武之地,诸多场景都可以借助它来实现高效的协调,下面为大家介绍几个典型应用场景:
1、配置管理(configuration management):在普通的 Java 应用中,配置项通常只是一个本地的配置文件即可满足需求。但若是微服务系统,各个独立的服务就需要采用集中化的配置管理方式,这时 ZooKeeper 就能派上用场了,它可以很好地协调各服务间的配置信息。
2、DNS 服务:在网络环境中,ZooKeeper 也能在 DNS 服务相关方面发挥独特作用,助力域名解析等工作更加顺畅地进行。
3、组成员管理(group membership):就像前面提到的 HBase 利用 ZooKeeper 进行集群的组成员管理一样,ZooKeeper 能够清晰地掌控成员的状态和信息,确保集群成员间的协调运作。
4、各种分布式锁:在需要实现分布式锁的场景中,ZooKeeper 也是一个得力的工具。
不过需要注意的是,ZooKeeper 更适用于存储和协同相关的关键数据,并不适合用于大数据量存储。这是为什么呢?主要有以下两方面原因:
5、设计方面:ZooKeeper 需要将所有的数据(也就是它的 data tree)加载到内存当中,这就使得它所能存储的数据量受到内存大小的限制。在这一点上,它和 Redis 比较相似。而一般的数据库系统,例如使用 InnoDB 存储引擎的 MySQL,由于 InnoDB 是基于 B-Tree 的存储引擎,B-tree 存储引擎以及 LSM 存储引擎都能够存储大于内存的数据量,所以在大数据存储方面更具优势。
6、工程方面:ZooKeeper 的设计目标主要是为协同服务提供数据存储,数据的高可用性和性能才是其最为看重的系统指标,处理大数据量并非它的首要目标。因此,ZooKeeper 在工程层面不会针对大数据量存储做过多的优化处理。
四、ZooKeeper服务的使用
若要使用 ZooKeeper 服务,首先我们的应用需要引入 ZooKeeper 的客户端库,之后通过客户端库与 ZooKeeper 集群进行网络通信,以此来使用 ZooKeeper 所提供的服务。从本质上来说,这属于 Client-Server 的架构,我们的应用扮演着客户端的角色,去调用 ZooKeeper Server 端提供的服务。
五、ZooKeeper数据模型
ZooKeeper的数据模型是层次模型,这种模型在文件系统中较为常见。层次模型和 key-value 模型是当下两种主流的数据模型。ZooKeeper 之所以采用文件系统模型,主要基于以下两点考虑:
- 文件系统的树形结构便于清晰地表达数据之间的层次关系,使得数据的组织和管理更加有条理;
- 文件系统的树形结构能够方便地为不同的应用分配独立的命名空间(namespace),确保各个应用的数据互不干扰。
ZooKeeper的层次模型被称作 data tree,data tree 的每个节点叫做 znode。与普通文件系统不同的是,ZooKeeper 中的每个节点都可以保存数据,并且每个节点都拥有一个版本(version),版本计数从 0 开始。
例如在如上图所示的 data tree 中包含两个子树,一个用于应用 1(/app1),另一个用于应用 2(/app2)。应用 1 的子树实现了一个简单的组成员协议:每个客户端进程 pi 创建一个 znode p_i 在 /app1 下,只要 /app1/p_i 存在,就代表进程 pi 处于正常运行状态。
1、data tree接口
ZooKeeper 对外提供了一个用来访问 data tree 的简化文件系统 API,具有以下特点:
- 使用 UNIX 风格的路径名来定位 znode,例如 /A/X 表示 znode A 的子节点 X,这种方式简单直观,易于理解和操作;
- znode 的数据只支持全量写入和读取,并不像通用文件系统那样支持部分写入和读取,这是由其自身设计和应用场景所决定的;
- data tree 的所有 API 都是 wait-free 的,也就是说正在执行中的 API 调用不会对其他 API 的完成产生影响,保证了操作的独立性和高效性;
- data tree 的 API 都是对文件系统的 wait-free 操作,虽然不直接提供锁这样的分布式协同机制,但其功能非常强大,可以用来实现多种分布式协同机制。
2、znode分类
一个 znode 可以分为不同的类型,具体可以是持久性的,也可以是临时性的,同时 znode 节点还可以具备顺序性。每一个顺序性的 znode 都会关联一个唯一的单调递增整数。因此,ZooKeeper 主要有以下 4 种 znode:
- 持久性的 znode (PERSISTENT):无论 ZooKeeper 出现宕机情况,还是 client 宕机,只要这个 znode 一旦创建,就不会丢失,能够保证数据的持久存储;
- 临时性的 znode (EPHEMERAL):当 ZooKeeper 宕机了,或者 client 在指定的 timeout 时间内没有连接 server,该 znode 都会被认为丢失,这种特性适用于一些需要动态感知客户端状态的场景;
- 持久顺序性的 znode (PERSISTENT_SEQUENTIAL):这类 znode 除了具备持久性 znode 的特点之外,其名字还具备顺序性;
- 临时顺序性的 znode (EPHEMERAL_SEQUENTIAL):它除了具备临时性 znode 的特点之外,名字同样具备顺序性,结合了临时和顺序两种特性,可满足更多复杂场景的需求。
六、安装ZooKeeper
首先,我们需要到 https://archive.apache.org/dist/zookeeper/stable/ 这个网址去下载 ZooKeeper,截至目前,它的最新版本是 3.5.6。
下载完成后,把 apache-zookeeper-3.5.6-bin.tar.gz 解压到一个本地目录(需要注意的是,目录名最好不要包含空格和中文,这里我使用 /usr/local 目录),解压命令如下:
tar -zxvf apache-zookeeper-3.5.6-bin.tar.gz
接着把 conf 目录下的 zoo_sample.cfg 重命名为 zoo.cfg,然后对相关配置进行修改。
配置以下环境变量,可以通过 vim /etc/profile 命令来操作:
七、启动Zookeeper
在完成安装和配置之后,就可以启动 Zookeeper 了,使用 zkServer.sh start 命令来启动 ZooKeeper 服务。
启动之后,我们需要做一些检查工作:
- 检查 ZooKeeper 日志是否有出错信息:如果没有返回结果,那就说明暂时没有错误信息,系统启动正常。
- 检查 ZooKeeper 数据文件:这里存放着 ZooKeeper 的事务日志文件和快照日志文件,由于现在还没有运行任何 ZooKeeper 命令,所以可能暂时还没有事务日志文件。
检查 ZooKeeper 是否在 2181 端口上监听:通过执行 netstat -an | ag 2181 命令,如果看到 ZooKeeper 已经在 2181 这个端口上监听了,那就说明启动成功。
下面来演示一下如何使用 zkCli:
1、zkCli使用
在执行 zkCli.sh 命令后,会出现很多消息,这些消息表明我们的 zkCli 和 ZooKeeper 的节点成功建立了有效连接。可以使用 ls -R / 命令来递归查找 ZooKeeper 的 znode 节点,使用 create /znode_name 命令来创建 znode 节点,具体演示如下:
2、用zkCli实现锁
分布式锁要求当锁的持有者出现宕机情况时,锁能够被自动释放。而 ZooKeeper 的 ephemeral 节点恰好具备这样的特性,接下来我们通过实际操作来演示一下。
需要在两个终端上分别启动 zkCli,具体操作如下:
(1)在终端 1 上:
执行 zkCli.sh,再执行 create -e /lock 命令,以此来建立临时 znode,实际上加锁的操作就是建立 znode 的过程,此时第一个客户端加锁成功。
(2)接下来在第二个客户端尝试加锁,在终端 2 上:
执行 zkCli.sh,再执行 create -e /lock 命令,这时会发现提示 Node already exists: /lock,表明 znode 已存在,znode 建立失败,也就意味着加锁失败。此时我们来监控这个 znode,通过执行 stat -w /lock 命令来等待锁被释放。
当我们在终端 1 上执行 quit 命令退出第一个客户端时,在客户端 2 上会收到一条 WATCHER 信息,具体如下:
在收到这个事件后,再次在客户端 2 上执行加锁操作,即执行 create -e /lock,会显示创建 znode 成功,也就是加锁成功。
-
广告合作
-
QQ群号:4114653