分布式架构(五)-Zookeeper基本使用

前言

本文来初步介绍zookeeper的基本使用方式,及其API的使用,并且通过监听器的特性,模拟服务器注册及发现功能。

zookeeper基本使用

在启动zookeeper集群以后,使用客户端进行登入
zkCli.sh
或
zkCli.sh -server <ip地址>
基本使用:
# 查看节点包含的子节点
ls /
ls /节点/路径

# 创建节点
create /路径 数据
# 创建节点时,可以指定为临时状态(-e)还是持久状态(默认),可以设定是否有序列化(-s)

# 获取节点数据
get /路径

# 设置节点数据
set /路径 数据

# 删除节点
delete /路径

# 递归删除节点
rmr /路径
上述命令,可以使用help方式来查看:


在上述命令中可以看到,get命令和ls命令均可以设置监听器。
因此,可以根据监听器的特性,来开发服务器动态上下线的功能。下面就对此进行介绍。

Zookeeper-API

使用eclipse开发工具,创建java-project。
依赖的jar包可以在 这里下载
本机电脑修改hosts文件,我这里用的是windows:C:\Windows\System32\drivers\etc,编辑hosts文件,文件末尾添加:
192.168.232.101 zookeeper1.com
192.168.232.102 zookeeper2.com
192.168.232.103 zookeeper3.com
接下来是java工具类,需要的可以直接copy进行测试。测试前请关闭zookeeper防火墙,或开放相应端口。
package com.noryar.rpc.demo;

import java.io.IOException;
import java.util.List;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

/**
 * zookeeper核心包的基本使用方式.
 * @author Leon.
 */
public class SimpleZkClient {

	/** zookeeper集群地址,用','分隔
	 * 这里使用主机名,设置方式: C:\Windows\System32\drivers\etc\hosts
	 * 修改hosts文件,添加如下:
	 * xxx.xxx.xxx.xxx zookeeper1.com
	 * xxx.xxx.xxx.xxx zookeeper2.com
	 */
	private static final String CONNECT = "zookeeper1.com:2181,zookeeper2.com:2181,zookeeper3.com:2181";
	/** 连接超时时间 */
	private static final int TIME_OUT = 2000;
	
	public static void main(String[] args) throws IOException {
		// 获取zk连接
		// 由于zk连接是底层API,用起来不是很方便,开发时可以使用第三方封装包,例如zkClient
		// 这里就使用底层API进行介绍
		final ZooKeeper zkClient = new ZooKeeper(CONNECT, TIME_OUT, new Watcher(){
			@Override
			public void process(WatchedEvent event) {
				// TODO Auto-generated method stub
				System.out.println(event.getType() + " || " + event.getPath());
				// 初始化zkClient时,结果是:None || null
			}
		});
		
		// 创建节点,对应zk命令的create
		// 参数1:节点路径,字符串
		// 参数2:节点数据,字节数组
		// 参数3:用于控制权限,枚举类型,Ids.
		// 参数4:节点类型,枚举类型,CreateMode.
		// 返回值:创建节点的路径
		try {
			zkClient.create("/demo", "this is demo".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
		} catch (KeeperException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		// 获取子节点,对应zk命令的ls
		// 这里有多种重载方法,参数2有boolean型,如果是true,代表使用的是创建zkClient是的监听器
		// 也可以重新定义一个监听器,对应zk命令的 ls / watch
		try {
			List<String> list = zkClient.getChildren("/demo", new Watcher(){
				// 监听器只能监听一次,监听完毕以后失效。
				@Override
				public void process(WatchedEvent event) {
					// TODO Auto-generated method stub
					System.out.println("监听到节点变化");
					System.out.println("时间类型:"+event.getType());
					// 防止监听器失效,监听以后重新监听
					try {
						zkClient.getChildren("/demo", true);
					} catch (KeeperException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
			});
			System.out.println("开始打印子节点...");
			for (String string : list) {
				System.out.println(string);
			}
			System.out.println("子节点打印结束...");
			// 这里打印出的结果集中,会看到以zookeeper为名的节点。这个节点是zookeeper启动的默认节点。
			// Thread.sleep(Long.MAX_VALUE);
		} catch (KeeperException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		// 获取数据
		// 参数1:要获取的数据节点
		// 参数2:监听器,true使用创建zkClient的监听器,false不使用监听器;监听器也可以自己定义。
		// 参数3:数据状态,可以new Stat();
		try {
			byte[] data = zkClient.getData("/demo", false, null);
			System.out.println(new String(data));
		} catch (KeeperException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		// 修改数据
		// 参数1:修改数据的节点路径.
		// 参数2:新数据
		// 参数3:数据版本,如果是所有版本,用-1
		// 返回值:版本对象,Stat
		try {
			zkClient.setData("/demo", "new data".getBytes(), -1);
			System.out.println("数据经过修改,修改后:");
			byte[] data = zkClient.getData("/demo", false, null);
			System.out.println(new String(data));
		} catch (KeeperException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (InterruptedException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		// 删除节点
		// 参数1:要删除的节点路径
		// 参数2:要删除的节点版本。如果要删除所有版本,用-1
		try {
			zkClient.delete("/demo", -1);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (KeeperException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}

服务器动态上下线DEMO开发

直接上代码吧
客户端:
package com.noryar.rpc.demo.server.perception.client;

import org.apache.zookeeper.ZooKeeper;

import com.noryar.rpc.demo.server.perception.ZkClientUtil;

public class Client {

	/**
	 * 客户端启动.
	 * @param args .
	 * @throws Exception e.
	 */
	public static void main(String[] args) throws Exception {
		getAllServer();
	}

	/**
	 * 获取所有服务器.
	 * @throws Exception e.
	 */
	private static void getAllServer() throws Exception {
		ZooKeeper client = ZkClientUtil.getClient(true);
		ZkClientUtil.getAllServer(client);
		Thread.sleep(Long.MAX_VALUE);
	}
	
	
	
}
服务器端:
package com.noryar.rpc.demo.server.perception.server;

import org.apache.zookeeper.ZooKeeper;

import com.noryar.rpc.demo.server.perception.ZkClientUtil;

/**
 * 服务机.
 * @author Leon
 */
public class Server {
	
	/**
	 * 服务器启动.
	 * @param args 服务器ip.
	 * @throws Exception e.
	 */
	public static void main(String[] args) throws Exception {
		if(null == args || args.length != 1)
			System.out.println("请输入服务器ip");
		else
			register(args[0]);
	}

	/**
	 * 服务器注册.
	 * @throws Exception e.
	 */
	private static void register(String ip) throws Exception {
		ZooKeeper client = ZkClientUtil.getClient(false);
		ZkClientUtil.register(client, ip);
		Thread.sleep(Long.MAX_VALUE);
	}
}
工具类:
package com.noryar.rpc.demo.server.perception;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

/**
 * zookeeper客户端工具类.
 * @author Leon
 */
public class ZkClientUtil {

	/** zookeeper集群地址,用','分隔
	 * 这里使用主机名,设置方式: C:\Windows\System32\drivers\etc\hosts
	 * 修改hosts文件,添加如下:
	 * xxx.xxx.xxx.xxx zookeeper1.com
	 * xxx.xxx.xxx.xxx zookeeper2.com
	 */
	private static final String CONNECT = "zookeeper1.com:2181,zookeeper2.com:2181,zookeeper3.com:2181";
	/** 连接超时时间 */
	private static final int TIME_OUT = 2000;
	/** 服务器注册节点路径 */
	private static final String SVR_REG_PATH = "/preception/server";
	private static final String PARENT_SVR_PATH = "/preception";
	private static ZooKeeper zkClient = null;
	
	/**
	 * 获取zookeeper客户端.
	 * @return zkClient
	 * @throws IOException
	 */
	public static ZooKeeper getClient(final boolean startWatcher) throws IOException{
		if(null == zkClient){
			zkClient = new ZooKeeper(CONNECT, TIME_OUT, new Watcher(){
				@Override
				public void process(WatchedEvent event) {
					if(startWatcher){
						try {
							getServerNode(zkClient);
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			});
		}
		return zkClient;
	}
	
	/**
	 * 服务器注册.<br>
	 * 这里因为是模拟环境,因此自己传递一个ip地址.
	 * @param zkClient zkClient.
	 * @param ip 服务器ip地址.
	 * @throws Exception e.
	 */
	public static void register(ZooKeeper zkClient, String ip) throws Exception{
		createServerNode(zkClient, ip);
	}
	
	/**
	 * 创建服务器注册节点.
	 * @param zkClient zkClient.
	 * @param ip 服务器ip.
	 * @throws Exception e.
	 */
	private static void createServerNode(ZooKeeper zkClient, String ip) throws Exception{
		// 通过创建有编号的节点,因此path不用考虑重复了.
		zkClient.create(SVR_REG_PATH, ip.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
		System.out.println(String.format("服务器【%s】注册成功!", ip));
	}
	
	/**
	 * 获取服务器列表.
	 * @param zkClient zkClient.
	 * @throws Exception 
	 * @throws KeeperException 
	 */
	public static void getAllServer(ZooKeeper zkClient) throws Exception{
		getServerNode(zkClient);
	}

	/**
	 * 获取服务器节点.
	 * @throws Exception e.
	 */
	private static void getServerNode(ZooKeeper zkClient) throws Exception {
		List<String> serverList = zkClient.getChildren(PARENT_SVR_PATH, true);
		List<String> list = new ArrayList<String>();
		for (String string : serverList) {
			byte[] data = zkClient.getData(PARENT_SVR_PATH + "/" + string, false, null);
			list.add(new String(data));
		}
		System.out.println(list);
	}
	
}

总结

以上就简单介绍了Zookeeper的基本功能,并由此开发了服务器动态上下线感知的demo。
demo可以在 这里下载
使用时,先启动客户端,然后启动多个服务端即可。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值