1. 什么是命名服务
命名服务是分布式系统中比较常见的一类场景。命名服务是分布式系统最基本的公共服务之一。在分布式系统中,被命名的实体通常可以是集群中的机器、提供的服务地址或远程对象等——这些我们都可以统称它们为名字(Name),其中较为常见的就是一些分布式服务框架(如RPC、RMI)中的服务地址列表,通过使用命名服务,客户端应用能够根据指定名字来获取资源的实体、服务地址和提供者的信息等。
Java中的JNDI便是一种典型的命名服务。JNDI是Java命名与目录接口(Java Naming and Irectory Interface)的缩写,是J2EE体系中重要的规范之一,标准的J2EE容器都提供了对JNDI规范的实现。因此,在实际开发中,开发人员常常使用应用服务窗口自带的JNDI实现来完成数据源的配置与管理——使用JNDI方式后,开发人员可以完全不需要关心数据库相关的任何信息,包括数据库类型、JDBC驱动类型及数据库账户等。
ZooKeeper的命名服务有两个应用方向:
- ZooKeeper提供类似JNDI服务,都能够帮助应用系统通过一个资源引用的方式来实现对资源的定位与实用。
- 利用ZooKeeper顺序节点的特性,制作分布式的ID生成器。
2. 命名服务
public class Naming {
private ZooKeeper zk = null; // ZooKeeper对象
private String nameroot = "/NameService";
/**
* @函数:命名服务构造函数
* @参数:zk的地址端口 描述:初始化zk实例,创建命名服务根路径
*/
public Naming(ZooKeeper zooKeeper) {
this.zk = zooKeeper;
// 判断是否有/NameService,如果没有,则创建该路径,用来作为所有的集中配置信息的根目录
try {
if (zk.exists(nameroot, false) == null) {
zk.create(nameroot, "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println(nameroot + " create success!");
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* @函数:注册一个全局名字
* @描述:待注册的名字字符串name,在zk中创建一个/NameService/name的znode路径
* @参数: 待注册的名字字符串name
* @返回值: 0 表示注册成功 -1 表示出错 1 表示该命名已被注册
*/
@SuppressWarnings("finally")
public boolean registered(String name,String nameValue) {
String path = nameroot + "/" + name;
try {
if (zk.exists(path, false) == null) {
zk.create(path, nameValue.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(name + " registered success!");
} else {
System.out.println(name + " is exists, can not regist again!");
}
return true;
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
/**
* @函数:注销一个全局名字
* @描述:待注销的名字字符串name,在zk中删除/NameService/name的znode路径
* @参数: 待注销的名字字符串name
* @返回值: 0 表示注销成功 -1 表示出错 1 表示该命名未注册,不存在命名服务系统中
*/
@SuppressWarnings("finally")
public boolean unRegistered(String name) {
String path = nameroot + "/" + name;
try {
if (zk.exists(path, false) != null) {
zk.delete(path, -1);
System.out.println(name + " unRegistered success!");
} else {
System.out.println(name + " is not exists, can not unRegistered!");
}
return true;
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
/**
* @函数:获取命名服务系统的所有命名
* @描述:
* @参数:
* @返回值:命名列表
*/
public List<String> readAll() {
List<String> namelist = new ArrayList<String>();
try {
namelist = zk.getChildren(nameroot, false);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return namelist;
}
/**
* @函数:获取命名服务系统的所有命名
* @描述:
* @参数:
* @返回值:命名列表
*/
public List<String> readAll(String match) {
List<String> namelist = new ArrayList<String>();
try {
namelist = zk.getChildren(nameroot, false);
namelist = namelist.stream().filter(item->item.indexOf(match)!=-1).collect(Collectors.toList());
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return namelist;
}
}
public class Test {
public static void main(String[] args) throws Exception {
ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", 5000, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("连接成功 ");
}
}, true);
Naming naming = new Naming(zk);
naming.registered("Service","127.0.0.1:2323");
naming.registered("Service","127.0.0.1:2324");
List<String> service = naming.readAll("Service");
for (String item : service) {
System.out.println(item);
byte[] data = zk.getData("/NameService/" + item, false, new Stat());
System.out.println(new String(data));
}
}
}
3. ID生成器