zookeeper简述
介绍
从本质上来说,Zookeeper就是一种分布式协调服务,在分布式环境中协调和管理服务是一个复杂的过程。
ZooKeeper的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。
Zookeeper提供服务主要就是通过:数据结构+原语集+watcher机制到达的。
分布式应用程序结合Zookeeper可以实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。
重要概念
ZooKeeper本身就是一个分布式程序(只要半数以上节点存活,ZooKeeper就能正常服务)。
ZooKeeper将数据保存在内存中,这也就保证了 高吞吐量和低延迟(但是内存限制了能够存储的容量不太大,此限制也是保持znode中存储的数据量较小的进一步原因)。
ZooKeeper是高性能的。 在“读”多于“写”的应用程序中尤其地高性能,因为“写”会导致所有的服务器间同步状态。(“读”多于“写”是协调服务的典型场景。)
ZooKeeper有临时节点的概念。 当创建临时节点的客户端会话一直保持活动,瞬时节点就一直存在。而当会话终结时,瞬时节点被删除。持久节点是指一旦这个ZNode被创建了,除非主动进行ZNode的移除操作,否则这个ZNode将一直保存在Zookeeper上。
ZooKeeper 底层其实只提供了两个功能:①管理(存储、读取)用户程序提交的数据;②为用户程序提交数据节点监听服务。
特性
- 顺序一致性:从同一个客户端发起的事务请求,最终将会严格按照其发起顺序被应用到ZooKeeper中。
- 原子性:所有事务请求的结果在集群中所有机器上的应用情况是一致的,也就是说要么整个集群所有集群都成功应用了某一个事务,要么都没有应用,一定不会出现集群中部分机器应用了该事务,而另外一部分没有应用的情况。
- 单一视图:无论客户端连接的是哪个ZooKeeper服务器,其看到的服务端数据模型都是一致的。
- 可靠性:一旦服务端成功地应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会被一直保留下来,除非有另一个事务又对其进行了变更。
- 实时性:通常人们看到实时性的第一反应是,一旦一个事务被成功应用,那么客户端能够立即从服务端上读取到这个事务变更后的最新数据状态。这里需要注意的是,ZooKeeper仅仅保证在一定的时间段内,客户端最终一定能够从服务端上读取到最新的数据状态。
顺序一致性是通过ZXid来实现的,全局唯一,顺序递增,同一个session中请求是FIFO的;一次事务的应用,服务端状态的变更会以Zxid、Znode数据版本、数据、节点路径的形式保存下来。
zk数据模型(ZNode)
zookeeper的数据模型和Unix的文件系统目录树很类似,拥有一个层次的命名空间。这里面的每一个节点都称为ZNode,节点可以拥有子节点,同时也允许少量数据节点存储在该节点之下。
节点引用方式
ZNode通过路径引用,如同Unix的文件路径。路径必须是要绝对的,因此他们必须有斜杠字符/来开头,除此之外,路径名必须是唯一的,且不能更改。
在dubbo的服务注册上,dubbo中有一个贯穿全局的URL类,dubbo中所有的配置信息都被存放在URL中传递,dubbo向注册中心注册时写下的节点名就是由URL中的URI和配置信息编码后组成的。
ZNode结构
ZNode兼具目录和文件两种特性,既像文件一样维护者数据,元信息,ACL,时间戳等数据结构,又像目录一样可以作为路径标识的一部分。
ZNode由一下及部分组成:
- Stat数据结构
- 操作控制表(ACL)-每个节点都有一个ACL来做节点的操作控制,这个列表规定了用户的权限,限定了特定用户对目标节点的操作。
- create:创建子节点的权限。
- read:获取子节点数据和子节点列表的权限。
- write:更新节点数据的权限。
- delete:删除子节点的权限。
- admin:设置节点ACL的权限。
- 版本-ZNode有三个数据版本
- version:当前ZNode的版本。
- cversion:当前ZNode子节点的版本。
- aversion:当前ACL列表的版本。
- Zxid
- 可以理解成Zookeeper中时间戳的一种表现形式,也可以理解成事务ID的概念。
- 如果Zxid1的值小于Zxid2的值,那么Zxid1所对应的事件发生在Zxid2所对应的事件之前。
- ZooKeeper的每个节点维护者三个Zxid值,分别为:cZxid、mZxid、pZxid。
- cZxid:节点创建时间。
- mZxid:节点最近一次修改时间。
- pZxid:该节点的子节点列表最后一次被修改时的时间,子节点内容变更不会变更pZxid。
- 操作控制表(ACL)-每个节点都有一个ACL来做节点的操作控制,这个列表规定了用户的权限,限定了特定用户对目标节点的操作。
- data域
- children节点
data域
Zookeeper中每个节点存储的数据要被原子性的操作,也就是说读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。
Zookeeper虽然可以存储数据,但是并不是为了做数据库或者大数据存储,相反,它是用来管理调度数据,比如分布式应用中的配置文件信息、状态信息、汇集位置等,这些数据通常是很小的数据,KB为大小单位。ZNode对数据大小也有限制,至多1M。实际上从这里,就可以推导出Zookeeper用于分布式配置中心的可行性。
Zxid
在Zookeeper中,能改变Zookeeper服务器状态的操作称为事务操作。一般包括数据节点创建,更新,删除和客户端会话创建与失效等操作。对每一个事务操作,Zookeeper都会为其分配唯一的全局事务ID,就是Zxid。
Zxid是一个64位的数字。前32位叫做epoch,用来标识Zookeeper 集群中的Leader节点,当Leader节点更换时,就会有一个新的epoch。后32位则为递增序列。从这些Zxid中可以间接地识别出ZooKeeper处理这些事务操作请求的全局顺序。
节点类型
ZNode有四种节点类型:持久节点,临时节点,持久顺序节点,临时顺序节点。
- 持久节点:该节点的生命周期不依赖于session,创建之后客户端断开连接,节点依旧存在,只用客户端执行删除操作,节点才能被删除。
- 临时节点:该节点的声明周期依赖于session,客户端断开连接,临时节点就会自动删除。另外,临时节点不允许有子节点。
- 顺序节点:当选择创建顺序节点时,ZooKeeper通过将10位的序列号附加到原始名称来设置znode的路径。顺序节点在锁定和同步中起重要作用。
Watches
Watches,监听事件,是zookeeper中很重要的一个特性。允许用户在指定节点上注册一些Watcher,并在某些特定事件触发的时候,Zookeeper服务端会将事件异步通知到监听了的客户端上去。
Znode修改是与znode相关的数据的修改或znode的子项中的更改。只触发一次watches。如果客户端想要再次通知,则必须通过另一个读取操作来完成。当连接会话过期时,客户端将与服务器断开连接,相关的watches也将被删除。
分类
- 数据监听器
- 子节点监听器
特点
- 一次性,一个watcher只会被通知一次,被通知过后会立即删除,如果节点再次改变,则不会收到通知,除非重新设置了watcher。
- 有序性:当监听的对象发生改变时,将会触发watch对应的事件,事件则被异步的发送到客户端,客户端收到watcher通知后才能查看变化结果。
时机
- setData将触发ZNode的数据watche。
- create和delete操作将触发ZNode的数据watch和子节点watch。
会话(Session)
Session指的是Zookeeper服务端与客户端之间的会话。
在Zookeeper中,一个客户端连接指的是客户端和服务器之间的一个TCP长连接。
客户端启动的时候,首先会与服务器建立一个TCP连接,从第一次连接建立开始,客户端会话的生命周期也开始了。通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向Zookeeper服务器发送请求并接受响应,同时还能够通过该连接接收来自服务器的Watch事件通知。
客户端以特定的时间间隔发送心跳以保持会话有效,如果ZooKeeper Server Ensembles在超过服务器开启时指定的期间(会话超时)都没有从客户端接收到心跳,则它会判定客户端死机。会话超时通常以毫秒为单位。当会话由于任何原因结束时,在该会话期间创建的临时节点也会被删除。
Session的sessionTimeout值用来设置一个客户端会话的超时时间。当由于服务器压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,只要在sessionTimeout规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。
在为客户端创建会话之前,服务端首先会为每个客户端都分配一个sessionID。由于 sessionID 是 Zookeeper 会话的一个重要标识,许多与会话相关的运行机制都是基于这个 sessionID 的,因此,无论是哪台服务器为客户端分配的 sessionID,都务必保证全局唯一。