ZooKeeper客户端编程入门

本文详细介绍了ZooKeeper客户端的基本使用方法、权限控制、watcher机制及异步调用,包括数据结构、基本操作、权限管理、认证方式、ACL控制和watcher的配置,帮助读者深入理解并应用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客户端的编程思路。

内容概要:本文详细介绍了一个基于C++的美食推荐分析系统的设计与实现,涵盖项目背景、目标、挑战及解决方案,并深入阐述了系统的整体架构与关键技术模块。系统通过用户行为数据建模、菜品内容特征分析、混合推荐算法(如基于内容与协同过滤)、用户画像动态演化、高效数据结构与并发处理等手段,实现个性化、健康化、多样化的美食推荐。文中提供了核心数据结构(如用户、菜品、评分)的设计思路及关键算法的C++代码示例,包括基于内容的推荐、协同过滤、多样性优化、健康饮食推荐等功能,展示了C++在高性能智能推荐系统中的应用潜力。同时,系统注重数据安全、隐私保护、跨平台部署与反馈闭环机制,具备良好的实用性与扩展性。; 适合人群:具备一定C++编程基础,熟悉数据结构与面向对象编程的高校学生、软件工程师或从事推荐系统研发的技术人员,尤其是对智能餐饮、个性化推荐、健康管理系统感兴趣的开发者。; 使用场景及目标:①学习如何使用C++构建高性能推荐系统;②掌握混合推荐算法在实际项目中的设计与融合方法;③理解用户画像、兴趣演化、冷启动等问题的工程解决方案;④应用于外卖平台、健康管理APP、智能餐饮终端等场景,提升个性化服务与运营效率。; 阅读建议:此资源以实际项目为导向,结合模型设计与代码实现,建议读者在学习过程中动手实践各模块代码,结合数据结构设计与算法逻辑进行调试与优化,并可在此基础上扩展图形界面或集成数据库,全面提升系统工程能力。
内容概要:本文提出“银龄智居”适老化智能家居建设计划,旨在解决当前智能家居产品在老年群体中存在的操作复杂、功能割裂、服务缺失等问题。项目基于OpenHarmony操作系统构建“感知层-控制层-应用层-云端”全链路系统,实现健康监测、环境安全预警、语音控制(支持8种方言)、远程监护等功能的深度融合,并通过大字体显示终端、简化操作流程提升老年用户使用体验。同时,项目配套“1小时响应、24小时上门”的全周期服务体系,打通设备安装、培训与维护环节,形成“硬件+软件+服务”一体化解决方案。该计划积极响应国家智慧养老政策,已在多个城市开展试点,致力于推动居家养老智能化、适老化发展。; 适合人群:关注智慧养老领域的创业者、科技企业研发人员、政府养老政策制定者、养老服务机构管理者以及对适老化技术感兴趣的研究人员。; 使用场景及目标:①应用于独居或半独居老年人家庭,提升其居家安全与健康管理能力;②为子女提供远程监护工具,增强家庭照护连接;③助力养老机构实现智能化升级,降低人工成本;④为地方政府推进适老化改造项目提供可复制的技术与服务模式。; 阅读建议:建议结合文中市场数据、用户需求分析与技术架构图深入理解项目设计逻辑,重点关注其在OpenHarmony生态下的分布式协同机制、方言识别与健康联动控制等创新点,并参考其营销策略与风险应对方案,用于实际项目规划或学术研究。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值