zookeeper简单介绍及API使用
1.1 zookeeper简介
zookeeper是一个针对大型分布式系统的可靠的协调系统,提供的功能包括配置维护、名字服务、分布式同步、组服务等。zookeeper可以集群复制,集群间通过zab协议来保持数据的一致性。该协议包括两个阶段:leader election阶段和Atomic broadcas阶段。
leader election阶段:集群间选举出一个leader,其他的机器则称为follower,所有的写操作都被传送给leader,并通过broadcas将所有的更新告诉follower,当leader崩溃或leader失去大多数的follower时,需要重新选举出一个新的leader,让所有的服务器都恢复到一个正确的状态。当leader被选举出来且大多数服务器完成了和leader的状态同步后,leader election过程结束,进入Atomic broadcas阶段。
Atomic broadcas阶段:Atomic broadcas同步leader和follower之间的信息,保证二者具有相同的系统状态。
zookeeper的协作过程简化了松散耦合系统之间的交互,即使参与者彼此不知道对方的存在,也能够相互发现并且完成交互。
1.2 zookeeper API简单使用
可以认为zookeeper是一个小型的、精简的文件系统,它的每个节点称为znode,znode除了本身能够包含一部分数据之外,还能拥有子节点,当节点或子节点数据发生变化时,基于watcher机制,会发出相应的通知给订阅其状态变化的客户端。
1.2.1 zookeeper节点创建
maven项目中引入模块:
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>
创建zookeeper对象和节点:
1 public static void main(String[] args) throws Exception { 2 /* 3 * 127.0.0.1:2181:服务器地址 4 * 10:超时时间 5 * watcher:若包含boolean watch的读方法中传入true,则将默认watcher注册为所关注事件的watcher 6 * 若传入false,则不注册任何watcher。此处暂且定为空 7 */ 8 ZooKeeper zookeeper = new ZooKeeper("127.0.0.1:2181", 10, null); 9 /* 10 * 若创建的节点已经存在,则会抛出异常 11 * /root:节点路径 ; root data:路径包含的字节数据 12 * Ids.OPEN_ACL_UNSAFE:访问权限 13 * CreateMode.PERSISTENT:节点类型 14 */ 15 zookeeper.create("/root", "root data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 16 /* 17 * 设置节点数据 18 * -1:版本号;若匹配不到响应的节点则会抛出异常 19 */ 20 zookeeper.setData("/root", "hello".getBytes(), -1); 21 /* 22 * 读取节点数据 23 * stat是节点状态参数,读取时会传出该节点当前状态信息 24 */ 25 Stat stat = new Stat(); 26 byte[] data = zookeeper.getData("/root", false, stat); 27 System.out.println(new String(data)); 28 /* 29 * 添加子节点,若父节点不存在会抛出异常 30 */ 31 zookeeper.create("/root/child", "child data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 32 /* 33 * 判断节点是否存在,不存在则返回的stat为null 34 */ 35 Stat existsStat = zookeeper.exists("/root/child", false); 36 System.out.println(existsStat); 37 /* 38 * /root/child:删除节点路径 39 * -1:节点的版本号;若设置为-1,则匹配所有版本,zookeeper会比较删除的版本和服务器版本是否一致,不一致会抛出异常 40 */ 41 zookeeper.delete("/root/child", -1); 42 }
实际运行中最常出现这个错误:
Exception in thread "main" org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /root
at org.apache.zookeeper.KeeperException.create(KeeperException.java:90)
at org.apache.zookeeper.KeeperException.create(KeeperException.java:42)
at org.apache.zookeeper.ZooKeeper.create(ZooKeeper.java:643)
at com.project.soa.zookeeper.ZookeeperDemo.main(ZookeeperDemo.java:12)
这是因为还未连接上zookeeper就开始添加、删除节点等操作,为避免这种情况发生,可以在做操作时对连接状态做判断:
1 ZooKeeper zookeeper = new ZooKeeper("127.0.0.1:2181", 10, null); 2 if (zookeeper.getState() == States.CONNECTED) { 3 4 }
1.2.2 watcher的实现
节点的状态发生变化,可以通过zookeeper的watcher机制让客户端取得通知。watcher的实现较为简单,只需实现org.apache.ZooKeeper.Watcher接口即可,其中节点的状态变化包含以下几种状态:
注意:watcher机制是一次性的,每次处理完状态变化事件之后需重新注册watcher。这也导致在处理事件和重新加上watcher这段时间发生的节点状态无法被感知。