系统结构:
2 节点角色:
- Server1、Server2、Server3构成了ZooKeeper注册中心,通过LeaderElection,Server2为Leader,Server1和Server3为Follower;
- Server1和Server2本身还提供服务,假设Server3不提供任何服务;
- Server4对外提供服务,但没有部署ZooKeeper服务器,不加入ZooKeeper注册中心;
- Client远程调用Server1、Server2、Server4的服务。
3 调用关系:
- Server1、Server2、Server4中对外发布的服务,在启动时向ZooKeeper注册中心注册服务;
- 服务消费者(Client)向注册中心获取服务提供者地址列表,直接调用提供者;
- 注册中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表;
- 服务消费者和服务提供者可连接注册中心任意一台ZooKeeper服务器。
4 ZooKeeper集群部署
三个ZooKeeperServer
5 ZooKeeper注册中心目录结构
6 服务提供者向注册中心注册服务信息
服务提供者将服务需要的信息通过create()函数,在注册中心创建对应的节点
/**
* registerService()
* register methord add on zookeeper
* @param args
* @throws IOException
* @throws InterruptedException
* @throws KeeperException
*/
privatestaticvoidregisterService() throws IOException, KeeperException, InterruptedException {
if (null == zk.exists("/serviceAlive", false))
zk.create("/serviceAlive", "serviceAlive".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
if (null != zk.exists("/serviceAlive", false))
zk.create("/serviceAlive/serviceAdd", "add".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
if (null == zk.exists("/ZooServerA", false))
zk.create("/ZooServerA", "ZooServerA".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
if (null == zk.exists("/ZooServerA/add", false))
zk.create("/ZooServerA/add", "add".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
if (null == zk.exists("/ZooServerA/add/url", false))
zk.create("/ZooServerA/add/url", "http://localhost:6666/add".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
if (null == zk.exists("/ZooServerA/add/namespace", false))
zk.create("/ZooServerA/add/namespace", "http://server.testzookeeper.dhong.com/".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
if (null == zk.exists("/ZooServerA/add/name", false))
zk.create("/ZooServerA/add/name", "ZooKeeperServerAService".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
String address = "http://localhost:6666/add";
Endpoint.publish(address, new ZooKeeperServerA());
System.out.println("service add started.");
}
7 服务消费者从注册中心获取服务信息
服务消费者通过getData()从注册中心获取使用服务所需的信息。
//从注册中心获得serviceAdd需要的信息
String urlAdd = new String(zkA.getData("/ZooServerA/add/url", false, null));
String nameSpaceAdd = new String(zkA.getData("/ZooServerA/add/namespace", false, null));
String nameAdd = new String(zkA.getData("/ZooServerA/add/name", false, null));
8 注册中心实时监视提供者服务状态
服务启动时,服务提供者在注册中心创建一个临时的目录"/serviceAlive/serviceAdd",当服务提供者与注册中心连接中断后,该临时节点会自动删除,注册中心通过触发与该节点关联的Watcher,从而将服务状态通知到服务的消费者。
if (null == zk.exists("/serviceAlive", false))
zk.create("/serviceAlive", "serviceAlive".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
if (null != zk.exists("/serviceAlive", false))
zk.create("/serviceAlive/serviceAdd", "add".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
9 注册中心实时通知消费者服务状态
- 服务消费者在使用服务前,检查"/serviceAlive/serviceAdd"节点是否存在,从而判断服务是否可用,并将该节点目录绑定到watchSeiverceAdd;
//检查“/serviceAlive/serviceAdd”节点是否存在,判断服务是否可用
if (null != zkA.exists("/serviceAlive/serviceAdd", watchSeiverceAdd)) {
serviceAdd = true;
}
- 当节点"/serviceAlive/serviceAdd"状态发生变化时,注册中心会自动通知到watchSeiverceAdd;收到通知的Watcher在process()方法中做相应的处理
//watchSeiverceA用于监视serviceAdd是否可用
privatestatic Watcher watchSeiverceAdd = new Watcher() {
//服务A启停watch
@Override
publicvoid process(WatchedEvent event) {
if (serviceAdd == true)
serviceAdd = false;
else
serviceAdd = true;
System.out.println("<--------------------------------------serviceAdd status changed--------------------------------------->");
try {
zkA.exists("/serviceAlive/serviceAdd", watchSeiverceAdd);
} catch (KeeperException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} ///Wather功能的一次性,处理完后重新注册
}
};