zookeeper的Java API模拟服务注册与发现
构建服务提供者
构建server1
/**
* 返回唯一的zookeeper实例
* @author sheledon
*/
public class ZkFactory {
private static final int sessionTimeout = 7000;
private static volatile ZooKeeper zkClient;
private static String serverAddress = "ip1:port1,ip2:port2";
private ZkFactory() throws IOException { }
public static ZooKeeper getZkClientInstance() throws IOException {
if (zkClient==null){
synchronized (ZkFactory.class){
if (zkClient==null){
zkClient = new ZooKeeper(serverAddress,sessionTimeout,null);
}
}
}
return zkClient;
}
}
/**
* 模拟分布式系统中服务注册
* 使用zookeeper作为服务的注册中心
* @author sheledon
*/
public class Main {
private static CountDownLatch latch = new CountDownLatch(1);
public static void main(String[] args) throws InterruptedException, IOException, KeeperException {
Main main = new Main();
main.registerService();
main.provideService();
latch.await();
}
//服务注册
private void registerService() throws IOException, KeeperException, InterruptedException {
ZooKeeper zooKeeper = ZkFactory.getZkClientInstance();
String address = "127.0.0.1:8081";
String znodePath = "/service-list/service1";
zooKeeper.create(
znodePath,
address.getBytes(StandardCharsets.UTF_8),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL,
new AsyncCallback.StringCallback() {
@Override
public void processResult(int rc, String path, Object ctx, String name) {
System.out.println("注册状态: "+rc);
System.out.println("服务注册: "+path);
}
},null);
}
// socket 通信
private void provideService() throws IOException {
ServerSocket serverSocket = new ServerSocket(8081);
while (true){
Socket socket = serverSocket.accept();
System.out.println("client ip: "+socket.getInetAddress().getHostAddress());
System.out.println("client port: "+socket.getPort());
new Thread(new Runnable() {
@Override
public void run() {
try(OutputStream ops = socket.getOutputStream()){
ops.write("port is 8081 提供服务".getBytes(StandardCharsets.UTF_8));
ops.flush();
}catch (Exception e){
System.out.println(e);
}
}
}).start();
}
}
}
复制一份创建 server2
创建服务消费者
/**
* 获取服务列表的线程
* @author sheledon
*/
public class ZkService extends Thread{
//服务列表
private volatile String [] services;
private String basePath = "/service-list";
private static final int sessionTimeout = 7000;
private static volatile ZooKeeper zkClient;
private static String serverAddress = "39.104.84.176:2181,39.104.84.176:2182,39.104.84.176:2183";
private static CountDownLatch latch = new CountDownLatch(1);
public ZkService() throws IOException {
zkClient = new ZooKeeper(serverAddress,sessionTimeout,new WatcherImpl());
}
@Override
public void run() {
try {
getServiceListFromZK();
latch.await();
} catch (Exception e) {
e.printStackTrace();
}
}
public String[] getServices(){
return this.services;
}
private void getServiceListFromZK() throws IOException, KeeperException, InterruptedException {
zkClient.getChildren(basePath,true,new IChildrenCallback(),"");
}
private void getServiceAddress(List<String> serviceList) throws KeeperException, InterruptedException {
int n = serviceList.size();
if (n==0){
return ;
}
System.out.println("更新服务列表");
this.services = new String[n];
for (int i=0;i<n;++i){
byte[] data = zkClient.getData(basePath + "/" + serviceList.get(i), false, new Stat());
services[i] = new String(data, Charset.forName("utf-8"));
System.out.println(services[i]);
}
}
/**
* 获得子节点的异步回调
*/
private class IChildrenCallback implements AsyncCallback.ChildrenCallback{
@Override
public void processResult(int rc, String path, Object ctx, List<String> children) {
if (rc==0){
try {
getServiceAddress(children);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 子节点列表发生改变的监听回调
*/
private class WatcherImpl implements Watcher{
@Override
public void process(WatchedEvent event) {
if (Event.EventType.NodeChildrenChanged == event.getType()) {
zkClient.getChildren(event.getPath(),true,new IChildrenCallback(),null);
}
}
}
}
Main
/**
* 使用循环模拟从 zookeeper 中获得服务列表,然后挑选服务发起访问
*/
public class Main {
private static Socket socket ;
private static String [] services;
public static void main(String[] args) throws IOException, InterruptedException {
ZkService zkService = new ZkService();
zkService.start();
Thread.sleep(2000);
Random random = new Random(100);
//每三秒获得一次服务列表
while (true){
String [] newServices = zkService.getServices();
if (newServices!=null){
services=newServices;
}
if (services==null){
continue;
}
int i = random.nextInt(services.length);
String[] address = services[i].split(":");
socket=new Socket();
try {
socket.connect(new InetSocketAddress(address[0],Integer.parseInt(address[1])));
}catch (Exception e){
System.out.println(e);
continue;
}
InputStream inputStream = socket.getInputStream();
byte [] bs = new byte[1024];
inputStream.read(bs);
System.out.println(new String(bs, Charset.forName("utf-8")));
Thread.sleep(3000);
}
}
}