ZooKeeper客户端编程入门

最近再看一个使用ZooKeeper的项目源代码,用C语言编写,但是ZooKeeper在C客户端方面的资料不太多,于是先学习了一下Java版本的客户端,C版本的客户端类似,先将这两天所看到的内容分享如下。


ZooKeeper是一个优秀的分布式协同工具,很多分布式项目都基于它进行架构设计,不过要想要对其有一个深入的理解(如果你想阅读其源代码),对其客户端API的熟悉必不可少。下面就简要记录一下ZooKeeper中各个API的简单用法。


这篇文章不打算对ZooKeeper的基本概念及安装进行讲解,想要了解这部分内容可以参考:http://zookeeper.apache.org/doc/r3.4.3/zookeeperOver.html , 
或者可以参考:http://zookeeper.apache.org/doc/r3.4.3/zookeeperProgrammers.html
均是官方文档,这也是想要学习某个开源工具必须的先行步骤,并且官网上的文档也应该算是最权威的,不过ZooKeeper在这方面的文档不怎么多,但作为入门了解,还是非常有用的。


下面将从基本用法,Watchert的用法,异步调用以及ACL四个方面对ZooKeeper客户端编程作简要介绍。
当完成这四个方面的理解以后,就可以使用ZK完成一些更加高级的任务,如分布式锁、Master选举、一致性服务保障、配置管理等。官方文档对此也有简要介绍,
参考:http://zookeeper.apache.org/doc/r3.4.3/recipes.html


基本数据结构

class Stat {
  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;
}
class Id {
  private String scheme;    //world、auth、digest、ip
  private String id;
} 
class ACL {
  private int perms;    //CREATE、READ、WRITE、DELETE、ADMIN
  private org.apache.zookeeper.data.Id id;
}


基本使用

try {    
      static String hostport = "127.0.0.1:2181";
      ZooKeeper zooKeeper = new ZooKeeper(hostport, 300000, null);    //创建一个ZooKeeper实例,不设置默认watcher
      String path = "/test";
      zooKeeper.create(path, path.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);    //创建一个节点
      Stat stat = new Stat();
      byte[] b = zooKeeper.getData(path, false, stat);    //获取节点的信息及存储的数据
      System.out.println(stat);
      System.out.println(new String(b));
      stat = zooKeeper.exists(path, false);    //查看path所代表的节点是否存在
      zooKeeper.setData(path, "helloworld".getBytes(), stat.getVersion());    //设置节点的数据
      //zooKeeper.delete(path, -1);    //删除节点
      zooKeeper.close();    //关闭实例
} catch (Exception e) {
      e.printStackTrace();
}

ZooKeeper通过Auth和ACL完成节点的权限控制。

Auth表示某种认证,由于一个ZooKeeper集群可能被多个项目使用,各个项目属于不同的项目组,他们在进行开发时肯定不想其他项目访问与自己相关的节点,这时可以通过为每个项目组分配一个Auth,然后每个项目组先通过Auth认证以后再继续相关的操作,这样甲Auth认证的用户就不能操作其他Auth认证后创建的节点,从而实现各个项目之间的隔离。ZooKeeper提供了如下方法完成认证,如下所示:
Void addAuthInfo(String scheme, byte[] auth) ,使用示例如下:

@Test
	public void testFirstStep() {
		try {
			zk = new ZooKeeper(hostport, 1000000, null);
			
			String auth_type = "digest";
			String auth = "joey:some";
			
			String p = "/acl_digest";
			
			zk.addAuthInfo(auth_type, auth.getBytes());
			
			zk.create(p, "hello".getBytes(), Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
			
			Stat stat = new Stat();
			System.out.println(new String(zk.getData(p, false, stat)));

			zk.close();
		} catch(Exception ex) {
			ex.printStackTrace();
		}
	}
	@Test
	public void testSecondStep() {
		String p = "/acl_digest";
	
	try {
		zk = new ZooKeeper(hostport, 1000000, null);
		
		String authType = "digest";
	     String badAuth = "joey:someBAD";
			
			zk.addAuthInfo(authType, badAuth.getBytes());
			Stat stat = new Stat();
			System.out.println(new String(zk.getData(p, false, stat)));
		} catch(Exception ex) {
			ex.printStackTrace();  //抛出异常
		} finally {
			try {
				zk.delete(p, -1);
				zk.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}
	}

ACL用于控制Znode的访问,和Unix文件访问权限类似,提供对某类用户设置某种权限的能力(如Unix中对Owner提供读、写、执行的权限),但是在ZooKeeper中没有Owner、Group等概念,于是在ZooKeeper中使用ID表示某一类用户,可以对ID设置某种权限。(ZooKeeper对ID的数量没有限制,不像Unix文件仅支持三种类型用户)

ZooKeeper支持的权限:
CREATE: you can create a child node
READ: you can get data from a node and list its children.
WRITE: you can set data for a node
DELETE: you can delete a child node
ADMIN: you can set permissions


ZooKeeper内建的sheme:(scheme是ID的其中一个属性)
world has a single id, anyone, that represents anyone.
auth doesn't use any id, represents any authenticated user.
digest uses a username:password string to generate MD5 hash which is then used as an ACL ID identity. Authentication is done by sending theusername:password in clear text. When used in the ACL the expression will be the username:base64 encoded SHA1 password digest.
ip uses the client host IP as an ACL ID identity. The ACL expression is of the form addr/bits where the most significant bits of addr are matched against the most significant bits of the client host IP.


ZK内建的ID:
ANYONE_ID_UNSAFE    //任意用户
AUTH_IDS     //通过Auth认证过的用户


内建的权限控制集合:
OPEN_ACL_UNSAFE: 创建任何人都可以操作的节点
READ_ACL_UNSAFE: 创建任何人都可以读的节点
CREATOR_ALL_ACL: 设置了Auth的用户可以使用该ACL集合创建节点,该节点也只能被同样Auth授权的用户操作


示例代码如下:

@Test
	public void testACL_with_ip_scheme() {
		try {
			Id id = new Id();
			id.setScheme("ip");
			id.setId(InetAddress.getLocalHost().getHostAddress());
			
			ACL acl = new ACL();
			acl.setId(id);    //对ID所指定的目标设置权限
			acl.setPerms(Perms.ALL);
			
			List<ACL> acls = new ArrayList<ACL>();
			acls.add(acl);    //可以添加多个运行的IP地址
			
			String p = "/ip";
			
			zk.create(p, p.getBytes(), acls, CreateMode.PERSISTENT);
			
			zk.delete(p, -1);  //仅IP相同的用户可以对该进行进行操作
		} catch(Exception ex) {
			ex.printStackTrace();
		}
	}


Watcher
可以设置Watcher的方式:

1) 在ZooKeeper的构造函数中可以设置Watcher

2) 使用ZooKeeper.register(Watcher)显示的更改在构造函数中设置的默认Watcher

3) 通过某些方法的调用可以更改某个path对应节点的Watcher    

 

具体可以设置Watcher的方法如下所示:

1)     构造函数: state changes or node events 

2)     Register: 修改构造函数中指定的默认Watcher.

3)     getData: triggered by sets data on the node, or deletes the node. 

4)     getChildren: triggered by deletes the node or creates/delete a child under the node. 

5)     exists: triggered by creates/delete the node or sets the data on the node.

 

其中构造函数阶段指定的Watcher一直有效(register方式属于该类),其余方法设置的Watcher仅有效一次。在方法调用时,如果指定开启watcher,如果该节点通过getData、getChildren和exists设置了Watcher,就触发该Watcher,然后使得该Watcher失效(但默认的Watcher还一直生效),否则触发构造函数中设定的默认Watcher。

 

示例代码如下:

class ExistsWatcher implements Watcher { 
   @Override
        public void process(WatchedEvent event) {
     System.out.println("---------------------------");
     System.out.println("setting by exist watcher");
     System.out.println("path is : " + event.getPath());
     System.out.println("type is : " + event.getType());
     System.out.println("state is : " + event.getState());
     System.out.println("---------------------------");
  }
 }
class DefaultWatcher implements Watcher {
  @Override
  public void process(WatchedEvent event) {
    System.out.println("=====>Default Watch Event: " + event.getType());
  }
}
@Test
  public void testWatcher() {
    try {
      DefaultWatcher defaultWatcher = new DefaultWatcher();
      ExistsWatcher existsWatcher = new ExistsWatcher();
      String p = "/watcher";
      ZooKeeper zk = new ZooKeeper(hostport, 300000, null);
      zk.register(defaultWatcher);
      Stat stat = zk.exists(p, existsWatcher);
      zk.create(p, p.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
      stat = zk.exists(p, true);
      byte[] b = zk.getData(p, true, stat);
      System.out.println(new String(b));
      stat = zk.exists(p, true);
      zk.setData(p, "Iloveyou".getBytes(), stat.getVersion());
      stat = zk.exists(p, existsWatcher);
      zk.delete(p, stat.getVersion());
      zk.close();
    } catch(Exception ex) {
      ex.printStackTrace();
    }
  }

运行结果如下:

=====>Default Watch Event: None
---------------------------                      
setting by exist watcher
path is : /watcher
type is : NodeCreated
state is : SyncConnected
---------------------------
/watcher
=====>Default Watch Event: NodeDataChanged
---------------------------
setting by exist watcher
path is : /watcher
type is : NodeDeleted
state is : SyncConnected
---------------------------

异步调用
顾名思义,异步调用是指在调用某个方法后不等待其返回,而是接着处理下面的任务,当方法调用完成时触发某个回调函数,回调函数需要在方法调用时指定,然后在回调函数中处理方法调用的结果。
在ZK中,几乎为每个方法都提供了异步调用的版本,如getData方法,其函数原型如下所示:


void getData(String path, boolean watch, DataCallback cb, Object ctx);
其中: 
DataCallback为提供回调函数的类,
ctx为回调函数需要的参数


示例代码如下:

Children2Callback cb = new Children2Callback() {
			@Override
			public void processResult(int rc, String path, Object ctx,
					List<String> children, Stat stat) {
				for (String s : children) {
					System.out.println("----->" + s);
				}
				System.out.println(ctx);    //输出:helloworld
			}
		};
		
		zk.getChildren(path, true, cb, "helloworld");

相信通过上面的学习一定能够熟悉ZK客户端的编程思路。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值