JAVA编程访问Zookeeper

1、依赖类库

在JAVA程序中调用Zookeeper时,首先需要引入Zookeeper类库:

 zookeeper-3.4.9.jar

由于Zookeeper使用了SLF4J来做Log4J的日志,因此还需要引入:

 slf4j-api-1.6.1.jar

 log4j-1.2.16.jar

 slf4j-log4j12-1.6.1.jar  (SFL4j对Log4j的使用)

2、访问会话

2.1、创建会话

调用Zookeeper首先需要先建立Zookeeper的会话,用于关联到具体的Zookeeper服务器和znode路径下:

有四种构造器方式可以建立会话:

ZooKeeper(String connectString,int sessionTimeout,Watcher watcher)

ZooKeeper(String connectString,int sessionTimeout,Watcher watcher,

        boolean canBeReadOnly)

ZooKeeper(String connectString,int sessionTimeout,Watcher watcher,

        long sessionId,byte[] sessionPasswd)

ZooKeeper(String connectString,int sessionTimeout,Watcher watcher,

        long sessionId,byte[] sessionPasswd,boolean canBeReadOnly)

参数含义:

connectString : 当前会话关联的最后一级znode,关联后,在当前会话过程中,将能够访问该节点以及其子节点,而不能访问该节点的上级节点和旁系节点,该节点可以视作是当前会话的根节点。

连接字符串的结构为:

connectString ::= {hostname:port ,…} [/znode]

例如:

连接到znode节点/myTest/testA,则该链接为:

“myA.zookeeper.test:2181, myB.zookeeper.test:2181/myTest/testA“

连接后,本次会话将近能够访问/myTest/testA及其子节点,zookeeper首先会检测第一个分隔符“/”,并获取前面的主机列表,然后再用分隔符“,“分割获取每一台主机。

sessionTimeout : 会话的超时时间,按照毫秒为单位进行计算,设置好会话时间后,可以在任意时刻,通过如下方法得到该时间:

public int getSessionTimeout()

watcher : 默认的观察者对象接口,该接口的实例将会被注册为本次会话内全局缺省的观察者对象;并且该观察者对象可以在任意时刻,通过如下方法将其覆盖:

public void register(Watcher watcher)

sessionId / sessionPasswd:组合此两个参数,可以在客户端结束当前会话后,继续恢复刚刚离开的那个会话,自需记住上一次的会话信息即可,可以通过如下两个方法在某一次会话过程中来获取:

public long getSessionId()

public byte[] getSessionPasswd()

canBeReadOnly:设置当前会话的客户端是否可以在其链接的服务器与集群中多数服务器失去联系,并停止处理客户端的读写请求时,仍然能够获得该服务器只读请求的响应

创建会话示例:

创建一个观察者,实现Watcher接口,并将其作为缺省观察者对象来创建一个Zookeeper客户端,并开启一个会话环境。

public class TestWatcher implements Watcher {

        @Override

        public void process(WatchedEvent event) {

                if (KeeperState.SyncConnected == event.getState()) { …  }

        } }

创建会话,以myTest作为当前会话的根节点,同时传入默认的观察者

public static void main(String[] args) {

        TestWatcher watcher = new TestWatcher();

        Zookeeper zookeeper = new Zookeeper(“192.168.1.200:2181/myTest”, 5000 , watcher);

}

2.2、结束会话

可以在某一个会话过程中,通过如下方法来结束本次会话:

public void close()

会话结束时,所有当前会话与Zookeeper关联的临时类型znode节点将会被全部删除,同时还会触发在这些节点上的所有观察者执行其process()方法。

3、访问节点

3.1、创建节点

创建节点有两种方式,一种是同步方式创建节点,并返回创建好的节点的路径名称,另一种方式是以异步的方式创建节点,然后通过回调接口方法的参数返回创建好的路径名称:

同步创建节点:

public String create(String path,byte[] data,Listacl,CreateMode createMode) throws KeeperException,InterruptedException

异步创建节点:

public void create(String path,byte[] data,Listacl,CreateMode createMode,AsyncCallback.StringCallback cb,Object ctx)

参数含义:

path : 将要创建的节点名称,该名称是预计要创建的znode节点的名称,但不一定是最终被创建的名称,该节点的最终名称还取决于CreateMode。

path会自动与创建会话时指定的connectString组合在一起来最终确认当前结点在Zookeeper中的具体位置。

data:将要写入该节点的具体数据

acl : 权限控制列表,可以从预定义的Ids接口中选择一项,通常对于不做权限要求的创建来说,可以选择值Ids.OPEN_ACL_UNSAFE(见第五章),代表不做权限限制。

createMode : 创建模式,存在四个值,分别代表创建的znode是临时的、临时且带序号的、持久的、持久且带序号的四种类型,若为带序号的模式,则在创建节点时,将会在path的结尾添加一个顺序的序号,值定义如下:

EPHEMERAL : 临时模式

EPHEMERAL_SEQUENTIAL:临时且带序号模式

PERSISTENT:持久模式

PERSISTENT_SEQUENTIAL:持久且带序号模式

cb / ctx : 组合此两个参数,可以设定在异步方式下,系统回调的参数及处理,其中,cb是一种AsyncCallback.StringCallback 类型的接口,该接口用于当节点完成创建后,对执行结果等进行查看和处理,ctx是将要传入回调接口中的任意对象,该对象可用于在主线程和异步调用的接口对象之间传递信息。

创建节点示例:

创建一个回调接口的实现,然后异步方式创建节点,并将CreateInfo信息传入回调接口中。

public class CreateDo implements AsyncCallback.StringCallback{   

        @Overridepublic void processResult(int rc, String path, Object ctx, String name) {   

                if(rc == 0){       

                        System.out.println((CreateInfo)ctx.getMyName());   

                }

        }

}

public class CreateInfo{

        private String myName;

        …

}

开始创建节点

public static void main(String[] args) {   

        TestWatcher watcher = new TestWatcher();

        Zookeeper zookeeper = new Zookeeper(“192.168.1.200:2181/myTest”, 5000 , watcher);

        byte[] data = “这是一个新的节点”.getBytes();

        CreateDo createDo = new CreateDo();

        CreateInfo createInfo = new CreateInfo();

        //创建一个临时的节点

        zookeeper.create(“/nodeAA” , data, Ids.OPEN_ACL_UNSAFE,

                CreateMode.EPHEMERAL, createDo, createInfo);

}

应用:

若当前需要创建的节点已经存在,则创建会不成功,在同步模式下,将会抛出KeeperException异常(NodeExistsException),而在异步方式下,将会通过回调方法的第一个参数rc返回一个值,若为0,则成功创建,-110代表当前结点已存在(返回码见第五章返回状态码一节)。

zookeeper集群的一致性将会保证,所有创建同一个名称节点的用户,一定会有唯一的一个用户能够成功创建这个节点,其他的用户都会返回节点已存在的错误码或异常。因此,凡是遇到在集群中,多个用户同时抢占同一个资源的情况,都可以通过此特性来获得支持,比如下列一些场景:

分布式锁:

可以利用此特点,将某个临时性节点作为一个分布式的锁,一旦该节点被创建,则认为已经挂锁,需要将该节点删除才能解锁,删除的方式有两种,一种是创建该节点的客户端挂了,另一种是该客户端主动删除。

所有其他用户检测到这个锁后,可以对其进行监听(Watch)(需要结合exists方法,见下节),一旦该锁被解开(删除),则所有节点都可以收到消息,从而进行下一轮抢占挂锁过程。

主备切换:

在某些场景下,若需要在多个用户中任意选择出一个领导者的情况时,可以通过大家抢占创建同一个名称的节点,则最后创建了该节点的用户就可以作为领导者,比如做为主备的服务器群,其中通过选举出一个服务器作为主服务器来执行服务,其他服务器作为备用服务器监听主服务器的状态,一旦主服务器工作不正常挂掉了,则其他服务器可以马上通过选举一个新领导者来代替主服务器执行服务器;可以和节点监听方法结合使用(见下节)。

3.2、监听节点

可以在任一时刻对某个znode节点进行检查,无论该节点是否存在,并同时可以针对这个节点注册一个监听器,随时通过监听方法的参数event监听该节点的各种变化:

被监控节点被创建:event.getType() == EventType.NodeCreated

被监控节点被删除:event.getType() == EventType.NodeDeleted

被监控节点的子节点被修改:event.getType() == EventType.NodeChildrenChanged

被监控节点的数据被修改:event.getType() == EventType.NodeDataChanged

存在两种同步方法用于创建节点,区别是一个使用指定的观察者对象,另一个是使用当前会话默认的观察者对象:

public Stat exists(String path,Watcher watcher) throws KeeperException,InterruptedException

public Stat exists(String path,boolean watch) throws KeeperException,InterruptedException

同样存在两种异步方法用于创建节点,区别同样是一个使用指定的观察者对象,另一个使用当前会话默认的观察者对象:

public void exists(String path,Watcher watcher,AsyncCallback.StatCallback cb,Object ctx)public void exists(String path,boolean watch,AsyncCallback.StatCallback cb,Object ctx)

对于同步方法也可以仅仅用于判断当前的节点状态,而不进行监听。

参数含义:

path : 监控的节点名称,path会自动与创建会话时指定的connectString组合在一起来最终确认当前结点在Zookeeper中的具体位置。

watcher / watch : 指定的观察者对象,若期望使用会话默认的观察者,则此处使用布尔类型的watch设置为true来指定;当监听的节点出现变更,将会触发观察者对象来执行相应的操作;所有观察者都是一次性观察,当其被触发通知并执行相应处理后,该次观察将失效,需要重新指定观察者。

AsyncCallback.StatCallback : 异步监控执行后,进行回调通知的接口(具体参见第三章),该回调接口不可用于监听状态变化,仅仅是用处理节点监听语句执行后的状态,比如是否监听成功、网络是否正常、服务器是否返回什么错误之类的。

ctx : 用于在进行监控初始时,向回调方法传送一个对象,可以传递任意的信息,用于在回调时使用。

监听节点示例:

创建一个自定义监听器,并当节点状态改变时打印当前情况,然后继续监听

public class NodeListener implements Watcher {   

        public static NodeListening nodeListener = new NodeListening();

        private Zookeeper zookeeper;

        private String node;

        public void init(Zookeeper zookeeper, String node){…}   

        @Overridepublic void process(WatchedEvent event) {   

                if(event.getState() == KeeperState. SyncConnected){       

                        if(event.getType() == EventType.NodeCreated){           

                                System.out.println(“节点被创建”);           

                                this.zookeeper.exists(this.path, NodeListener.nodeListener);       

                        } else if(event.getType() == EventType. NodeDeleted){           

                                System.out.println(“节点被删除”);         

                                this.zookeeper.exists(this.path, NodeListener.nodeListener);       

                        } else if(event.getType() == EventType. NodeChildrenChanged){           

                                System.out.println(“子节点被修改”);           

                                this.zookeeper.exists(this.path, NodeListener.nodeListener);       

                        } else if(event.getType() == EventType. NodeDataChanged){           

                                System.out.println(“节点数据被更新”);           

                                this.zookeeper.exists(this.path, NodeListener.nodeListener);       

                        }   

                }

        }

}

开始启动监听:

public static void main(String[] args) {   

        …

        //初始化监听器

        NodeListener.nodeListener.init(zookeeper, “/nodeAA”);

        zookeeper.exixts(“/nodeAA”, NodeListener.nodeListener);

        …

}

被监听的节点“/nodeAA”此时可以不存在,exists方法执行后,可以继续执行其他方法,此时一旦节点“/nodeAA”发生变化,则将会触发系统内另一个内部线程开始执行监听者的process方法,实现监听处理的目的。

应用:

zookeeper允许在没有节点存在时,任意指定一个节点名称进行监听,也可以在节点或者其数据内容或者其子节点发生变化时及时通知监听者,因此,所有需要根据某一个点的状态改变而进行处理的场景,都可以使用此方式来实现,比如下列一些场景:

分布式锁:

可以利用此特点,对某个节点进行监控,一旦该节点被创建,则可以及时通知所有正在抢锁的用户不用再抢了,并进行监听是否开锁,一旦开锁并获得监听通知,可以重新进行抢锁。

主备切换:

可以和创建节点方法结合使用,所有备份服务器都同时监听主工作服务器的状态,一旦主服务器瘫痪,其节点被删除,则所有备份服务器都能感知到该节点被删除,此时个备份服务器可以再次发起选举主服务器的过程。主备切换时,还需要考虑“脑裂”的情况,并进行处理。

配置更新:

可以将集群中所有服务器共有的配置放到一个znode下,然后所有服务器都监听该节点,一旦该节点的数据发生变更,则所有服务器注册到该节点的观察者都将会被通知,这样每台服务器都可以重新获取配置信息,而不会出现配置信息不一致的情况发生(具体获取节点数据的内容见第四章),同样也可以通过获取节点数据时设置监听,将和本方法起到相同效果。

远程监控:

集群中每一台服务器都可以创建一个客户端,并在某个指定路径下关联并创建一个临时的节点,代表当前服务器加入远程监控环境,同时不断将自身的状态信息写入该节点。

监控终端可以针对每一台服务器节点进行监控,并获的这些节点的所有变化情况,包括节点中保存的服务器状态信息的所有更新情况,从而了解这台服务器及时信息情况。监控终端也可以监控这些服务器对应节点的父级节点来跟踪是否集群中有服务器发生变化等,并可以获得这些服务器节点的清单(见获取子节点一节)通过此种方式,可以有效地将监控终端与每台服务器进行解耦,同时有效地避免了监控终端的单点故障。

3.3、节点删除

可以在任一时刻,通过如下方法将某个节点删除,与创建节点相似,删除操作也分为同步和异步两种方式:

同步删除节点:

public void delete(String path,int version)throws InterruptedException,KeeperException

异步删除节点:

public void delete(String path,int version,AsyncCallback.VoidCallback cb,Object ctx)

参数含义:

path : 将要删除的节点名称,path会自动与创建会话时指定的connectString组合在一起来最终确认当前结点在Zookeeper中的具体位置。

version:版本是指当前将要删除的版本,若不考虑版本问题,可以取值 -1,若设置了具体的值,则该值若与具体的节点的version值不相同,则将会删除失败。此处节点的版本就是节点最后一次被修改的累计次数,每次针对该节点的修改,版本号通常都会增加,这样有效回避了某个用户对节点修改后,并对其进行删除之前,有其他用户也对该节点进行了修改,此时删除时就能够发现当前节点已经被他人改过,不能够删除了。

AsyncCallback.VoidCallback : 异步监控执行后,进行回调通知的接口(具体参见第三章),该回调接口不可用于监听状态变化,仅仅是用处理节点监听语句执行后的状态,比如是否监听成功、网络是否正常、服务器是否返回什么错误之类的。

ctx : 用于在进行监控初始时,向回调方法传送一个对象,可以传递任意的信息,用于在回调时使用。

删除节点示例:

删除节点“/nodeAA”,不考虑该节点是否被其他用户修改过:

public static void main(String[] args) {   

        …

        //开始删除

        zookeeper.delete(“/nodeAA”, -1);

        …

}

3.4、获得子节点

从已知的某个节点获得其包含的所有子节点,有八种方式来获得子节点。同步获得子节点有四种方式,其区别主要在于设置观察者和获得执行状态的不同。

public ListgetChildren(String path,boolean watch)

        throws KeeperException,InterruptedException

public ListgetChildren(String path,boolean watch,Stat stat)

        throws KeeperException,InterruptedException

public ListgetChildren(String path,Watcher watcher)

        throws KeeperException,InterruptedException

public ListgetChildren(String path,Watcher watcher,Stat stat)

        throws KeeperException,InterruptedException

异步获得子节点也有四种方式,其区别同样在于设置观察者和获得执行状态的不同。

public void getChildren(String path,boolean watch,

        AsyncCallback.Children2Callback cb,Object ctx)

public void getChildren(String path,boolean watch,

        AsyncCallback.ChildrenCallback cb,Object ctx)

public void getChildren(String path,Watcher watcher,

        AsyncCallback.Children2Callback cb,Object ctx)

public void getChildren(String path,Watcher watcher,

        AsyncCallback.ChildrenCallback cb,Object ctx)

参数含义:

path : 将要获得子节点的节点名称,path会自动与创建会话时指定的connectString组合在一起来最终确认当前结点在Zookeeper中的具体位置。

watcher / watch : 指定的观察者对象,若期望使用会话默认的观察者,则此处使用布尔类型的watch设置为true来指定;

当节点被删除,或者子节点发生删除或者新增的情况时,将会触发并通知观察者;所有观察者都是一次性观察,当其被触发通知并执行相应处理后,该次观察将失效,需要重新指定观察者。

stat : 当前方法的执行结果状态,以及服务器返回的各种执行后信息,有两种方式来获得,一种是通过同步方法传入Stat对象,并装在执行信息,另一种是通过异步方式,将执行状态封装成Stat对象,并通过AsyncCallback.Children2Callback回调接口的参数获传入回调接口的实现者中。

AsyncCallback.Children2Callback/AsyncCallback.ChildrenCallback : 两种回调接口的区别是,AsyncCallback.Children2Callback回调接口的方法参数中,多传入一个Stat对象来带入当前执行的状态,而AsyncCallback.ChildrenCallback回调接口中得不到执行状态。

ctx : 用于在方法执行时,向回调方法传送一个对象,可以传递任意的信息,用于在回调时使用。获取节点示例:使用默认观察者,获取节点“/nodeAA”下的所有子节点:

public static void main(String[] args) {   

        …

        //获取子节点

        List<String> childrens = zooKeeper.getChildren(“/nodeAA”, true);

        …

}

应用:

当获取了某个节点的子节点后,通过注册一个观察者,若该节点被删除或者字节点内容发生变更,则会触发观察者,可以重新更新子节点的列表,因此,所有针对一组登记记录,其中任何记录发生变化,都会导致所有获得这组记录的用户得到通知,比如下列一些场景:

负载均衡:

负载均衡设备分派具体的执行服务器地址时,可以维护一张所有可用服务器的清单,然后向这些服务器了解情况,并分派压力,若某台服务器出现故障,或者增加了新的服务器,则会直接触发调度服务器获得服务器列表更新的通知,从而使调度服务器能够更有效地分派及转发请求等。

4、访问数据

4.1、获取节点数据

当关联到某个节点时,获取节点数据有两种方式,一种是同步方式获取节点数据,并以字节数组方式返回数据信息,另一种方式是以异步的方式获取节点数据,然后通过回调接口方法的参数返回节点数据:

同步获取节点数据

public byte[] getData(String path,boolean watch,Stat stat)

        throws KeeperException,InterruptedException

public byte[] getData(String path,Watcher watcher,Stat stat)

        throws KeeperException,InterruptedException

异步获取节点数据

public void getData(String path,boolean watch,AsyncCallback.DataCallback cb,Object ctx)

public void getData(String path,Watcher watcher,AsyncCallback.DataCallback cb,Object ctx)

参数含义:

path : 将要获取数据的节点名称,path会自动与创建会话时指定的connectString组合在一起来最终确认当前结点在Zookeeper中的具体位置。

watcher / watch : 指定的观察者对象,若期望使用会话默认的观察者,则此处使用布尔类型的watch设置为true来指定;当节点数据内容发生变更,或者节点被删除时,将会触发并通知观察者;所有观察者都是一次性观察,当其被触发通知并执行相应处理后,该次观察将失效,需要重新指定观察者。

stat : 当前方法的执行结果状态,以及服务器返回的各种执行后信息,有两种方式来获得,一种是通过同步方法传入Stat对象,并装在执行信息,另一种是通过异步方式,将执行状态封装成Stat对象,并通过AsyncCallback.DataCallback回调接口的参数获传入回调接口的实现者中。

应用:

获取节点的数据能够保持最新,并且能够感知该数据是否发生变化,一旦发生变化,则可及时更新最新的数据。

配置更新:

可以将集群中所有服务器共有的配置放到一个znode下,然后所有服务器都从该节点获取配置,并设置观察者;一旦该节点的数据发生变更,则所有服务器注册到该节点的观察者都将会被通知,这样每台服务器都可以重新获取配置信息,而不会出现配置信息不一致的情况发生。

4.2、修改节点数据

节点在创建时,就需要为其初始化一些数据,这些数据可以被修改,有两种方式可以修改一个节点的数据,一种是同步方式修改,另一种方式是以异步的方式修改,然后通过回调接口方法的参数返回结果:

同步修改节点数据:

public Stat setData(String path,byte[] data,int version)

        throws KeeperException,InterruptedException

异步修改节点数据:

public void setData(String path,byte[] data,int version,

        AsyncCallback.StatCallback cb,Object ctx)

参数含义:

path : 将要获取数据的节点名称,path会自动与创建会话时指定的connectString组合在一起来最终确认当前结点在Zookeeper中的具体位置。

data:将要更新到该节点的具体数据

version:版本是指当前将要修改的版本,若不考虑版本问题,可以取值 -1,若设置了具体的值,则该值若与具体的节点的version值不相同,则修改将会失败。

此处节点的版本就是节点最后一次被修改的累计次数,每次针对该节点的修改,版本号通常都会增加,这样有效回避了某个用户对节点修改后,并对其进行修改之前,有其他用户也对该节点进行了修改,此时修改时就能够发现当前节点已经被他人改过,不能够再修改了。

AsyncCallback.StatCallback : 异步监控执行后,进行回调通知的接口(具体参见第三章),该回调接口不可用于监听状态变化,仅仅是用处理节点监听语句执行后的状态,比如是否监听成功、网络是否正常、服务器是否返回什么错误之类的。

ctx : 用于在进行监控初始时,向回调方法传送一个对象,可以传递任意的信息,用于在回调时使用。

5、数据结构

5.1、异步回调接口

异步回调接口定义在接口AsyncCallback中,一共有7种类型,分别用于在不同的操作中,回调并传入不同的内容:

接口类型                                                应用的操作

StatCallback                                          setData()和exists()

DataCallback                                         getData()

ACLCallback                                          getACL()

ChildrenCallback                                   getChildren()

Children2Callback                                 getChildren()

StringCallback                                       create()

VoidCallback                                         delete()

5.1.1、StatCallback

用于在设置节点数据时,以及在判断节点是否存在时进行回调,其回调方法为:

void processResult(int rc,String path,Object ctx,Stat stat)

5.1.2、DataCallback

用于在查询节点数据时进行回调,其回调方法为:

void processResult(int rc,String path,Object ctx,byte[] data,Stat stat)

5.1.3、ACLCallback

用于在获得权限时进行回调,其回调方法为:

void processResult(int rc,String path,Object ctx,Listacl,Stat stat)

5.1.4、ChildrenCallback

用于在查询子节点列表时进行回调,其回调方法为:

void processResult(int rc,String path,Object ctx,Listchildren)

5.1.5、Children2Callback

用于在查询子节点列表时进行回调,并获得状态信息,其回调方法为:

void processResult(int rc,String path,Object ctx,Listchildren,Stat stat)

5.1.6、StringCallback

用于在创建节点时进行回调,其回调方法为:

void processResult(int rc,String path,Object ctx,String name)

5.1.7、VoidCallback

用于在删除节点时进行回调,其回调方法为:

void processResult(int rc,String path,Object ctx)

5.1.8、MultiCallback

用于在批处理时进行回调,其回调方法为:

void processResult(int rc,String path,Object ctx,ListopResults)

5.1.9、返回状态码

回调接口方法中,第一个参数rc的含义:

值         编码                                                       含义

0          OK                                                          执行成功

-1         SYSTEMERROR                                   服务器系统错误

-2         RUNTIMEINCONSISTENCY                 在运行期发现一致性错误

-3         DATAINCONSISTENCY                        发现数据一致性错误

-4         CONNECTIONLOSS                              客户端和服务器之间链接已断开

-5         MARSHALLINGERROR                         数据编码或者解码错误

-6         UNIMPLEMENTED                                 操作不支持

-7         OPERATIONTIMEOUT                           操作超时

-8         BADARGUMENTS                                  无效的参数

-100     APIERROR API                                       调用错误

-101     NONODE                                                 未找到指定的节点

-102     NOAUTH                                                  没有权限,没通过认证

-103     BADVERSION                                          版本冲突错误

-108     NOCHILDRENFOREPHEMERALS         临时节点没有子节点

-110     NODEEXISTS                                          指定的节点已经存在

-111     NOTEMPTY                                             节点中已经存在了子节点

-112     SESSIONEXPIRED                                 在当前服务器中会话已过期

-113     INVALIDCALLBACK                                无效的回调

-114     INVALIDACL                                            无效的ACL控制

-115     AUTHFAILED                                          客户端权限认证失败

-118     SESSIONMOVED                                   会话已经被迁移到另一台服务器中

-119     NOTREADONLY                                     状态更改请求被传递给只读服务器

5.2、状态对象

所有针对节点及其数据进行回调的状态信息,都会封装在状态对象Stat中返回给客户端,状态对象的声明:

public class Stat implements Record {

        private long czxid;

        private long mzxid;

        private long ctime;

        private long mtime;

        private int version;

        private int cversion;

        private int aversion;

        private long ephemeralOwner;

        private int dataLength;

        private int numChildren;

        private long pzxid;

}

其中三个zxid的含义:

czxid:对应为该节点的创建时间(Create)

mzxid:对应该节点的最近一次修改的时间(Mofify),与其子节点无关

pzxid:这个节点就和子节点有关啦,是与该节点的子节点(或该节点)的最近一次 创建/删除的时间戳对应,且只与本节点/该节点的子节点有关,与孙子节点无关。

其中三个version的含义:

version:数据内容的版本号,修改当前结点数据内容,则会变更此版本号

cversion:子节点的版本号,子节点发生变更会改变此版本号

aversion:ACL的版本号,当前结点的ACL发生变更,会改变此版本号

5.3、Ids接口

Ids接口用于声明各种权限相关的配置,在ZooDefs类中,Ids接口的定义如下:

public class ZooDefs {

        public interface Ids {       

                 /**       

                  * world 模式,代表任何人       

                  * 它下面只有一个id, 叫anyone, world:anyone代表任何人,zookeeper

                  * 中对所有人有权限的节点就是属于world:anyone的       

                  */       

                 public final Id ANYONE_ID_UNSAFE = new Id(“world”, “anyone”);       

                 /**       

                  * auth模式

                  * 它不需要id, 只要是通过认证的用户都有权限(zookeeper支持通过kerberos来

                  * 进行认证, 也支持username/password形式的认证)       

                  */       

                 public final Id AUTH_IDS = new Id(“auth”, “”);       

                 /**       

                  * 完全开放的ACL权限       

                  * 支持读、写、创建、删除以及管理       

                  */       

                 public final ArrayListOPEN_ACL_UNSAFE = new ArrayList(Collections.singletonList(new ACL(Perms.ALL, ANYONE_ID_UNSAFE)));       

                  /**       

                   * 为通过认证的人赋予写权限       

                   */       

                   public final ArrayListCREATOR_ALL_ACL = new ArrayList(Collections.singletonList(new ACL(Perms.ALL, AUTH_IDS)));       

                   /**       

                    * 为所有人赋予读权限       

                    */       

                    public final ArrayListREAD_ACL_UNSAFE = new ArrayList(Collections.singletonList(new ACL(Perms.READ, ANYONE_ID_UNSAFE)));

        }

}

点赞