Zookeeper registry of dubbo

Keywords: Java Zookeeper Dubbo Redis

At present, dubbo supports a variety of registration centers: Zookeeper, Redis, Simple, Multicast, Etcd3.

This article analyzes how dubbo integrates Zookeeper to register and subscribe services when Zookeeper is used as the registration center.

First, Dubbo registers the service with Zookeeper, and the directory structure is as follows: (registration interface name: com.bob.dubbo.service.CityDubboService)

When the consumer and provider services are started, format their own URL into a string, and then register it under the corresponding node of zookeeper as a temporary node. After disconnection, the node will be deleted. When the consumer starts, it will not only subscribe to the service, but also register its own URL into zookeeper;

ZookeeperRegistry

ZookeeperRegistry: the main interaction classes between dubbo and zookeeper have been analyzed in combination with the source code. First, let's look at the doSubcribe() method:

@Override
    public void doSubscribe(final URL url, final NotifyListener listener) {
        try {
            // Handle all subscriptions initiated by the service layer, such as those in the monitoring center
            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<>());
                    listeners = zkListeners.get(url);
                }
                ChildListener zkListener = listeners.get(listener);
                if (zkListener == null) {
                    listeners.putIfAbsent(listener, (parentPath, 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);
                    }
                }
                // Process subscriptions initiated by the specified service layer, such as those of service consumers
            } else {
                List<URL> urls = new ArrayList<>();
                // Circular classification array, router, configurator, provider
                for (String path : toCategoriesPath(url)) {
                    // Get the listener set corresponding to url
                    ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
                    if (listeners == null) {// No, create
                        zkListeners.putIfAbsent(url, new ConcurrentHashMap<>());
                        listeners = zkListeners.get(url);
                    }
                    // Get ChildListener object
                    ChildListener zkListener = listeners.get(listener);
                    if (zkListener == null) {//  No listener exists for subdirectory to create ChildListener object
                        // Subscribe to the parent directory. When any child node changes, this callback function will be triggered and the notify() method in the listener will be called back
                        listeners.putIfAbsent(listener, (parentPath, currentChilds) -> ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds)));
                        zkListener = listeners.get(listener);
                    }
                    // Initiate subscription to Zookeeper, PATH node, and return all child elements under this node PATH: / root node / interface full name / providers, such as / dubbo/com.bob.service.CityService/providers
                    zkClient.create(path, false);
                    List<String> children = zkClient.addChildListener(path, zkListener);
                    if (children != null) {
                        urls.addAll(toUrlsWithEmpty(url, path, children));
                    }
                }
                // When the first full data acquisition is completed, call the 'notify(...)' method and call back the NotifyListener. In this step, instantiate the Invoker from the connection Provider
                notify(url, listener, urls);
            }
        } catch (Throwable e) {
            throw new RpcException("Failed to subscribe " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

Posted by Tensing on Sun, 01 Dec 2019 08:10:43 -0800