사육사 준비 :
- Zookeeper 서버 측 다운로드 (여기에는 apache-zookeeper-3.5.5.tar.gz 다운로드가 아닌 구덩이가 있습니다) : http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.5.5/apache- 사육사-3.5.5-bin.tar.gz
- {zookeeper_base} \ conf \ zoo_sample.cfg를 현재 디렉토리에 복사하고 이름을 zoo.cfg로 변경하십시오.
- {zookeeper_base} \ bin \ zkServer.cmd 시작
클래스 상속 관계 :
- RegistryService는 register register (URL url), unregister unregister (URL url), subscribe (URL url, NotifyListener listener), unsubscribe unsubscribe (URL url, NotifyListener listener), lookup (URL url))의 5 가지 인터페이스를 제공합니다.
- FailbackRegistry는 RegistryService의 구현 클래스로, 구독 실패 및 구독 취소 실패 (시간이 지정된 작업을 사용하여 주기적으로 재시도)를 재 시도합니다. 또한 추상 메소드 doRegister (URL url), doUnregister (URL url), doSubscribe (URL url, NotifyListener listener), doUnsubscribe (URL url, NotifyListener listener)를 정의합니다.
- ZookeeperRegistry는 등록, 취소, 구독 및 취소 메소드를 구현하는 FailbackRegistry 추상 클래스의 구현 클래스입니다.
Zookeeper는 구성 정보의 등록 및 검색을 담당하는 레지스트리입니다. dubbo 아키텍처에서는 서비스 등록 및 검색 구현 중 하나로서 주로 서비스 인터페이스 노출을 담당하며, 노드 구성을 통해 소비자는 서비스 제공자를 찾을 수 있습니다. ZookeeperRegistry의 소스 코드를 분석해 보겠습니다.
// 服务注册时,创建节点
protected void doRegister(URL url) {
try {
// ZookeeperClient zkClient
// 后面会解析
zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
} catch (Throwable e) {
throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
// 服务解注册,删除节点
protected void doUnregister(URL url) {
try {
// ZookeeperClient zkClient
// 后面会解析
zkClient.delete(toUrlPath(url));
} catch (Throwable e) {
throw new RpcException("Failed to unregister " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
// 服务订阅
// ZookeeperRegistry#doSubscribe(final URL url, final NotifyListener listener)
protected void doSubscribe(final URL url, final NotifyListener listener) {
try {
if (Constants.ANY_VALUE.equals(url.getServiceInterface())) {
// 订阅所有节点
String root = toRootPath();
ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
if (listeners == null) {
zkListeners.putIfAbsent(url, new ConcurrentHashMap<NotifyListener, ChildListener>());
listeners = zkListeners.get(url);
}
ChildListener zkListener = listeners.get(listener);
if (zkListener == null) {
listeners.putIfAbsent(listener, new ChildListener() {
@Override
public void childChanged(String parentPath, List<String> currentChilds) {
for (String child : currentChilds) {
child = URL.decode(child);
if (!anyServices.contains(child)) {
anyServices.add(child);
subscribe(url.setPath(child).addParameters(Constants.INTERFACE_KEY, child,
Constants.CHECK_KEY, String.valueOf(false)), listener);
}
}
}
});
zkListener = listeners.get(listener);
}
zkClient.create(root, false);
List<String> services = zkClient.addChildListener(root, zkListener);
if (services != null && !services.isEmpty()) {
for (String service : services) {
service = URL.decode(service);
anyServices.add(service);
subscribe(url.setPath(service).addParameters(Constants.INTERFACE_KEY, service,
Constants.CHECK_KEY, String.valueOf(false)), listener);
}
}
} else {
// 订阅部分节点
List<URL> urls = new ArrayList<URL>();
for (String path : toCategoriesPath(url)) {
// ConcurrentMap<URL, ConcurrentMap<NotifyListener, ChildListener>> zkListeners
// 一个URL有一个ConcurrentMap<NotifyListener, ChildListener>
// NotifyListener的实现类如RegistryDirectory
// ChildListener对RegistryDirectory配置变动的监听,在其childChanged()对业务进行处理
ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
if (listeners == null) {
zkListeners.putIfAbsent(url, new ConcurrentHashMap<NotifyListener, ChildListener>());
listeners = zkListeners.get(url);
}
//
ChildListener zkListener = listeners.get(listener);
// RegistryDirectory
if (zkListener == null) {
// 创建监听器,监听节点变化
listeners.putIfAbsent(listener, new ChildListener() {
@Override
public void childChanged(String parentPath, List<String> currentChilds) {
// 有变更时会调用RegistryDirectory#notify(List<URL>)
ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds));
}
});
zkListener = listeners.get(listener);
}
// 创建持久化节点
zkClient.create(path, false);
// 为节点添加监听
// 最终调用CuratorFramework#getChildren()#usingWatcher(listener)#forPath(path)进行监听
List<String> children = zkClient.addChildListener(path, zkListener);
if (children != null) {
urls.addAll(toUrlsWithEmpty(url, path, children));
}
}
// 订阅时,会调用RegistryDirectory#notify(List<URL>)初始化
notify(url, listener, urls);
}
} catch (Throwable e) {
throw new RpcException("Failed to subscribe " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
// 取消订阅
protected void doUnsubscribe(URL url, NotifyListener listener) {
ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
if (listeners != null) {
ChildListener zkListener = listeners.get(listener);
if (zkListener != null) {
if (Constants.ANY_VALUE.equals(url.getServiceInterface())) {
// 订阅所有节点
String root = toRootPath();
zkClient.removeChildListener(root, zkListener);
} else {
for (String path : toCategoriesPath(url)) {
// 删除监听
// ((CuratorWatcherImpl) listener).unwatch()
zkClient.removeChildListener(path, zkListener);
}
}
}
}
}
ZookeeperClient의 노드 생성, 삭제 및 모니터링 작업을 살펴 보겠습니다.
// 递归创建节点
// 除了叶节点是临时节点,其余节点都是永久节点(叶节点数据会定期更新可用的服务)
// eg. /dubbo/com.alibaba.dubbo.demo.DemoService/providers/dubbo%3A%2F%2F10.0.75.1%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26bean.name%3Dcom.alibaba.dubbo.demo.DemoService%26dubbo%3D2.0.2%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D7160%26side%3Dprovider%26timestamp%3D1567860977014
// 创建节点有2种实现:CuratorZookeeperClient和ZkclientZookeeperClient,默认使用CuratorZookeeperClient实现
// AbstractZookeeperClient.create(String path, boolean ephemeral)
public void create(String path, boolean ephemeral) {
if (!ephemeral) {
// 非临时节点
if (checkExists(path)) {
// 已存在则不再创建
return;
}
}
int i = path.lastIndexOf('/');
if (i > 0) {
// 判断是否为最后一个
// 递归创建节点
create(path.substring(0, i), false);
}
if (ephemeral) {
// 创建临时节点
createEphemeral(path);
} else {
// 创建持久化节点
createPersistent(path);
}
}
// 为节点添加监听
public List<String> addChildListener(String path, final ChildListener listener) {
ConcurrentMap<ChildListener, TargetChildListener> listeners = childListeners.get(path);
if (listeners == null) {
childListeners.putIfAbsent(path, new ConcurrentHashMap<ChildListener, TargetChildListener>());
listeners = childListeners.get(path);
}
TargetChildListener targetListener = listeners.get(listener);
if (targetListener == null) {
listeners.putIfAbsent(listener, createTargetChildListener(path, listener));
targetListener = listeners.get(listener);
}
// 调用子类添加监听
// 默认实现是CuratorZookeeperClient#addTargetChildListener(path, targetListener)
return addTargetChildListener(path, targetListener);
}