zookeeper的基本使用

  概述:理论暂略

    一、windows 集群安装

1、复制3分zoo?.cfg的文件
	每份文件分别是
	1.1 zoo1.cfg
	tickTime=2000
	initLimit=10
	syncLimit=5
	dataDir=D:\\zookeeper-3.4.12\\data\\1  //持续递增
	dataLogDir=D:\\zookeeper-3.4.12\\log\\1 //持续递增
	clientPort=2181  //持续递增
	server.1=127.0.0.1:2887:3887 //第一个端口此server和集群中 Leader服务器交换信息的端口,第二个端口是选举端口
	server.2=127.0.0.1:2888:3888
	server.3=127.0.0.1:2889:3889
	1.2 zoo2.cfg
	tickTime=2000
	initLimit=10
	syncLimit=5
	dataDir=D:\\zookeeper-3.4.12\\data\\2
	dataLogDir=D:\\zookeeper-3.4.12\\log\\2
	clientPort=2182
	server.1=127.0.0.1:2887:3887
	server.2=127.0.0.1:2888:3888
	server.3=127.0.0.1:2889:3889
	1.3 zoo3.cfg   略!
	
2、需要复制3个启动脚本.并且指定启动脚本zkServer?.cmd内的增加一个参数 set ZOOCFG=../conf/zoo?.cfg

3、在data/?下创建一个文本文件myid (无后缀)  并且依次填上?的数值

4、启动即可!

二、基本操作APi

/**
  一、基本操作APi
		1、创建一个目录节点
			zk.create("/testRootPath2", "testRootData".getBytes(), Ids.OPEN_ACL_UNSAFE,
				   CreateMode.PERSISTENT);
				   
		2、创建一个子目录节点
		   zk.create("/testRootPath2/testChildPathOne", "testChildDataOne".getBytes(),
		   Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
		   
		3、取节点数据
			new String(zk.getData("/testRootPath2",false,null)) // false不监控
			
		4、取子节点目录
			zk.getChildren("/testRootPath2",true) 
			
		5、修改子节点数据
			zk.setData("/testRootPath2/testChildPathOne","modifyChildDataOne".getBytes(),-1);
 */
public class ZookeeperDemo {
	
	
	@Test
	public void test1() throws Exception {
		ZooKeeper zk = new ZooKeeper("localhost:"+2181,30000, new Watcher(){
            // 监控所有被触发的事件
            public void process(WatchedEvent event){
                System.out.println(event.getPath()+"已经触发了" + event.getType() + "事件!"); 
            }
        });

		//创建一个目录节点
		zk.create("/testRootPath2", "testRootData".getBytes(), Ids.OPEN_ACL_UNSAFE,
				   CreateMode.PERSISTENT);
		
		//创建一个子目录节点
		zk.create("/testRootPath2/testChildPathOne", "testChildDataOne".getBytes(),
		   Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
		
		//取出目录节点数据
		System.out.println(new String(zk.getData("/testRootPath2",false,null)));
		
		//取出子目录节点列表
		System.out.println(zk.getChildren("/testRootPath2",true));
		
		//修改子目录节点数据
		zk.setData("/testRootPath2/testChildPathOne","modifyChildDataOne".getBytes(),-1);
		System.out.println("目录节点状态:["+zk.exists("/testRootPath2",true)+"]");
		
		// 创建另外一个子目录节点
		zk.create("/testRootPath2/testChildPathTwo", "testChildDataTwo".getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); 
		System.out.println(new String(zk.getData("/testRootPath2/testChildPathTwo",true,null))); 
		
		// 删除子目录节点
		zk.delete("/testRootPath2/testChildPathTwo",-1);
		zk.delete("/testRootPath2/testChildPathOne",-1);
		
		// 删除父目录节点
		zk.delete("/testRootPath2",-1);
		
		Thread.sleep(1000);
		
		// 关闭连接
		zk.close(); 
	}
}

三、Acl介绍 

 * 概述: ACL:Access Control List 访问控制列表 ACL
 * 权限控制,使用:scheme:id:perm 来标识,
 * 主要涵盖下面 3个方面 权限模式(Scheme):
 * 授权的策略 --- newId('digest', ""); // 这个digest就是授权策略 授权对象(ID):
 * 授权的对象 --- id的值就是授权对象; // 比如用户名密码,或者id策略的地址 权限(Permission):授予的权限 ---
 * 模式和对象确定被授权的客户端,权限就是这个客户端可操作的读、写等操作。
 * 
 * 特性: Zookeeper的权限全部是基于节点的,即一个节点有一个节点的权限,每个节点可以设置多种ACL, 子节点不能继承父节点的权限。
 * 
 * Scheme模式:

    world: 默认方式,相当于全部都能访问, 授权对象就是字符串anyone。
 *  auth: 认证方式,代表已经认证通过的用户。
 * digest: 用户名密码的认证方式, new Id("digest", md5(username:password));。 
 * ip:地址授权方式,可采用id段方式,比如192.168.0.1/24。

	public static void main(String[] args)
			throws NoSuchAlgorithmException, IOException, KeeperException, InterruptedException {
		// 设置节点acl_test全部客户端可以访问,但是只有密码正确可以写权限
		List<ACL> acls = new ArrayList<>();
		ACL acl1 = new ACL(Perms.READ, new Id("world", "anyone"));
		Id id = new Id("digest", DigestAuthenticationProvider.generateDigest("admin:admin"));
		ACL acl2 = new ACL(Perms.ALL, id);
		acls.add(acl1);
		acls.add(acl2);
		ZooKeeper zk = new ZooKeeper("localhost:2181", 2000, null);
		if (zk.exists("/acl_test", false) == null) {
			zk.create("/acl_test", "acl_test_data".getBytes(), acls, CreateMode.PERSISTENT); // 此节点任意可读,认证可写
		}

		// 客户端设置权限对象,如果和节点创建时设置的权限认证通过,则可以操作。
		zk.addAuthInfo("digest", "admin:adminx".getBytes());
		List<ACL> acl = zk.getACL("/acl_test", new Stat());
		System.out.println(acl.get(0).toString());

		// zk.setData("/acl_test", "wefwef".getBytes(), -1);
		// //出错,没有写权限KeeperErrorCode = NoAuth for /test3
		zk.delete("/acl_test", -1); // 注意:ACL中的delete权限应该理解为对子节点的delete权限

	}

四、Watch介绍 

一句话攻略: 首先只有3个get类型的方法能够触发实现Watch方法的process方法。
 *               exists 触发 目标节点的创建,删除,数据更新
 *               getData 比较上面----目标节点除了创建。删除,和更新都可以触发
 *               getChildren 子节点的创建和删除会触发NodeChildrenChanged,以及父节点本身的删除

private ZooKeeper connection() throws IOException{
		return new ZooKeeper("localhost:" + 2181, 10000, new Watcher() {
			public void process(WatchedEvent event) {
				if (event.getPath() == null) { // 连接时会触发None的事件
					System.out.println("[初始化连接]" + event.getPath() + ":" + event.getType());
				} else if (event.getType() == Event.EventType.NodeDeleted) {
					System.out.println("[节点删除]" + event.getPath() + ":" + event.getType());
				} else if (event.getType() == Event.EventType.NodeCreated) {
					System.out.println("[节点创建]" + event.getPath() + ":" + event.getType());
				} else if (event.getType() == Event.EventType.NodeDataChanged) {
					System.out.println("[节点更新]" + event.getPath() + ":" + event.getType());
				} else if (event.getType() == Event.EventType.NodeChildrenChanged) {
					System.out.println("[子节点更新(父增删子节点)]" + event.getPath() + ":" + event.getType());
				}
			}
		});
	}
	
	/**
	 * 测试exists事件: --> 被监视的Znode创建(create:NodeCreate)、删除(delete:NodeDelete)、更新(setData:NodeDataChange)时被触发。
	 */
	@Test
	public void test1() throws IOException, KeeperException, InterruptedException{
		ZooKeeper zk = connection();
		Stat stat = zk.exists("/root", true);
		if (stat == null) {
			zk.create("/root", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
		}
		Stat stat2 = zk.exists("/root", true);
		if (stat2 == null) {
			zk.create("/root", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
		} else {
			zk.setData("/root", "haha".getBytes(), -1);// -1好像表示全部版本
		}
		// zk.delete("/root",-1); 此时不触发事件,因为一个get类型方法只能触发它对应的事件一次。
		Stat stat3 = zk.exists("/root", true);
		if (stat3 != null) {
			zk.delete("/root", -1);
		}
	}
	
	/**
	 * 测试getData事件: --> 被监视的Znode删除(delete:NodeDelete)、更新(setData:NodeDataChange)时被触发。
	 */
	@Test
	public void test2() throws IOException, KeeperException, InterruptedException{
		ZooKeeper zk = connection();
		Stat stat = zk.exists("/root", false);
		if(stat==null){
			zk.create("/root", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
		}
		byte[] data1 = zk.getData("/root", true, null);
		System.out.println(new String(data1));
		zk.setData("/root", "haha".getBytes(), -1); //触发NodeDataChange
		byte[] data2 = zk.getData("/root", true, null);
		System.out.println(new String(data2));
		zk.delete("/root",-1);
	}
	
	/**
	 * 测试getChildren事件:-->父节点下的子增删 (delete:NodeChildrenChanged) 父节点自己的删除 (delete:NodeDelete)
	 */
	@Test
	public void test3() throws IOException, KeeperException, InterruptedException{
		ZooKeeper zk = connection();
		Stat stat = zk.exists("/root", false);
		if(stat==null){
			zk.create("/root", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
		}
		//---------------------------------------------------------
		zk.getChildren("/root", true);
		zk.create("/root/children1", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
		zk.getChildren("/root", true);
		zk.create("/root/children2", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
		zk.getChildren("/root", true);
		zk.delete("/root/children1", -1);
		zk.delete("/root/children2", -1);
		zk.getChildren("/root", true);
		zk.delete("/root", -1); /**不能级联删除,要把子节点全删掉!*/
	}

.五、ZkClient的使用

   <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.10</version>
     </dependency>
    
四、zkClient的使用
概述:IZKConnection:是一个ZkClient与Zookeeper之间的一个适配器;在代码里直接使用的是ZKClient,
 实质上还是委托了zookeeper进行处理。
	
	在ZKClient中,根据事件类型,分为  :
	节点事件(数据事件),对应的事件处理器是IZKDataListener;
	子节点事件,对应的事件处理器是IZKChildListener;
	Session事件,对应的事件处理器是IZKStatusListener;
	ZkEventThread:是专门用来处理事件的线程

启动ZKClient:在创建ZKClient对象时,就完成了到ZooKeeper服务器连接的建立
	1)、启动时,制定好connection string,连接超时时间,序列化工具等
	2)、创建并启动eventThread,用于接收事件,并调度事件监听器Listener的执行
	3)、连接到Zookeeper服务器,同时将ZKClient自身作为默认的Watcher


 */
public class ClientDemo {
	
    public static final String PATH_DELIMITER = "/";
	
	public static ZkClient zkClient = ZkClientUtil.createZkClient("127.0.0.1:2171", null);

	/**
	 * 1、基础api的演示
	 */
	public static void main(String[] args) {
		String path = "/root";
		zkClient.deleteRecursive(path); // 递归删除
		zkClient.createPersistent(path, "root_data"); // 创建持久节点
		zkClient.writeData(path, "root_data2"); // 写数据
		User user = new User();
		user.setId(1);
		user.setUsername("zhangsan");
		zkClient.writeData(path, user);
		System.out.println(((User) zkClient.readData(path)).getUsername());
		zkClient.createPersistent(path+"/child1", true); // 递归创建
		zkClient.writeData(path+"/child1", "child1_data");
		Object readData = zkClient.readData(path+"/child1");
		System.out.println(readData);
		List<String> list = zkClient.getChildren(path); // 得到子节点
		for (String string : list) {
			System.out.println(string);
		}
	}
	
	/**
	 * 2、服务节点发现创建的演示
	 * 服务父节点采用持久节点, 服务子项采用临时节点,节点不存在就创建。
	 */
	@Test
	public void test2() {
		String[] uris = new String[] { "ip1", "ip2" };
		String servicePath = "/server_root" + PATH_DELIMITER + "server_name" + "/service";
		if (!zkClient.exists(servicePath)) {
			// 没有该节点就创建
			zkClient.createPersistent(servicePath, true);
		}
		for (String uri : uris) {
			String uriPath = servicePath + PATH_DELIMITER + uri;
			if (zkClient.exists(uriPath)) {
				// 删除之前的节点
				zkClient.delete(uriPath);
			}
			// 创建一个临时节点,会话失效即被清理
			zkClient.createEphemeral(uriPath);
		}
	}
	
	/**
	 * 3、监听器IZkDataListener的演示
	 */
	@Test
	public void test3() {

		String path = "/test_client_listenner";

		zkClient.delete(path);

		zkClient.subscribeDataChanges(path, new IZkDataListener() {

			@Override
			public void handleDataChange(String dataPath, Object data) throws Exception {
				System.out.printf("数据更新%s,数据是:%s", dataPath, data);
				System.out.println("");
			}

			@Override
			public void handleDataDeleted(String dataPath) throws Exception {
				System.out.printf("数据删除%s", dataPath);
			}

		});

		zkClient.createPersistent(path, "data");
		
//		注释掉为正常监听使用
//		zkClient.readData(path); 
//
//		zkClient.writeData(path, "data_new1"); 
//		
//		zkClient.readData(path);
//		
//		zkClient.writeData(path, "data_new2"); 
//		
//		zkClient.readData(path);
//		
//		zkClient.writeData(path, "data_new3"); 
//		
//		zkClient.readData(path);
//		
//		zkClient.writeData(path, "data_new4"); 
//		
//		zkClient.readData(path);
//		
//		zkClient.delete(path,-1);
		
//		下面演示无getData等操作的演示,  
		zkClient.writeData(path, "data_new1"); // 触发 -- 原因,每次Listener运行后,会再次注册watch。
				
		zkClient.writeData(path, "data_new2"); 
				
		zkClient.writeData(path, "data_new3");  // 触发 -- 同上
				
		zkClient.writeData(path, "data_new4");
				
		zkClient.delete(path,-1);
		
	}
	
}

class User implements Serializable {

	private static final long serialVersionUID = 7859434873243822876L;

	private Integer id;
	
	private String username;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}
	
}

 

 

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值