Zookeeper java API的使用

版权声明:个人原创,转载请标注! https://blog.csdn.net/Z_Date/article/details/83830572

目录

 

1、 eclipse环境配置

.2 、基本操作

3、 监听集群中主机的上下线


1、 eclipse环境配置

  • 普通的java项目

    1. 创建一个java项目

    2. 依赖的jar包

zookeeper-3.4.7\lib下的
	jline-0.9.94.jar
	log4j-1.2.15.jar
	netty-3.2.2.Final.jar
	slf4j-api-1.6.1.jar
	slf4j-log4j12-1.6.1.jar
zookeeper-3.4.7\zookeeper-3.4.7.jar
  • maven项目
  • 创建maven项目步骤:略

  1. pom.xml (查询该坐标的网站:http://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper/3.4.7)

<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.7</version>
    <type>pom</type>
</dependency>

在maven工程的src/main/resource目录放置一个log4j.properties,其内容如下:

# Rules reminder:
# DEBUG < INFO < WARN < ERROR < FATAL
# Global logging configuration
log4j.rootLogger=INFO,R,stdout
## File output...
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=/home/hadoop/flume/logs/test.log
log4j.appender.R.MaxFileSize=100MB
log4j.appender.R.MaxBackupIndex=7
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d [%t] %-5p%l method\:%M %m%n
#log4j.logger.org.apache.catalina=INFO,R,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p%l method\:%M %m%n
#%d:显示日志记录时间
#[%t]:输出产生该日志事件的线程名
#%-5p:显示该条日志的优先级
#%l:输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数
#%M:方法名
#%m:显示输出消息
#%n:当前平台下的换行符

.2 、基本操作

public class TestCRUD {

	private static final String connectString = "min1:2181," +"min2:2181," +"min3:2181";
	private static final int sessionTimeout = 2000;
	
	@Test
	public void testConnect(){
		ZooKeeper zkClient = null;
		try {
			//连接成功后,会回调watcher监听,此连接操作是异步的,执行完new语句后,直接调用后续代码
			zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
				/**
				 * public enum EventType {
				            None (-1),
				            NodeCreated (1),
				            NodeDeleted (2),
				            NodeDataChanged (3),
				            NodeChildrenChanged (4);
				 */
				@Override
				public void process(WatchedEvent event) {
					// 收到事件通知后的回调函数(应该是我们自己的事件处理逻辑)
					System.out.println("=========="+event.getType()+"===="+event.getState()); 
				}
			});
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		//连接状态值   CONNECTING, ASSOCIATING, CONNECTED, CONNECTEDREADONLY,
		System.out.println("-------------------"+zkClient.getState());
		while(true){
			try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
			//等待zookeeper客户端连接服务器成功的,查看连接时的状态信息。
			System.out.println("====-----===="+zkClient.getState());
		}
	}
	
	
	@Test	
	public void testCreate() throws Exception {
		ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, 
				new Watcher() {
					@Override
					public void process(WatchedEvent event) {
						System.out.println("=========="+event.getType()); 
					}
		});
		
		Thread.sleep(10*1000);//等待的目的是使zookeeper客户端连接成功后,才执行后续操作
		
		if(zkClient.getState() == States.CONNECTED){//连接服务器连接成功
			String nodeCreated = zkClient.create("/age", //:要创建的节点的路径
					"18".getBytes(), //节点中的数据
					Ids.OPEN_ACL_UNSAFE, //节点的权限
					CreateMode.PERSISTENT);//节点的类型
			System.out.println("创建成功后,节点的真是路径是:"+nodeCreated);
		}		
	}
	
	//判断znode是否存在
	@Test	
	public void testExist() throws Exception{
		
		ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, 
				new Watcher() {
					//修改目标节点   event.getType()的值是NodeDataChanged
					@Override
					public void process(WatchedEvent event) {
						System.out.println("=========="+event.getType()); 
					}
		});
		
		Thread.sleep(10*1000);//等待的目的是使zookeeper客户端连接成功后,才执行后续操作
		
		//第二个参数表示  是否监听”/age“节点的状态的改变,为true时,则监听,当另一个zookeeper客户端修改、删除该节点的值时,回调watcher
		Stat stat = zkClient.exists("/age", true);
		System.out.println(stat==null?"not exist":"exist");
		
		Thread.sleep(20*1000);
	}
	
	//获取znode的数据
	@Test
	public void getData() throws Exception {
		ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, 
				new Watcher() {
					@Override
					public void process(WatchedEvent event) {
						System.out.println("=========="+event.getType()); 
					}
		});
		
		Thread.sleep(10*1000);//等待的目的是使zookeeper客户端连接成功后,才执行后续操作
		
		byte[] data = zkClient.getData("/age", false, null);
		System.out.println(new String(data));
		
	}
	
	// 获取子节点
	@Test
	public void getChildren() throws Exception {
		ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, 
				new Watcher() {
					@Override
					public void process(WatchedEvent event) {
						System.out.println("=========="+event.getType()); 
					}
		});
		
		Thread.sleep(10*1000);//等待的目的是使zookeeper客户端连接成功后,才执行后续操作
		
		//只能获得一个路径下的直接子节点的信息,不能递归获取孙节点
		List<String> children = zkClient.getChildren("/", true);
		for (String child : children) {
			System.out.println(child);
		}
		Thread.sleep(Long.MAX_VALUE);
	}
		
	
	//删除znode
	@Test
	public void deleteZnode() throws Exception {
		ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, 
				new Watcher() {
					@Override
					public void process(WatchedEvent event) {
						System.out.println("=========="+event.getType()); 
					}
		});
		
		Thread.sleep(10*1000);//等待的目的是使zookeeper客户端连接成功后,才执行后续操作
		
		//参数2:指定要删除的版本,-1表示删除所有版本
		zkClient.delete("/age", -1);
	
	}
}

3、 监听集群中主机的上下线

案例说明:

1.DistributedServer程序一运行起来就向zookeeper的/servers路径下创建一个临时节点

如该类启动三个实例时,分别为传入三个字符串,分别为   server1,server2,server3
	根据代码逻辑,会在zookeeper的/servers下创建三个EPHEMERAL_SEQUENTIAL类型的节点,节点名为
		/servers/server000001    此节点对应的value是server1   
		/servers/server000002    此节点对应的value是server2
		/servers/server000003    此节点对应的value是server3 

2.DistributedClient代码实时夺取/servers下的节点集合内容 如 [/servers/server000001,/servers/server000002,/servers/server000003] 说明这个客户端所在的机器,可用的集群有三台机器 DistributedClient代码监听了/servers目录的子节点,当有机器掉线时,/servers下的节点集合内容会变化的 如 [/servers/server000001,,/servers/server000003] [/servers/server000003] 这样也就实时感知了三台集群中机器的状态

总结:有四台机器组成的集群,如a1,a2,a3,a4其中a1是主节点;a2,a3,a4是从节点 DistributedServer代码分别运行在a2,a3,a4从节点上 DistributedClient代码运行在a1主节点上

代码如下:

public class DistributedServer {
	
	private static final String connectString = "min1:2181," +"min2:2181," +"min3:2181";
	private static final int sessionTimeout = 2000;
	private static final String parentNode = "/test2017-12-25";

	private ZooKeeper zk = null;

	public static void main(String[] args) throws Exception {

		// 获取zk连接
		DistributedServer server = new DistributedServer();
		server.getConnect();
		Thread.sleep(10*1000);
		// 利用zk连接注册服务器信息
		server.registerServer(args[0]);
		// 启动业务功能
		server.handleBussiness(args[0]);
	}
	
	/**
	 * 创建到zk的客户端连接
	 */
	public void getConnect() throws Exception {

		zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
			@Override
			public void process(WatchedEvent event) {
				// 收到事件通知后的回调函数(应该是我们自己的事件处理逻辑)
				System.out.println(event.getType() + "---" + event.getPath());
				try {
					zk.getChildren("/", true);
				} catch (Exception e) {
				}
			}
		});
	}

	/**
	 * 向zk集群注册服务器信息
	 */
	public void registerServer(String hostname) throws Exception {
		// CreateMode.EPHEMERAL_SEQUENTIAL  节点类型
		/**
		 * 参数3 acl是Access Contral
		 * ZooKeeper使用ACL来控制访问其znode(ZooKeeper的数据树的数据节点)。ACL的实现方式非常类似于UNIX文件的访问权限:它采用访问权限位 允许/禁止 对节点的各种操作以及能进行操作的范围。
		 * 不同于UNIX权限的是,ZooKeeper的节点不局限于 用户(文件的拥有者),组和其他人(其它)这三个标准范围。ZooKeeper不具有znode的拥有者的概念。相反,ACL指定id集以及与之对应的权限。
		 * http://ifeve.com/zookeeper-access-control-using-acls/
		 */
		String create = zk.create(parentNode + "/server", hostname.getBytes(), 
				Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
		System.out.println(hostname + "is online.." + create);
	}

	/**
	 * 业务功能
	 */
	public void handleBussiness(String hostname) throws InterruptedException {
		System.out.println(hostname + "start working.....");
		Thread.sleep(Long.MAX_VALUE);
	}
}
public class DistributedClient {

	private static final String connectString = "min1:2181," +"min2:2181," +"min3:2181";
	private static final int sessionTimeout = 2000;
	private static final String parentNode = "/test2017-12-25";
	private volatile List<String> serverList;
	private ZooKeeper zk = null;

	public static void main(String[] args) throws Exception {

		// 获取zk连接
		DistributedClient client = new DistributedClient();
		client.getConnect();
		Thread.sleep(10*1000);
		
		// 获取servers的子节点信息(并监听),从中获取服务器信息列表
		client.getServerList();

		// 业务线程启动
		client.handleBussiness();
	}
	/**
	 * 创建到zk的客户端连接
	 */
	public void getConnect() throws Exception {

		zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
			@Override
			public void process(WatchedEvent event) {
				// 收到事件通知后的回调函数(应该是我们自己的事件处理逻辑)
				try {
					//重新更新服务器列表,并且注册了监听
					getServerList();
				} catch (Exception e) {}
			}
		});
	}

	/**
	 * 获取服务器信息列表
	 */
	public void getServerList() throws Exception {

		// 获取服务器子节点信息,并且对父节点进行监听
		List<String> children = zk.getChildren(parentNode, true);

		// 先创建一个局部的list来存服务器信息
		List<String> servers = new ArrayList<String>();
		for (String child : children) {
			// child只是子节点的节点名
			byte[] data = zk.getData(parentNode + "/" + child, false, null);
			servers.add(new String(data));
		}
		// 把servers赋值给成员变量serverList,已提供给各业务线程使用
		serverList = servers;
		
		//打印服务器列表
		System.out.println(serverList);
		
	}

	/**
	 * 业务功能
	 * 
	 * @throws InterruptedException
	 */
	public void handleBussiness() throws InterruptedException {
		System.out.println("client start working.....");
		Thread.sleep(Long.MAX_VALUE);
	}
}

猜你喜欢

转载自blog.csdn.net/Z_Date/article/details/83830572