zookeeper类似一个分布式的文件系统,每个节点可以有和它自身或它的子节点相关联的数据,此外指向节点的路劲必须使用绝对路径(不能使用相对路劲);
Znode
对应目录树中的的一个节点,并拥有一些属性信息(版本号、时间戳等),每当Znode数据改变时它相应的版本号就会增加;
属性结构说明:
czxid:节点被创建的Zxid值(Zxid为时间戳格式)
mzxid:节点被修改的Zxid值;
ctime:节点被创建的时间;
mtime:节点最后一次的修改时间;
version:节点被修改的版本号;
cversion:节点所拥有的子节点被修改的版本号;
aversion:节点的ACL被修改的版本号;
dataLength:节点数据域的长度;
numChildren:节点拥有的子节点个数;
emphemeralOwner:如果此节点为临时节点,那么他的值为这个节点拥有者的会话ID;否则,它的值为0;
特点:
1、znode 可以有子节点目录,并且每个 znode 可以存储数据,注意 EPHEMERAL 类型的目录节点不能有子节点目录;
2、znode 是有版本的,每个 znode 中存储的数据可以有多个版本,也就是一个访问路径中可以存储多份数据;
3、znode 可以是临时节点,一旦创建这个 znode 的客户端与服务器失去联系,这个 znode 也将自动删除,Zookeeper 的客户端和服务器通信采用长连接方式,每个客户端和服务器通过心跳来保持连接,这个连接状态称为 session,如果 znode 是临时节点,这个 session 失效,znode 就会被删除;
4、znode 的目录名可以自动编号;
5、znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端;
Zookeeper服务与客户端交互
客户端应用程序创建Zookeeper实例,与Zookeeper服务建立起连接,Zookeeper系统将会给此连接会话分配一个ID值,并且客户端会周期性的向服务器发送心跳来维持会话的连接,只要连接有效,客户端还可通过Zookpeeper API来进行相应的处理;
zookeeper系统机构图:
常用方法说明
1、String create(String path,byte[] data,List<ACL> acl,CreateMode createMode)
功能说明:
a、根据path创建目录节点,该节点的数据域初始值为data;
b、acl:目录分别由perms和id两部分组成,Perms标识权限,有ALL、READ、WRITE、CREATE、DELETE、ADMIN六种;id标识访问目录的身份列表,有ANYONE_ID_UNSAFE、AUTH_IDS两种,分别表示任何人都可以访问和仅创建者有权限访问;常用的ACL有OPEN_ACL_UNSAFE、CREATOR_ALL_ACL、READ_ACL_UNSAFE三种,定义在ZooDefs中,
c、createMode:分别有四种表现形式PERSISTENT:持久的目录节点;EPHEMERAL:临时目录节点,当创建该节点的客户端与服务端连接超时或断开,该节点将自动删除;PERSISTENT_SEQUENTIAL:顺序自动编号的目录节点,根据当前已经存在的节点数自动加1;EPHEMERAL_SEQUENTIAL:临时自动编号节点;
2、State exists(String path,boolean wach)
功能说明:
根据path判断目录节点是否存在,可通过watch控制是否监听;
3、void delete (String path,int version)
功能说明:
根据目录节点路径path及版本信息version,删除对应的目录节点,当version为-1时将删除该节点所有数据;
4、List<String> getChildren(String path,boolean watch)
功能说明:
获取path下的所有子目录节点;
5、State setData(String path,byte[] data,int version)
功能说明:
根据path及version设置节点的数据域为data,当version为-1时将匹配任何版本;
6、byte[] getData(String path,boolean watch,Stat stat)
功能说明:
获取节点数据(path表示目录节点路径,stat标识数据的版本信息,watch用来控制是否设置监控);
7、void addAuthInfo(String scheme,byte[] auth)
功能说明:
客户端将自己的授权信息提交给服务器,服务器将根据这个授权信息验证客户端的访问权限;
8、Stat setAcl(String path,List<ACL> acl,int version)
功能说明:
给path表示的目录节点设置访问权限(注: Zookeeper 中的目录节点权限不具有传递性,父目录节点的权限不能传递给子目录节点);
9、List<ACL> getACL(String path,Stat stat)
功能说明:
获取path表示的目录节点的访问权限列表;
写操作与zookeeper内部事件对应关系
zookeeper内部事件与watch的对应关系
写操作与watch对应关系
Zookeeper应用场景
1、配置管理
在分布式应用中,存在一些公共配置,每台机器都需要加载,若单独部署在每台机器,那么对配置文件变动维护会比较繁琐,而且容易出现不一致的情况,采用zookeeper进行统一配置管理后,将有效的解决该问题;
配置管理结构图:
说明:
图中的每个client代表一台电脑,而且都对zookeeper中的/configuration目录进行监控,当/configuration节点的数据域产生变化时,所有的client都将会收到通知进行同步;
2、集群管理
以zookeeper来实现集群的管理方式如下图所示,集群中的每台机器在/GroupMenbers(EPHEMERAL类型)节点目录下,都会建立一个对应clienti(EPHEMERAL_SEQUENTIAL类型)子节点,并在/GroupMenbers节点上设置监控getChildren,当创建它的集群节点挂了,这个目录节点也随之被删除,所以 Children 将会变化,这时 getChildren上的 Watch 将会被调用,所以其它 集群节点 就知道。新增集群节点实现同理。
选举功能(Leader Election)的实现,在zookeeper中的每个server中创建一个EPHEMERAL_SEQUENTIAL目录节点,之所以它是 EPHEMERAL_SEQUENTIAL 目录节点,是因为我们可以给每台 Server 编号,我们可以选择当前是最小编号的 Server 为 Master,假如这个最小编号的 几圈死去,由于是 EPHEMERAL 节点,死去的 Server 对应的节点也被删除,所以当前的节点列表中又出现一个最小编号的节点,我们就选择这个节点为当前 Master。这样就实现了动态选择 Master,避免了传统意义上单 Master 容易出现单点故障的问题。
集群管理结构图
3、共享锁
实现方式:在需要获得锁的 Server 创建一个 EPHEMERAL_SEQUENTIAL 目录节点,然后调用 getChildren方法获取当前的目录节点列表中最小的目录节点是不是就是自己创建的目录节点,如果正是自己创建的,那么它就获得了这个锁,如果不是那么它就调用 exists(String path, boolean watch) 方法并监控 Zookeeper 上目录节点列表的变化,一直到自己创建的节点是列表中最小编号的目录节点,从而获得锁,释放锁很简单,只要删除前面它自己所创建的目录节点就行了。
流程图
4、队列
定义:当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达;
实现思路:
创建一个父目录 /synchronizing,每个成员都监控标志(Set Watch)位目录 /synchronizing/start 是否存在,然后每个成员都加入这个队列,加入队列的方式就是创建 /synchronizing/member_i 的临时目录节点,然后每个成员获取 / synchronizing 目录的所有目录节点,也就是 member_i。判断 i 的值是否已经是成员的个数,如果小于成员个数等待 /synchronizing/start 的出现,如果已经相等就创建 /synchronizing/start。
同步队列流程图
FIFO 队列实现思路:
在特定的目录下创建 SEQUENTIAL 类型的子目录 /queue_i,这样就能保证所有成员加入队列时都是有编号的,出队列时通过 getChildren( ) 方法可以返回当前所有的队列中的元素,然后消费其中最小的一个,这样就能保证 FIFO