1. Java操作ZooKeeper
引入jar包:
<dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.10</version></dependency>
privateZooKeeper zk;/**
* 创建连接
*
* @param address 地址 集群写多个,逗号分开docker.vm.com:2181,docker.vm.com:2182,docker.vm.com:2183
* @param sessionTimeout 会话过期时间
*/publicvoidcreateConnection(String address,int sessionTimeout){try{
zk =newZooKeeper(address, sessionTimeout,newWatcher(){// 监控所有被触发的事件publicvoidprocess(WatchedEvent event){System.out.println("已经触发了"+ event.getType()+"事件!");//1、获取事件状态Event.KeeperState state = event.getState();//2、获取事件类型Event.EventType type = event.getType();//获取节点地址String path = event.getPath();//3、判断是否连接if(Event.KeeperState.SyncConnected== state){//4、判断类型if(Event.EventType.None== type){System.out.println("###zookeeper建立连接成功###");}elseif(Event.EventType.NodeCreated== type){System.out.println("###Watcher监听的对应数据节点被创建###, 当前新增节点:"+ path);}elseif(Event.EventType.NodeDataChanged== type){System.out.println("###Watcher监听的对应数据节点的数据内容发生变更###, 当前节点:"+ path +",被修改...");}elseif(Event.EventType.NodeChildrenChanged== type){System.out.println("###Wather监听的对应数据节点的子节点列表发生变更###, 当前子节点:"+ path +",被修改...");}elseif(Event.EventType.NodeDeleted== type){System.out.println("###Watcher监听的对应数据节点被删除###, 当前节点:"+ path +",被删除...");}}}});}catch(IOException e){
e.printStackTrace();}}/**
* 判断指定节点是否存在
*
* @param path
* @param needWatch
* @return
*/publicStatexist(String path,boolean needWatch){try{returnthis.zk.exists(path, needWatch);}catch(Exception e){
e.printStackTrace();returnnull;}}/**
* 创建持久化节点
*
* @param path
* @param data
* @return
*/publicbooleancreateNode(String path,String data){try{this.exist(path,true);/**
* acl:权限列表
提供默认的权限OPEN_ACL_UNSAFE、CREATOR_ALL_ACL、READ_ACL_UNSAFE
OPEN_ACL_UNSAFE:完全开放
CREATOR_ALL_ACL:创建该znode的连接拥有所有权限
READ_ACL_UNSAFE:所有的客户端都可读
*//**
* PERSISTENT 持久化节点
* PERSISTENT_SEQUENTIAL 顺序自动编号持久化节点,这种节点会根据当前已存在的节点数自动加 1
* EPHEMERAL 临时节点, 客户端session超时这类节点就会被自动删除
* EPHEMERAL_SEQUENTIAL 临时自动编号节点
*/
zk.create(path, data.getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);System.out.println("###新增节点信息path:"+ path +" data:"+ data);returntrue;}catch(Exception e){
e.printStackTrace();returnfalse;}}/**
* 修改持久化节点
*
* @param path
* @param data
* @return
*/publicbooleanupdateNode(String path,String data){try{this.exist(path,true);//zk的数据版本是从0开始计数的。如果客户端传入的是-1,则表示zk服务器需要基于最新的数据进行更新。如果对zk的数据节点的更新操作没有原子性要求则可以使用-1.//version参数指定要更新的数据的版本, 如果version和真实的版本不同, 更新操作将失败. 指定version为-1则忽略版本检查
zk.setData(path, data.getBytes(),-1);System.out.println("###修改节点信息path:"+ path +" data:"+ data);returntrue;}catch(Exception e){
e.printStackTrace();returnfalse;}}publicbooleandeleteNode(String path){try{this.exist(path,true);
zk.delete(path,-1);System.out.println("###删除节点信息path:"+ path);returntrue;}catch(Exception e){
e.printStackTrace();returnfalse;}}publicbyte[]getNodeData(String path,boolean needWatch,Stat stat){try{byte[] data = zk.getData(path, needWatch, stat);return data;}catch(KeeperException e){
e.printStackTrace();}catch(InterruptedException e){
e.printStackTrace();}returnnull;}publicvoidclose(){try{if(zk !=null){
zk.close();System.out.println("###zookeeper服务已关闭");}}catch(Exception e){
e.printStackTrace();}}publicstaticvoidmain(String[] args)throwsException{ZooTest test =newZooTest();
test.createConnection(ADDRESS, SESSION_TIMEOUT);
test.createNode("/t1","55555");
test.updateNode("/test","3333");
test.deleteNode("/test");
test.close();}
zookeeper的权限: ZooKeeper提供了如下几种验证模式(scheme):
• digest:Client端由用户名和密码验证,譬如user:password,digest的密码生成方式是Sha1摘要的base64形式
• auth:不使用任何id,代表任何已确认用户。 • ip:Client端由IP地址验证,譬如172.2.0.0/24
• world:固定用户为anyone,为所有Client端开放权限
• super:在这种scheme情况下,对应的id拥有超级权限,可以做任何事情(cdrwa)注意的是,exists操作和getAcl操作并不受ACL许可控制,因此任何客户端可以查询节点的状态和节点的ACL。
节点的权限(perms)主要有以下几种: • Create 允许对子节点Create操作 • Read
允许对本节点GetChildren和GetData操作 • Write 允许对本节点SetData操作 • Delete
允许对子节点Delete操作 • Admin 允许对本节点setAcl操作
ZooKeeper zk =newZooKeeper("10.9.126.153",3000,null);List<ACL> acls =newArrayList<ACL>(1);Id id =newId("digest",DigestAuthenticationProvider.generateDigest("admin:admin123"));ACL acl =newACL(ZooDefs.Perms.ALL, id);//ACL acl = new ACL(ZooDefs.Perms.CREATE|ZooDefs.Perms.READ, id);//给多权限
acls.add(acl);
zk.create("/test",newbyte[0], acls,CreateMode.PERSISTENT);
zk.addAuthInfo("digest","admin:admin123".getBytes());
zk.close();
2. ZooKeeper基础
ZooKeeper是一个分布式应用程序协调服务。它监视集群中各个节点的状态,根据节点提交的反馈进行下一步合理操作。保证系统性能高效,功能稳定。
ZooKeeper客户端和server采用长连接。建立连接之后server生成64位的session
id给客户端。客户端定期发送ping包检查和保存于server的连接。一旦session结束或者超时,所有的临时节点被删除。客户端可以设置session超时时间。
2.1 ZooKeeper节点
ZooKeeper提供一个多层级(基于树形结构)的节点命名空间。类似于linux的目录结构,不同的是ZooKeeper每个节点都能存放数据,而linux文件系统中,只有文件中才能写数据,文件夹中只能放文件(ZooKeeper更简单,不区分文件和文件夹)。ZooKeeper中的节点不允许递归创建,即父节点不存在,不能创建子节点。如:
/parent_node/child
如果/parent_node不存在,则不能直接创建/parent_node/child
Zookeeper节点不能存放大量数据,每个节点存放数据上限为1M。 ZooKeeper节点有四种类型:
持久节点(PERSISTENT):在节点创建后就一直存在,直到有显示的删除操作来清除这个节点。不会随客户端会话失效而消失。如果创建节点时选择PERSISTENT,则不能有同名的节点存在,否则会报错:
持久顺序节点(PERSISTENT_SEQUENTIAL):这类节点也是持久的。ZooKeeper中每个父节点会为它的一级子节点维护一份时序,记录每个子节点的先后顺序。ZooKeeper会为每个节点添加一个数字(10位长度左边以0填充的递增数字)后缀作为新的节点名,数字范围是整型最大值。如创建两个/nodetest/child节点,/nodetest下的节点是:
临时节点(EPHEMERAL):临时节点的生命周期与客户端会话绑定,如果创建节点的客户端会话失效(并不是断开连接),则节点就被清除掉。临时节点下不能创建子节点
临时顺序节点(EPHEMERAL_SEQUENTIAL):节点创建规则同持久顺序节点,只不过它是临时的。
2.2 Dubbo在ZooKeeper中的存储
Dubbo使用ZooKeeper作为注册中心,也是以节点的形式存储的: 根节点:在/dubbo下 一级节点时服务名(接口全路径)
二级节点下有四个子节点:consumers、configurators、routers、providers
Dubbo服务启动的时候会向/dubbo/${serviceName}/ providers下写入自己的URL地址,完成服务发布
2.3 ZooKeeper Watcher
客户端在向 ZooKeeper 服务器注册 Watcher 的同时,会将 Watcher 对象存储在客户端的 WatchManager中。当ZooKeeper 服务器触发 Watcher 事件后,会向客户端发送通知,客户端线程从 WatchManager的实现类中取出对应的 Watcher 对象来执行回调逻辑。
这个 Watcher 将作为整个 ZooKeeper会话期间的默认Watcher,会一直被保存在客户端 ZKWatchManager 的 defaultWatcher 中。另外,ZooKeeper
客户端也可以通过 getData、exists 和 getChildren 三个接口来向 ZooKeeper 服务器注册 Watcher。
无论是服务端还是客户端,一旦一个 Watcher 被触发,ZooKeeper 都会将其从相应的存储中移除。因此,在 Watcher的使用上是单次的,需要反复注册。这样的设计有效地减轻了服务端的压力。 触发Watcher回调的条件:
a) 客户端建立连接、断开连接
b) 节点数据发生变化
c) 节点本身发生变化
版权归原作者 专治八阿哥的孟老师 所有, 如有侵权,请联系我们删除。