Zookeeper data synchronization -Bootstrap end


Introduction to the

This article explores Zookeeper data synchronization for Soul gateway Bootstrap

The sample start

Environment configuration

Start mysql and ZK with Docker

docker run -dit --name zk -p 2181:2181 zookeepe
docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:latest
Copy the code

Soul – Admin configuration

Soul-admin and soul-bootstrap Websocket synchronization are disabled, and HTTP synchronization is enabled.

Soul-admin’s HTTP synchronization configuration temporarily disables other synchronization methods for comments

  sync:
      zookeeper:
          url: localhost:2181
          sessionTimeout: 5000
          connectionTimeout: 2000
Copy the code

Soul – the Bootstrap configuration

Soul-bootstrap Http synchronization configuration, temporarily comment out other synchronization methods

soul :
    file:
      enabled: true
    corss:
      enabled: true
    dubbo :
      parameter: multi
    sync:
        zookeeper:
             url: localhost:2181
             sessionTimeout: 5000
             connectionTimeout: 2000
Copy the code

Boot failure

Start soul-admin, soul-bootstrap, and soul-example HTTP

http://localhost:9195/dubbo/findById? Id =1, failed to access the link

No data was found during debugging, and data will be sent when only changes are made. If you restart it, try again

I feel it may be a bug, but first I rule out my own code version and my own use of the problem, I asked the elder brother in the group, and found that it is my own use of the problem

Start the repair

The solution is to pull your own code, make sure it is up to date, then delete the soul data in ZooKeeper, restart Admin and Bootstrap, and re-access

The following is the ZK graphical client, which is easy to compare prices, and also can be used in Win (the first startup may not display the full display, you can turn off and start again). The following is the installation tutorial and download link found in search:

  • Use the ZooKeeper graphical client tool ZooInspector
  • Issues.apache.org/jira/secure…

The source code to view

We directly located into the Soul gateway source code reading (12) data synchronization preliminary zK synchronization entry class: ZookeeperSyncDataService

If you have used ZK for a little bit, you can see the familiar Watch, which monitors the changes of data. From the following code, you can roughly see the monitoring of the five kinds of data I analyzed previously: plug-in data, selector data, rule data, AppAuth data and Metadata data

public class ZookeeperSyncDataService implements SyncDataService.AutoCloseable {

    public ZookeeperSyncDataService(final ZkClient zkClient, final PluginDataSubscriber pluginDataSubscriber,
                                    final List<MetaDataSubscriber> metaDataSubscribers, final List<AuthDataSubscriber> authDataSubscribers) {
        this.zkClient = zkClient;
        this.pluginDataSubscriber = pluginDataSubscriber;
        this.metaDataSubscribers = metaDataSubscribers;
        this.authDataSubscribers = authDataSubscribers;
        watcherData();
        watchAppAuth();
        watchMetaData();
    }

    private void watcherAll(final String pluginName) { watcherPlugin(pluginName); watcherSelector(pluginName); watcherRule(pluginName); }}Copy the code

We hit a breakpoint on the constructor, look at the call stack, and find that it is similar to HTTP synchronization, as shown in the code below, which is started using Spring mode

public class ZookeeperSyncDataConfiguration {
   
    @Bean
    public SyncDataService syncDataService(final ObjectProvider<ZkClient> zkClient, final ObjectProvider<PluginDataSubscriber> pluginSubscriber,
                                           final ObjectProvider<List<MetaDataSubscriber>> metaSubscribers, final ObjectProvider<List<AuthDataSubscriber>> authSubscribers) {
        log.info("you use zookeeper sync soul data.......");
        return new ZookeeperSyncDataService(zkClient.getIfAvailable(), pluginSubscriber.getIfAvailable(),
                metaSubscribers.getIfAvailable(Collections::emptyList), authSubscribers.getIfAvailable(Collections::emptyList));
    }

    @Bean
    public ZkClient zkClient(final ZookeeperConfig zookeeperConfig) {
        return newZkClient(zookeeperConfig.getUrl(), zookeeperConfig.getSessionTimeout(), zookeeperConfig.getConnectionTimeout()); }}Copy the code

Simple debugging and look, found that zK synchronization mode and Websocket is relatively simple, the structure is also very clear, here will not do too much introduction, on its core logic, the code is as follows:

Constructor to start all data listening, and five types of node initialization

Need to pay attention to understand is the list of data monitoring (monitoring additions and deletions, etc.), monitoring the change of a single data in the list, the code monitoring is basically this kind of routine, pay attention to understand

public class ZookeeperSyncDataService implements SyncDataService.AutoCloseable {

    public ZookeeperSyncDataService(final ZkClient zkClient, final PluginDataSubscriber pluginDataSubscriber,
                                    final List<MetaDataSubscriber> metaDataSubscribers, final List<AuthDataSubscriber> authDataSubscribers) {
        this.zkClient = zkClient;
        this.pluginDataSubscriber = pluginDataSubscriber;
        this.metaDataSubscribers = metaDataSubscribers;
        this.authDataSubscribers = authDataSubscribers;
        // The following three functions initialize and start the listener
        watcherData();
        watchAppAuth();
        watchMetaData();
    }

    private void watcherData(a) {
        final String pluginParent = ZkPathConstants.PLUGIN_PARENT;
        // Get the list of plug-ins and start the listener (in which the plugin data, selectors, and rules are initialized)
        List<String> pluginZKs = zkClientGetChildren(pluginParent);
        for (String pluginName : pluginZKs) {
            watcherAll(pluginName);
        }
        
        // Start listening, update data (new and modified), listen for updated plug-ins
        zkClient.subscribeChildChanges(pluginParent, (parentPath, currentChildren) -> {
            if (CollectionUtils.isNotEmpty(currentChildren)) {
                for(String pluginName : currentChildren) { watcherAll(pluginName); }}}); }private void watcherAll(final String pluginName) {
        watcherPlugin(pluginName);
        watcherSelector(pluginName);
        watcherRule(pluginName);
    }

    private void watcherPlugin(final String pluginName) {
        String pluginPath = ZkPathConstants.buildPluginPath(pluginName);
        if(! zkClient.exists(pluginPath)) { zkClient.createPersistent(pluginPath,true);
        }
        // Initialize plug-in data
        cachePluginData(zkClient.readData(pluginPath));
        // Listen for plug-in data
        subscribePluginDataChanges(pluginPath, pluginName);
    }

    // The selector structure is roughly: plug-in --> list of selectors --> single selector
    // So ultimately you need to initialize and listen on a single selector
    // Listen on the upper list of selectors, and the list will update
    private void watcherSelector(final String pluginName) {
        String selectorParentPath = ZkPathConstants.buildSelectorParentPath(pluginName);
        List<String> childrenList = zkClientGetChildren(selectorParentPath);
        if (CollectionUtils.isNotEmpty(childrenList)) {
            childrenList.forEach(children -> {
                String realPath = buildRealPath(selectorParentPath, children);
                cacheSelectorData(zkClient.readData(realPath));
                subscribeSelectorDataChanges(realPath);
            });
        }
        subscribeChildChanges(ConfigGroupEnum.SELECTOR, selectorParentPath, childrenList);
    }

    // Same principle as selector
    private void watcherRule(final String pluginName) {
        String ruleParent = ZkPathConstants.buildRuleParentPath(pluginName);
        List<String> childrenList = zkClientGetChildren(ruleParent);
        if (CollectionUtils.isNotEmpty(childrenList)) {
            childrenList.forEach(children -> {
                String realPath = buildRealPath(ruleParent, children);
                cacheRuleData(zkClient.readData(realPath));
                subscribeRuleDataChanges(realPath);
            });
        }
        subscribeChildChanges(ConfigGroupEnum.RULE, ruleParent, childrenList);
    }

    // It works like a selector
    private void watchAppAuth(a) {
        final String appAuthParent = ZkPathConstants.APP_AUTH_PARENT;
        List<String> childrenList = zkClientGetChildren(appAuthParent);
        if (CollectionUtils.isNotEmpty(childrenList)) {
            childrenList.forEach(children -> {
                String realPath = buildRealPath(appAuthParent, children);
                cacheAuthData(zkClient.readData(realPath));
                subscribeAppAuthDataChanges(realPath);
            });
        }
        subscribeChildChanges(ConfigGroupEnum.APP_AUTH, appAuthParent, childrenList);
    }

    // It works like a selector
    private void watchMetaData(a) {
        final String metaDataPath = ZkPathConstants.META_DATA;
        List<String> childrenList = zkClientGetChildren(metaDataPath);
        if(CollectionUtils.isNotEmpty(childrenList)) { childrenList.forEach(children -> { String realPath = buildRealPath(metaDataPath, children); cacheMetaData(zkClient.readData(realPath)); subscribeMetaDataChanges(realPath); }); } subscribeChildChanges(ConfigGroupEnum.APP_AUTH, metaDataPath, childrenList); }}Copy the code

conclusion

Overall, the ZooKeeper synchronization approach is relatively easy to understand and the code structure is clear

If you haven’t used ZooKeeper before, you might be a little confused. Here’s a brief introduction of your own understanding:

The core of the listening mentioned in the above analysis is publish-subscribe

When the ZK client is connected to the ZK server, the server sends the changed data to the client. The client performs operations after receiving the changed data

The data for these changes can be directories (the list data mentioned above) or specific individual files (the list data)

With this in mind, you can roughly understand the heart of ZK synchronization

The zooKeeper synchronization process is as follows:

  • 1. Read initial data for initialization
  • 2. Listen for the read initialization data
  • 3. Read the changed data, update the local cache, and monitor the changed data

Soul Gateway source code analysis article list

Github

  • Soul source reading (a) overview

  • Soul source code reading (two) the initial run of the code

  • HTTP request processing overview

  • Dubbo Request Overview

  • Soul Gateway source code reading (five) request type exploration

  • Soul Gateway source code reading (6) Sofa request processing overview

  • Soul gateway source code reading (seven) a stream limit plug-in exploration

  • Soul gateway source code reading (eight) route matching exploration

  • Soul Gateway source code reading (nine) plug-in configuration load preliminary discussion

  • Soul Gateway source code reading (ten) custom simple plug-in written

  • Soul Gateway source code read (11) request processing summary

  • Soul Gateway source code reading (12) data synchronization preliminary -Bootstrap end

  • Soul Gateway source code reading (thirteen) Websocket synchronization data -Bootstrap end

  • Soul Gateway source code reading (14) HTTP data synchronization -Bootstrap end

  • Zookeeper data synchronization -Bootstrap end

  • HTTP parameter request error

The Denver nuggets

  • Soul Gateway source code read (a) overview

  • Soul Gateway source code reading (two) the initial operation of the code

  • Soul Gateway source code reading (3) Request processing overview

  • Dubbo Request Overview

  • Soul Gateway source code reading (five) request type exploration

  • Soul Gateway source code reading (6) Sofa request processing overview

  • Soul gateway source code reading (seven) a stream limit plug-in exploration

  • Soul gateway source code reading (eight) route matching exploration

  • Soul Gateway source code reading (nine) plug-in configuration load preliminary discussion

  • Soul Gateway source code reading (ten) custom simple plug-in written

  • Soul Gateway source code read (11) request processing summary

  • Soul Gateway source code reading (12) data synchronization

  • Soul Gateway source code reading (thirteen) Websocket synchronization data -Bootstrap end

  • Soul Gateway source code reading (14) HTTP data synchronization -Bootstrap end

  • HTTP parameter request error