ZooKeeper说话的方式简单点

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云原生网关 MSE Higress,422元/月
简介: 简单点,说话的方式简单点。萦绕耳畔的是这首歌,那就简单点吧,来浅谈一下ZooKeeper的理解。小马仍然努力寻求以最通俗的语言来一起入门理解下这个分布式利器。

简单点,说话的方式简单点。萦绕耳畔的是这首歌,那就简单点吧,来浅谈一下ZooKeeper的理解。小马仍然努力寻求以最通俗的语言来一起入门理解下这个分布式利器。

啥是ZooKeeper
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

以上是百科的解释,其实ZooKeeper的功能包括数据发布/订阅(配置中心),负载均衡,命名服务,分布式协调/通知,集群管理,Master选举,分布式锁和分布式队列等。它还是Kafka等中间件的重要依赖组件呢。它为啥这么优秀呢?还得从它的原理说起。

主要特性

zookeeper本身就是一个分布式程序,为了保证高可用,通常以集群的形态来部署zookeeper,只要半数以上节点存活,zookeeper就能正常服务。zookeeper将数据保存在内存中,这保证了高吞吐和低延迟。zookeeper是高性能的,在读多于写的程序中尤其的高性能,因为写会导致所有服务器间同步状态。zookeeper有临时节点概念,当创建临时节点的客户端会话保持活动,临时节点就一直存在,而当会话终结时,临时节点就被删除了。zookeeper底层只提供了两个功能:1 管理用户程序提交的数据, 2 为用户程序提交的数据节点提供监听服务。下文将以zk简称ZooKeeper。

为什么ZooKeeper能做这么多

ZooKeeper的工作原理可以简单归结为两个词:文件系统+监听机制。是的,你没看错,它就是这么得简单粗暴。

1、文件系统

我们借用一张图来直观理解一下。
image.png

每个根目录下的子目录节点,都被称作为 znode(目录节点)。和文件系统一样,能做各种增删改查操作,唯一的不同是znode是可以存储数据的。Zookeeper的数据模型是树结构,在内存数据库中,存储了整棵树的内容,包括所有的节点路径、节点数据、ACL信息,Zookeeper会定时将这个数据存储到磁盘上。

有四种节点类型:

永久节点(persistent):客户端与zk断开连接后,该节点依旧存在,除非客户端主动删除;

临时节点(ephemeral):客户端关闭zk连接后自动清除,此类型不能有子节点;

有编号节点(Persistent_sequential):自动增加顺序编号的znode持久化节点;

临时有编号(Ephemral_ sequential):znode节点编号会自动增加,但是是临时的,会随客户端连接断开而消失。分布式锁创建的锁节点就是这种。

2、监听机制

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、节点删除、子目录节点增删)时,zk会通知客户端。这其实有点像订阅发布机制,这个机制对zk命名服务,分布式协调/通知,集群管理,分布式队列等的实现至关重要。其监听过程下面配置中心再作详细说明,先借用一张图来助于理解。
image.png

ZooKeeper能做什么

我们就以比较经典的配置中心和分布式锁功能来简单理解下ZooKeeper是怎么做到的。

1、配置中心

使用ZooKeeper实现分布式应用配置中心。所谓的配置中心,顾名思义就是发布者将数据发布到 ZooKeeper的一个或一系列节点上,供订阅者进行数据订阅,进而达到动态获取数据的目的,实现配置信息的集中式管理和数据的动态更新。发布/订阅系统一般有两种设计模式,分别是推(Push)模式和拉(Pull)模式。推模式,服务端主动将数据更新发送给所有订阅的客户端。拉模式,客户端通过采用定时轮询拉取。

ZooKeeper采用的是推拉相结合的方式:客户端向服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务端就会向相应的客户端发送Watcher事件通知,客户端接收到这个消息通知之后,需要主动到服务端获取最新的数据。 如果将配置信息存放到zk上进行集中管理,那么通常情况下,应用在启动的时候会主动到zk服务器上进行一次配置信息的获取,同时,在指定上注册一个Watcher监听,这样一来,但凡配置信息发生变更,服务器都会实时通知所有订阅的客户端,从而达到实时获取最新配置信息的目的。

我们还是借用一张图来助于理解。
image.png

其中大概的流程是这样,zookeeper service是一个配置中心服务,底下的三个为客户端服务,服务启动后,由ConfigFetcher模块(可以认为是客户端服务上的zk客户端代码块)和zookeeper

service通讯,获取它所关心的znode目录节点中的配置数据(可以考虑同步保存一份到本地配置文件来维护,当配置中心服务挂掉后可以取本地配置),并向该znode节点注册一个watcher以监听节点数据的变更。当ConfigUpdater(可以做成一个管理后台中心)对zookeeper

service中的配置数据进行变更,各个服务受到节点配置数据变动通知,读取新的配置数据,并重新注册watcher以监听下一次变更。其实很像发布订阅机制,监听机制的作用在这里得到充分发挥。

小马联想到consul的配置中心,不过小马的理解是其是基于consul集群内部的客户端数据同步。

2、分布式锁

分布式锁是最经常被谈及的一个话题,zk的分布式锁还是要得益于它的临时有序号接节点,当然监听机制是基础。还是借用下一张图来助于理解吧。
image.png

参照上图,我们想要实现一个分布式锁,比如秒杀资源锁。首先创建一个持久性节点test/lock。每个需要获取秒杀锁的线程进来后都会创建一个临时有序节点,比如A用户创建了test/lock/seq-0000 0001节点,B创建了test/lock/seq-0000 0002节点。由于有序性,我们规定编号最小的节点获得到锁,可以进行秒杀操作,操作完释放锁就是删除节点。我们的B在A释放锁之前处于等待状态,等待A的znode节点的通知,一旦被删除,就进行再一次判断,如果自己现在是最小的那个节点则获得锁,可以秒杀操作了。因此,这里每一个等通知的znode节点,只需要监听linsten或者watch监视排号在自己前面那个znode节点就可以了。

这种一传一的监听方式,可以避免羊群效应,就是假如A被删除,其他的所有节点都同时去监听变化做出反应造成服务器压力。这样也就很好理解为什么要使用临时的有序节点(失去连接删除节点释放锁)而不是永久的,因为一传一的方式如果其中一个断掉,不释放锁,那么后面都会断掉,一直等待导致死锁。

问:Redis与Zookeeper实现分布式锁的区别?

答:redis分布式锁,需要不断去尝试获取锁,比较消耗性能;zk分布式锁,获取不到锁,注册个监听器即可,性能开销较小;redis获取锁的那个客户端bug了或者挂了,那么只能等待超时时间之后才能释放锁;而zk的话,因为创建的是临时znode,只要客户端挂了,znode就没了,此时就自动释放锁…

3、命名服务,分布式协调/通知,集群管理,Master选举

既然谈到配置中心,自然离不开服务注册和发现。zk在Kafka中的作用是管理元数据(meatdata)信息(集群、broker、主题、分区),即对应映射关系(key=>value)。当然,发送给主题分区的消息数据zk是不受理的(消息以文件的形式存储在文件系统中),否则会吃不消的。kafka使用zookeeper来实现动态的集群扩展,不需要更改客户端(producer和consumer)的配置。以下借用网上的一段文来记录理解。

broker会在zookeeper注册并保持相关的元数据(topic,partition信息等)更新,而客户端会在zookeeper上注册相关的watcher。一旦zookeeper发生变化,客户端能及时感知并作出相应调整。这样就保证了添加或去除broker时,各broker间仍能自动实现负载均衡。这其实就是服务发现。这里的客户端指的是Kafka的消息生产端(Producer)和消息消费端(Consumer)。

Producer端使用zookeeper用来"发现"broker列表,以及和Topic下每个partition的leader建立socket连接并发送消息。也就是说每个Topic的partition是由Lead角色的Broker端使用zookeeper来注册broker信息,以及监测partition leader存活性。

Consumer端使用zookeeper用来注册consumer信息,其中包括consumer消费的partition列表等,同时也用来发现broker列表,并和partition leader建立socket连接,并获取消息。

后记

zk一般以集群的方式出现,一般包含三个角色,leader,follower,observer,内置Master选举机制,这点和consul集群内部选举功能类似。
image.png

kafka集群的broker leader选举图 (kafka中broker Controller的管理工作依赖于Zookeeper)


zk中创建和删除节点只能通过Leader服务器来执行,然后Leader服务器还需要将数据同步到所有的Follower机器上。每次在创建锁和释放锁的过程中,都要动态创建、销毁瞬时节点来实现锁功能,高并发下影响性能。所以通常在高并发量,性能要求很高的场景下,被推荐使用基于redis的分布式锁,而可靠性要求高的场景使用zk。

很多中间件,比如Kafka、Hadoop、HBase,都用到了 Zookeeper,于是很多人就会去了解这个 Zookeeper 到底是什么,为什么它在分布式系统里有着如此无可替代的地位,因为它最突出的协调作用,领导选举,用起来像单机但比单机更可靠。类似的选举有Redis哨兵,consul的集群领导选举。

就此搁笔吧。本文主要是小马的个人学习理解,分享整理出来旨在希望能有助于大家理解zk,不到之处还请指正。深入实践请参阅官方文档,本文部分资料参考于网络资源,感谢分享者无私分享。

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
3月前
|
监控 API
【zookeeper 第四篇章】监控 Watcher
ZooKeeper通过Watcher机制实现了数据的发布/订阅功能。多个订阅者可以监听同一主题对象,一旦该对象状态变化,如节点内容或子节点列表变动,ZooKeeper会实时通知所有订阅者。Watcher架构包括ZooKeeper服务端、客户端及其Watcher管理器。客户端向服务端注册Watcher并保存至本地管理器中;当状态变化时,服务端通知客户端,触发相关Watcher回调处理逻辑。
79 2
|
3月前
|
前端开发 Java 开发者
【zookeeper 第一篇章】认识一下 zookeeper
Spring框架是为Java应用程序提供全面支持的平台,帮助开发者解决基础问题,专注于业务逻辑。它具备IOC(控制反转)和AOP(面向切面编程)等功能,提供MVC架构支持、事务管理和JDBC异常处理等。Spring的核心是IOC容器,通过依赖注入管理组件。依赖注入包括构造函数、setter及接口注入等方式。IOC的优点在于减少代码量,促进松耦合。
34 0
|
6月前
|
存储 Dubbo 网络协议
Zookeeper学习系列【一】 教会你Zookeeper的一些基础概念
Zookeeper学习系列【一】 教会你Zookeeper的一些基础概念
328 0
|
Java Linux API
Zookeeper学习---3、服务器动态上下线监听案例、ZooKeeper 分布式锁案例、企业面试真题
Zookeeper学习---3、服务器动态上下线监听案例、ZooKeeper 分布式锁案例、企业面试真题
|
消息中间件 算法 网络协议
Zookeeper投票选举过程详讲
Zookeeper投票选举过程详讲
165 0
|
消息中间件 缓存 运维
9张图,Kafka为什么要放弃Zookeeper
9张图,Kafka为什么要放弃Zookeeper
694 0
9张图,Kafka为什么要放弃Zookeeper
|
搜索推荐 大数据 API
ZooKeeper 典型应用:数据发布与订阅|学习笔记
快速学习 ZooKeeper 典型应用:数据发布与订阅
244 0
ZooKeeper 典型应用:数据发布与订阅|学习笔记
|
存储 监控 网络协议
测试理论--zookeeper相关
ZooKeeper相关内容讲解与基本操作方法
133 0
测试理论--zookeeper相关
|
消息中间件 存储 算法
知其然而知其所以然,为什么Kafka在2.8版本中会“抛弃”Zookeeper
知其然而知其所以然,为什么Kafka在2.8版本中会“抛弃”Zookeeper
知其然而知其所以然,为什么Kafka在2.8版本中会“抛弃”Zookeeper
|
XML JSON 监控
种草推荐Zookeeper客户端
种草推荐Zookeeper客户端
279 0