如何通过zookeeper实现服务注册中心
(1)发现的问题
(2)解决的方法
(3)代码实现
(1)UserService代码
package com.yyds.quartzstudy.service;
import org.apache.zookeeper.*;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class UserService {
private final static String userServicePrefix = "/services/user";
private final static String orderServicePrefix = "/services/order";
public void userService(String ip){
/**
* 1、连接上zk集群
*/
try {
String zkAddr = "192.168.42.101:2181,192.168.42.102:2181,192.168.42.103:2181";
// 只要执行一次countDown(),等待的线程就会继续执行
CountDownLatch countDownLatch = new CountDownLatch(1);
ZooKeeper zooKeeper = new ZooKeeper(zkAddr, 5000, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {// 异步创建
countDownLatch.countDown();
}
});
countDownLatch.await();
System.out.println("userService机器-" + ip + " 连接zk成功...");
/**
* 2、注册到服务注册中心
*/
register(zooKeeper, ip);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 将服务注册到服务注册中心
*/
private void register(ZooKeeper zooKeeper, String ip) {
String userServicePath = userServicePrefix + "/" + ip;
/**
* 尝试创建/services/user/{ip}节点
* 如果创建成功,表示正常注册到服务注册中心
* 此时需要去监听订单服务,一旦订单服务列表发生变化(新增,宕机),这里就会感知到
* 如果创建失败,直接退出,去查ip被占用的原因
*/
zooKeeper.create(
userServicePath,
("" + ip).getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL,
new AsyncCallback.StringCallback() {
@Override
public void processResult(int i, String s, Object o, String s1) {
if(i == KeeperException.Code.OK.intValue()){
System.out.println("userService机器-" + ip + " 将服务注册到服务注册中心成功," + "节点名称为:" + userServicePath);
// 需要去监听订单服务,一旦订单服务列表发生变化(新增,宕机),这里就会感知到
try {
List<String> orderServiceList = autoFindOrderService(zooKeeper, ip);
if(orderServiceList.size() < 1){
System.out.println("userService机器-" + ip + " 第一次 没有发现可用的订单服务...");
}else {
orderServiceList.stream()
.map(orderIp -> "userService机器-" + ip + " 第一次 发现可用的订单服务,orderService机器ip为:" + orderIp + "...")
.forEach(System.out::println);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("userService机器-" + ip + " 第一次获取order服务异常...");
}
}else if(i == KeeperException.Code.NODEEXISTS.intValue()){
System.out.println("userService机器-" + ip + " 将服务注册到服务注册中心失败," + "节点名称为:" + userServicePath);
}else {
System.out.println("userService机器-" + ip + " 错误," + "节点名称为:" + userServicePath);
}
}
/**
* 自动监听订单服务的列表
*/
private List<String> autoFindOrderService(ZooKeeper zooKeeper, String ip) throws Exception {
// 需要去监听订单服务,一旦订单服务列表发生变化(新增,宕机),这里就会感知到
List<String> children = zooKeeper.getChildren(orderServicePrefix, new Watcher() {
@Override
public void process(WatchedEvent event) {
// 如果子节点发生了变化,需要获取最新的子节点列表 并且需要继续监听
if (event.getType() == Event.EventType.NodeChildrenChanged) {
try {
List<String> orderServiceList = autoFindOrderService(zooKeeper, ip);
if(orderServiceList.size() < 1){
System.out.println("userService机器-" + ip + " 没有发现可用的订单服务...");
}else {
orderServiceList.stream()
.map(orderIp -> "userService机器-" + ip + " 发现可用的订单服务,orderService机器ip为:" + orderIp + "...")
.forEach(System.out::println);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("userService机器-" + ip + " 获取order服务异常...");
}
}else {
// 其他事件暂时不关注
System.out.println("其他事件:" + event.getType().getIntValue());
}
}
});
return children;
}
} ,
"call_back");
}
}
(2)测试代码
package com.yyds.quartzstudy.service;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
public class ServiceTest {
public static void main(String[] args) throws InterruptedException {
Arrays.asList("192.168.100.10","192.168.100.11")
.stream()
.map(ip -> (Runnable)() -> new UserService().userService(ip))
.map(Thread::new)
.forEach(Thread::start);
TimeUnit.SECONDS.sleep(10000);
}
}
(3)order服务用zk客户端模拟
userService机器-192.168.100.11 连接zk成功...
userService机器-192.168.100.10 连接zk成功...
userService机器-192.168.100.11 将服务注册到服务注册中心成功,节点名称为:/services/user/192.168.100.11
userService机器-192.168.100.10 将服务注册到服务注册中心成功,节点名称为:/services/user/192.168.100.10
userService机器-192.168.100.10 第一次 没有发现可用的订单服务...
userService机器-192.168.100.11 第一次 没有发现可用的订单服务...
用zk的命令行客户端模拟订单服务上线:
[zk: localhost:2181(CONNECTED) 8] create -e /services/order/192.168.100.10 ""
Created /services/order/192.168.100.10
[zk: localhost:2181(CONNECTED) 9] create -e /services/order/192.168.100.11 ""
Created /services/order/192.168.100.11
结果如下:
userService机器-192.168.100.11 发现可用的订单服务,orderService机器ip为:192.168.100.10...
userService机器-192.168.100.10 发现可用的订单服务,orderService机器ip为:192.168.100.10...
userService机器-192.168.100.10 发现可用的订单服务,orderService机器ip为:192.168.100.10...
userService机器-192.168.100.10 发现可用的订单服务,orderService机器ip为:192.168.100.11...
userService机器-192.168.100.11 发现可用的订单服务,orderService机器ip为:192.168.100.10...
userService机器-192.168.100.11 发现可用的订单服务,orderService机器ip为:192.168.100.11...
用zk的命令行客户端模拟订单服务下线:
[zk: localhost:2181(CONNECTED) 10] delete /services/order/192.168.100.10
结果如下:
userService机器-192.168.100.10 发现可用的订单服务,orderService机器ip为:192.168.100.11...
userService机器-192.168.100.11 发现可用的订单服务,orderService机器ip为:192.168.100.11...