作者的其他平台:
| CSDN:blog.csdn.net/qq_41153943
| 掘金:juejin.cn/user/651387…
| 知乎:www.zhihu.com/people/1024…
| GitHub:github.com/JiangXia-10…
| 公众号:1024笔记
本文一共5232字,预计阅读时间13分钟
在分布式系统中,注册中心充当着重要角色,是服务发现、客户端负载均衡中不可缺少的一员。注册中心除了能够实现基本的功能外,它的稳定性、可用性和健壮性对整个分布式系统的流畅运行影响重大。dubbo作为国内一款主流的分布式系统,支持的注册中心有zookeeper、nacos和redis等第三方中间件。
高并发分布式开发技术体系已然非常的庞大,前段时间一直在准备找工作,参加面试,通过面试的情况可以发现RPC、Dubbo、zookeeper、nacos、分布式、微服务等这些已经成为了找工作的最基础的技能要求了。
之前有篇文章介绍到了如何使用nacos作为注册中心:SpringCloud:搭建Nacos服务以及服务发现。其实不仅仅nacos可以作为注册中心,zookeeper也可以作为注册中心使用。但是Zookeeper其实不仅仅可以作为注册中心。
对于Zookeeper,其官方文档上的解释是:它是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。可以理解为zookeeper是文件系统+监听通知机制。
今天这篇文章就一起来学习学习Zookeeper,我自己也是学习的过程,所以如果有不正确的地方欢迎讨论指正!
随着系统应用的拓展和数据量的保证,我们的系统经常会遇到这些情况:
怎么保证一个服务器集群中的所有服务器保持共享的配置信息的一致性?
如果服务器集群中有一台机器挂掉了,其他机器如何感知到这一变化并接管任务?
对于分布式系统,如何高效协同多台服务对同一网络文件进行写操作并保持一致性?
如何做到不重启集群而完成机器的添加?
…
为了解决上述的问题,就需要一个类似于线程协同机制的工具,让各个服务进行协同工作。而zookeeper就是这样的一类工具。
上面说到对于Zookeeper,其官方文档上的解释是:它是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。
所以可以理解为zookeeper是一种可以用于分布式应用的高性能协调服务,它的数据是存于内存中的,并且持久化实现在日志中。而它的内存结构是类似于树形结构,具有高吞吐低延迟的特点。zookeeper不仅仅可以帮助我们实现分布式统一配置中心,服务注册,分布式锁等,它们维护内存中的状态图像,以及持久性存储中的事务日志和快照。只要大多数服务器可用,ZooKeeper服务就可用。客户端连接到单个ZooKeeper服务器。客户端维护TCP连接,通过该连接发送请求,获取响应,获取监视事件以及发送tick。如果与服务器的TCP连接中断,则客户端将连接到其他服务器。所以可以简单地认为zookeeper=文件系统+监听通知机制。
我们还可以这样理解:zookeeper的中文意思就是动物园管理员(zoom+keeper)。动物园管理员的作用就是负责管理动物园里面的动物,让它们井然有序。而zookeeper是apache下的开源项目,在apache下的很多开源项目其实都是以动物作为图标的,比如Hadoop(大象),Hive(蜜蜂),Pig(小猪)、tomcat(猫)。
所以可以记忆成apache下的项目就是动物园,而zookeeper就是负责管理这些动物(开源项目)的动物管理员。
zookeeper 会维护一个具有层次关系的数据结构,它非常类似于一个标准的文件系统:
上图中的树形结构中的每个节点(目录项),比如NameService 都被称作为 znode(目录节点)。zonde通过路径引用,路径必须是绝对的,因此他们必须由斜杠字符来开头。除此以外,它们必须是唯一的,也就是说每一个路径只有一个表示,因此这些路径不能改变。在zookeeper中,路径由Unicode字符串组成,并且有一些限制。字符串"/ZooKeeper"用以保存管理信息,比如关键配额信息。
znode同时具有文件和目录两种特点。既像文件一样维护着数据、元信息、访问控制列表)、时间戳等数据结构,又可以像目录一样可以作为路径标识的一部分,能够自由的增加、删除znode。
每个znode都是由三部分组成:
stat:此为状态信息, 描述该znode的版本, 权限等信息
data:与该znode关联的数据
children:该znode下的子节点
需要注意的是同一个节点下的子节点名称不能相同,且命名是有规范的,它的路径是没有相对路径的概念的,都是绝对路径,任何开始都以"/"开始,最后就是,它存放数据的大小是有限制的。
zookeeper中的节点有两种,分别为临时节点(Ephemeral Node)和永久节点(Persistent Node)。节点的类型在创建时即被确定,并且不能改变。
两种节点的区别在于是否依赖于会话(Session)而生存。客户端和ZooKeeper服务器的一次连接称为一次会话。客户端靠与服务器建立一个TCP的长连接来维持一个会话,客户端在启动的时候首先会与服务器建立一个TCP连接,通过这个连接客户端能够通过心跳检测与服务器保持有效的会话,也能向ZooKeeper服务器发送请求并获得响应。
(1)、临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话结束,临时节点将被自动删除,当然也可以手动删除。虽然每个临时的Znode都会绑定到一个客户端会话,但他们对所有的客户端还是可见的。另外,zookeeper的临时节点不允许拥有子节点。临时节点又可以细分为:临时目录节点和临时顺序编号目录节点。
临时目录节点(EPHEMERAL):客户端与zookeeper断开连接后,该节点被删除;
临时顺序编号目录节点(EPHEMERAL_SEQUENTIAL):客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号;
(2)、永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。临时节点又可以细分为:持久目录节点和持久顺序编号目录节点。
持久化目录节点(PERSISTENT):客户端与zookeeper断开连接后,该节点依旧存在
持久化顺序编号目录节点(PERSISTENT_SEQUENTIAL):客户端与zookeeper断开连接后,该节点依旧存在,只是zookeeper给该节点名称进行顺序编号。
上面的分类有个概念叫顺序节点:在创建节点的时候,用户可以请求在zooKeeper的路径结尾添加一个递增的计数。这个计数对于此节点的父节点来说是唯一的,当客户端请求创建这个节点后,zookeeper会根据父节点的zxid状态,为这个节点编写一个全目录唯一的编号,并且这个编号只会一直增长。这样的节点称为顺序节点。
这上面又提到了一个概念叫zxid:对于改变zookeeper节点状态的每一个操作都将使这个节点接收到一个Zxid格式的时间戳,并且这个时间戳全局有序。可以理解为每个改变对节点的操作都会产生一个唯一的事务id叫做Zxid。如果Zxid1的值小于Zxid2的值,那么就可以认为Zxid1所对应的事件发生在Zxid2所对应的事件之前。其实,zookeeper的每个节点都维护着两个Zxid值,分别是:cZxid、mZxid。
cZxid:指的是节点的创建时间所对应的Zxid格式时间戳。
mZxid:指的是节点的修改时间所对应的Zxid格式时间戳。
实现中Zxid是一个64位的数字,它高32位是epoch(投票)用来标识Leader关系是否改变,每次一个Leader被选出来,它都会有一个新的epoch。而低32位就是个递增计数。
zookeeper提供了多种方式跟踪时间,zookeeper给每个更新贴上一个数字(前面说的zxid),这个数字反映了所有zookeeper事务的顺序,严格的顺序意味着可以在客户机上实现复杂的同步。除了上面说到的zxid,还有version、zoo.cfg中ticks配置。
version numbers(版本号):版本号是用来记录节点数据或者是节点的子节点列表或者是权限信息的修改次数。如果一个节点的version是1,那就代表说这个节点从创建以来被修改了一次。
每个节点维护着三个版本号,他们分别为:
version:节点数据版本号
cversion:子节点版本号
aversion:节点所拥有的ACL版本号
对节点的写请求都会导致该节点的3种版本号增加,原理和乐观锁差不多。
ticks :zoo.cfg文件中的配置。当使用多服务器zookeeper时,服务器使用一个“滴答”来定义事件的时间,如状态上传,会话超时等,它通过最小会话超时(默认是滴答时间x2)间接公开,如果客户端请求超过这个时间,那客户端就不再能连接上服务器端
real time:zookeeper并不使用真实时间
所以可以理解为zookeeper是一个协调者,使得一些交互连接有序进行!
速度快
前面提到了zookeeper的数据加载在内存中,所以它具有高吞吐和低延迟的效果。并且以读取为事务速度尤其快,而且操作的znode大小限制在1m。正是这些特点,使得zookeeper可以适用于大型的分布式系统
zookeeper的数据是可复制,可备份的。zookeeper可以快速地搭建一个集群,内部自带了这样的一些工具与机制,我们只需要设置一些配置即可,保证服务可靠,所以不会成为单点故障。如下:
zookeeper允许用户在指定节点上注册一些Watcher,当数据节点发生变化的时候,zookeeper服务器会把这个变化的通知发送给感兴趣的客户端。这个是zookeeper的核心特性,zookeeper的很多功能都是基于这个特性实现的。
如果有两个客户端都在zookeeper集群中注册了watcher(事件监听器),那么当zookeeper中的节点数据发生变化的时候,zookeeper会把这一变化的通知发送给客户端,当客户端收到这个变化通知的时候,会触发某些提前定义好的动作。一般来说,zookeeper会向客户端发送且仅发送一条通知,如果一个watch同时注册了多个接口(exists,getData),如果此时删除节点,虽然这个事件对exists和getData都有效,但是watch只会被调用一次。并且这些请求有可能存在延时,所以不能绝对可靠得到每个节点发生的每个更改。watch触发后会立即删除,要持续监听变化的话就需要持续提供设置watch。并且客户端先得到watch通知才可查看变化结果。
触发watch事件的条件有4种,create,delete,change,child(子节点事件)
所以可以总结zookeeper的特点如下:
1、原子性(Atomicity),更新成功或失败。没有部分结果;
2、可靠性:数据的变更不会丢失,除非被客户端覆盖修改;
3、实时性:系统的客户端当时读取到的数据是最新的;
4、有序性:客户端的操作都是按照顺序生效的;
5、一致性:又叫单个系统映像,无论连接的是哪个服务器,客户端看到的内容都是相同的。
上述就是关于zookeeper的简单介绍。自己也是一个学习的过程。总结了一些关于zookeeper的概念和相关知识点,如果有不正确的地方,欢迎指出来,交流讨论!
后续将介绍zookeeper更多的相关内容!
Spring注解(三):@scope设置组件作用域
Spring常用注解大全,值得你的收藏!!!
Spring注解(七):使用@Value对Bean进行属性赋值
SpringBoot开发Restful风格的接口实现CRUD功能
Spring注解(六):Bean的生命周期中自定义初始化和销毁方法的四种方式
SpringCloud:搭建Nacos服务以及服务发现
SpringBoot整合Redis使用教程
聊聊Redis是如何做到“持久化”