Zookepeer
1.入门简介
1.1 Zookepeer是什么
1.1.1 官方版
①它是拿来管大象(Hadoop)、蜜蜂(Hive)、小猪(Pig)的管理员,Apache Hbase和Apache Solr以及阿里的Dubbo等项目中都采用到了Zookeeper。
②一句话:ZooKeeper是一个分布式协调技术、高性能的,开源的分布式系统的协调(Coordination)服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用程序一致性和分布式协调技术服务的软件。
1.1.2 从设计模式角度来理解
是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在,Zookeeper上注册的那些观察者做出相应的反应,从而实现集群中类似Master/Slave管理模式。
1.1.3 通俗总结
zookeeper=类似unix文件系统+通知机制+Znode节点
作用:服务注册+分布式系统的一致性通知协调
下载地址:https://zookeeper.apache.org/
1.2 如何使用?
1.2.1 统一命名服务
(Name Service如Dubbo服务注册中心)
①Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。
在Dubbo实现中:
②服务提供者在启动的时候,向ZK上的指定节点/dubbo/${serviceName}/providers目录下写入自己的URL地址,这个操作就完成了服务的发布。
③服务消费者启动的时候,订阅/dubbo/ s e r v i c e N a m e / p r o v i d e r s 目 录 下 的 提 供 者 U R L 地 址 , 并 向 / d u b b o / {serviceName}/providers目录下的提供者URL地址, 并向/dubbo/ serviceName/providers目录下的提供者URL地址,并向/dubbo/{serviceName} /consumers目录下写入自己的URL地址。
注意,所有向ZK上注册的地址都是临时节点,这样就能够保证服务提供者和消费者能够自动感应资源的变化。 另外,Dubbo还有针对服务粒度的监控,方法是订阅/dubbo/${serviceName}目录下所有提供者和消费者的信息。
1.2.2 配置管理
(Configuration Management如淘宝开源配置管理框架Diamond)
①在大型的分布式系统中,为了服务海量的请求,同一个应用常常需要多个实例。如果存在配置更新的需求,常常需要逐台更新,给运维增加了很大的负担同时带来一定的风险(配置会存在不一致的窗口期,或者个别节点忘记更新)。zookeeper可以用来做集中的配置管理,存储在zookeeper集群中的配置,如果发生变更会主动推送到连接配置中心的应用节点,实现一处更新处处更新的效果。
②现在把这些配置全部放到zookeeper上去,保存在 Zookeeper 的某个目录节点中,然后所有相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会收到 Zookeeper 的通知,然后从 Zookeeper 获取新的配置信息应用到系统中就好。
1.2.3 Java操作API
2.安装配置
2.1 Linux下安装
①官网下载安装包,本次版本zookeeper-3.4.11.tar.gz
②拷贝进入到/opt目录下并解压或直接执行解压命令tar -zxvf zookeeper-3.4.11.tar.gz -C /opt
③在/opt目录中新建专属zookeeper目录,mkdir /myzookeeper,随后将上一步解压的zookeeper内容拷贝进/myzookeeper目录内
④进入conf文件夹,拷贝zoo_sample.cfg改为zoo.cfg
⑤zoo.cfg解读
<1>tickTime
tickTime:通信心跳数,Zookeeper服务器心跳时间,单位毫秒
Zookeeper使用的基本时间, 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳,时间单位为毫秒。
它用于心跳机制,并且设置最小的session超时时间为两倍心跳时间.(session的最小超时时间是2*tickTime。)
<2>initLimit
这个配置项是用来配置Zookeeper接收Follower客户端(这里所说的客户端不是用户链接Zookeeper服务器的客户端,**而是Zookeeper服务器集群中连接到leader的Follower服务器,**Follower在启动过程中,会从Leader同步所有最新数据,然后确定自己能够对外服务的起始状态。Leader允许Follower在 initLimit 时间内完成这个工作)初始化连接是最长能忍受多少个心跳的时间间隔数。
当已经超过10个心跳的时间(也就是tickTime)长度后Zookeeper服务器还没有收到客户端返回的信息,那么表明这个客户端连接失败。总的时间长度就是10*2000=20秒
<3>syncLimit
syncLimit:LF同步通信时限,集群中Leader与Follower之间的最大响应时间单位。
在运行过程中,Leader负责与ZK集群中所有机器进行通信,例如通过一些心跳检测机制,来检测机器的存活状态,
假如响应超过syncLimit * tickTime(假设syncLimit=5 ,请求和应答时间长度,最长不能超过多少个tickTime的时间长度,总的时间长度就是5*2000=10秒。),Leader认为Follwer死掉,从服务器列表中删除Follwer。
在运行过程中,Leader负责与ZK集群中所有机器进行通信,例如通过一些心跳检测机制,来检测机器的存活状态。如果L发出心跳包在syncLimit之后,还没有从F那收到响应,那么就认为这个F已经不在线了。
<4>dataDir
dataDir:数据文件目录+数据持久化路径
保存内存数据库快照信息的位置,如果没有其他说明,更新的事务日志也保存到数据库。
<5>clientPort
clientPort:客户端连接端口,监听客户端连接的端口。
⑥启动Zookeeper服务之前需要先安装好Java环境
⑦开启服务器+客户端连接
开启/停止服务器:
/myzookeeper/zookeeper-3.4.9/bin路径下
客户端连接:
连接:./zkCli.sh
退出:quit
3.数据模型/znode节点
Zookeeper维护一个类似文件系统的数据结构
所使用的数据模型风格很像文件系统的目录树结构,简单来说,有点类似windows中注册表的结构,
有名称,
有树节点,
有Key(键)/Value(值)对的关系,
可以看做一个树形结构的数据库,分布在不同的机器上做名称管理。
3.1 初识znode节点
①ZooKeeper数据模型的结构与Unix文件系统很类似,整体上可以看作是一棵树,每个节点称做一个ZNode
②很显然zookeeper集群自身维护了一套数据结构。这个存储结构是一个树形结构,其上的每一个节点,我们称之为"znode",每一个znode默认能够存储1MB的数据,每个ZNode都可以通过其路径唯一标识
3.2 znode的数据模型
3.2.1 znode是什么
Znode维护了一个stat结构,这个stat包含数据变化的版本号、访问控制列表变化、还有时间戳。版本号和时间戳一起,可让Zookeeper验证缓存和协调更新。每次znode的数据发生了变化,版本号就增加。
例如,无论何时客户端检索数据,它也一起检索数据的版本号。并且当客户端执行更新或删除时,客户端必须提供他正在改变的znode的版本号。如果它提供的版本号和真实的数据版本号不一致,更新将会失败。
3.2.2 ZooKeeper的Stat结构体
①czxid- 引起这个znode创建的zxid,创建节点的事务的zxid(ZooKeeper Transaction Id)
每次修改ZooKeeper状态都会收到一个zxid形式的时间戳,也就是ZooKeeper事务ID。
事务ID是ZooKeeper中所有修改总的次序。每个修改都有唯一的zxid,如果zxid1小于zxid2,那么zxid1在zxid2之前发生。
②ctime - znode被创建的毫秒数(从1970年开始)
③mzxid - znode最后更新的zxid
④mtime - znode最后修改的毫秒数(从1970年开始)
⑤pZxid - znode最后更新的子节点zxid
⑥cversion - znode子节点变化号,znode子节点修改次数
⑦dataversion - znode数据变化号
⑧aclVersion - znode访问控制列表的变化号
⑨ephemeralOwner- 如果是临时节点,这个是znode拥有者的session id。如果不是临时节点则是0。
⑩dataLength - znode的数据长度
numChildren - znode子节点数量
3.2.3 小总结
①zookeeper内部维护了一套类似UNIX的树形数据结构:由znode构成的集合,
②znode的集合又是一个树形结构,
③每一个znode又有很多属性进行描述。 Znode = path + data + Stat
3.3 znode中的存在类型
3.3.1 PERSISTENT-持久化目录节点
客户端与zookeeper断开连接后,该节点依旧存在
3.3.2 PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点
客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
3.3.3 EPHEMERAL-临时目录节点
客户端与zookeeper断开连接后,该节点被删除
3.3.4 EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点
客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号
3.3.5 节点存在类型详解
znode是由客户端创建的,它和创建它的客户端的内在联系,决定了它的存在性:
PERSISTENT-持久化节点:创建这个节点的客户端在与zookeeper服务的连接断开后,这个节点也不会被删除(除非您使用API强制删除)。
PERSISTENT_SEQUENTIAL-持久化顺序编号节点:当客户端请求创建这个节点A后,zookeeper会根据parent-znode的zxid状态,为这个A节点编写一个全目录唯一的编号(这个编号只会一直增长)。当客户端与zookeeper服务的连接断开后,这个节点也不会被删除。
EPHEMERAL-临时目录节点:创建这个节点的客户端在与zookeeper服务的连接断开后,这个节点(还有涉及到的子节点)就会被删除。
EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点:当客户端请求创建这个节点A后,zookeeper会根据parent-znode的zxid状态,为这个A节点编写一个全目录唯一的编号(这个编号只会一直增长)。当创建这个节点的客户端与zookeeper服务的连接断开后,这个节点被删除。
另外,无论是EPHEMERAL还是EPHEMERAL_SEQUENTIAL节点类型,在zookeeper的client异常终止后,节点也会被删除。
4.基础命令和Java客户端操作
4.1 zkCli的常用命令操作
和redis的KV键值对类似,只不过key变成了一个路径节点值,v就是data。Zookeeper表现为一个分层的文件系统目录树结构,不同于文件系统之处在于:zk节点可以有自己的数据,而unix文件系统中的目录节点只有子节点。
一个节点对应一个应用/服务,节点存储的数据就是应用需要的配置信息。
①ls(使用 ls 命令来查看当前znode中所包含的内容)
②ls2(查看当前节点数据并能看到更新次数等数据)
③stat(查看节点状态)
④set(设置节点的具体值)
⑤get(获得节点的值)
⑥create
⑦delete(删除无子节点的目录)
⑧rmr(递归删除)
4.2 四字命令(了解)
zookeeper支持某些特定的四字命令,他们大多是用来查询ZK服务的当前状态及相关信息的,
通过telnet或nc向zookeeper提交相应命令,如:echo ruok | nc 127.0.0.1 2181
运行公式:echo 四字命令 | nc 主机IP zookeeper端口
通知机制
客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。
5.1 watch
5.1.1 watch是什么
ZooKeeper 支持watch(观察)的概念。客户端可以在每个znode结点上设置一个观察。如果被观察服务端的znode结点有变更,那么watch就会被触发,这个watch所属的客户端将接收到一个通知包被告知结点已经发生变化,把相应的事件通知给设置过Watcher的Client端。
Zookeeper里的所有读取操作:getData(),getChildren()和exists()都有设置watch的选项
总结来说就是:异步回调的触发机制
5.1.2 watch事件理解
①一次触发
-
当数据有了变化时zkserver向客户端发送一个watch,它是一次性的动作,即触发一次就不再有效,类似一次性纸杯。
-
只监控一次
-
如果想继续Watch的话,需要客户端重新设置Watcher。因此如果你得到一个watch事件且想在将来的变化得到通知,必须新设置另一个watch。
②发往客户端
-
Watches是异步发往客户端的,Zookeeper提供一个顺序保证:在看到watch事件之前绝不会看到变化,这样不同客户端看到的是一致性的顺序。
-
在(导致观察事件被触发的)修改操作的成功返回码到达客户端之前,事件可能在去往客户端的路上,但是可能不会到达客户端。观察事件是异步地发送给观察者(客户端)的。ZooKeeper会保证次序:在收到观察事件之前,客户端不会看到已经为之设置观察的节点的改动。网络延迟或者其他因素可能会让不同的客户端在不同的时间收到观察事件和更新操作的返回码。这里的要点是:不同客户端看到的事情都有一致的次序。
③为数据设置watch
-
节点有不同的改动方式。可以认为ZooKeeper维护两个观察列表:**数据观察和子节点观察。**getData()和exists()设置数据观察。getChildren()设置子节点观察。此外,还可以认为不同的返回数据有不同的观察。getData()和exists()返回节点的数据,而getChildren()返回子节点列表。所以,setData()将为znode触发数据观察。成功的create()将为新创建的节点触发数据观察,为其父节点触发子节点观察。成功的delete()将会为被删除的节点触发数据观察以及子节点观察(因为节点不能再有子节点了),为其父节点触发子节点观察。
-
观察维护在客户端连接到的ZooKeeper服 务器中。这让观察的设置、维护和分发是轻量级的。客户端连接到新的服务器时,所有会话事件将被触发。同服务器断开连接期间不会收到观察。客户端重新连接 时,如果需要,先前已经注册的观察将被重新注册和触发。通常这都是透明的。有一种情况下观察事件将丢失:对还没有创建的节点设置存在观察,而在断开连接期 间创建节点,然后删除。
④时序性和一致性
-
Watches是在client连接到Zookeeper服务端的本地维护,这可让watches成为轻量的,可维护的和派发的。当一个client连接到新server,watch将会触发任何session事件,断开连接后不能接收到。当客户端重连,先前注册的watches将会被重新注册并触发。
-
关于watches,Zookeeper维护这些保证:
(1)Watches和其他事件、watches和异步恢复都是有序的。Zookeeper客户端保证每件事都是有序派发
(2)客户端在看到新数据之前先看到watch事件
(3)对应更新顺序的watches事件顺序由Zookeeper服务所见