Introduction to the

This article begins to enter the analysis of the Soul gateway data synchronization related source code, first look at the data is what data, the general principle and way of synchronization

Source code for the Debug

Data this is where the relevant data should be routed, used in the program for rule matching, obtaining the real address of the back-end server, and so on

In the previous analysis of the processing flow, we know that the core code for route matching is as follows:

public abstract class AbstractSoulPlugin implements SoulPlugin {...public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
        String pluginName = named();
        // Get the plug-in configuration
        final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);
        if(pluginData ! =null && pluginData.getEnabled()) {
            // Get the selector
            finalCollection<SelectorData> selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName); .// Get the rule
            finalSelectorData selectorData = matchSelector(exchange, selectors); . }returnchain.execute(exchange); }... }Copy the code

As you can see, there are three types of data: plug-in configuration data, selector data, and rule data. All of these data are retrieved from BaseDataCache. Let’s take a look at the core code:

public final class BaseDataCache {
    
    private static final BaseDataCache INSTANCE = new BaseDataCache();
    
    /** * pluginName -> PluginData. */
    private static final ConcurrentMap<String, PluginData> PLUGIN_MAP = Maps.newConcurrentMap();
    
    /** * pluginName -> SelectorData. */
    private static final ConcurrentMap<String, List<SelectorData>> SELECTOR_MAP = Maps.newConcurrentMap();
    
    /** * selectorId -> RuleData. */
    private static final ConcurrentMap<String, List<RuleData>> RULE_MAP = Maps.newConcurrentMap();

    public void cachePluginData(final PluginData pluginData) {
        Optional.ofNullable(pluginData).ifPresent(data -> PLUGIN_MAP.put(data.getName(), data));
    }

    public void removePluginData(final PluginData pluginData) {
        Optional.ofNullable(pluginData).ifPresent(data -> PLUGIN_MAP.remove(data.getName()));
    }
    
    public PluginData obtainPluginData(final String pluginName) {
        return PLUGIN_MAP.get(pluginName);
    }

    public void cacheSelectData(final SelectorData selectorData) {
        Optional.ofNullable(selectorData).ifPresent(this::selectorAccept);
    }

    public void removeSelectData(final SelectorData selectorData) {
        Optional.ofNullable(selectorData).ifPresent(data -> {
            final List<SelectorData> selectorDataList = SELECTOR_MAP.get(data.getPluginName());
            Optional.ofNullable(selectorDataList).ifPresent(list -> list.removeIf(e -> e.getId().equals(data.getId())));
        });
    }
    
    public List<SelectorData> obtainSelectorData(final String pluginName) {
        return SELECTOR_MAP.get(pluginName);
    }

    public void cacheRuleData(final RuleData ruleData) {
        Optional.ofNullable(ruleData).ifPresent(this::ruleAccept);
    }
    
    public void removeRuleData(final RuleData ruleData) {
        Optional.ofNullable(ruleData).ifPresent(data -> {
            final List<RuleData> ruleDataList = RULE_MAP.get(data.getSelectorId());
            Optional.ofNullable(ruleDataList).ifPresent(list -> list.removeIf(rule -> rule.getId().equals(data.getId())));
        });
    }

    public List<RuleData> obtainRuleData(final String selectorId) {
        returnRULE_MAP.get(selectorId); }}Copy the code

As can be seen from the above code, this is a static singleton class. The name of each method can be roughly seen as adding, deleting, changing and checking plug-in configuration data, selector configuration data and rule configuration data

Cachexxxx and RemoVEXXXX are the corresponding update and delete operations (adding and modifying operations are the same for Map)

Let’s take a look at where the CachexXX and RemoVEXXXXX methods are referenced

We use the IDEA, Alt + F7 view used in those places, find down, through processing BaseDataCache class, the class itself and some relevant test only CommonPluginDataSubscriber call this class, This class is the core data synchronization class, the approximate code is as follows:

public class CommonPluginDataSubscriber implements PluginDataSubscriber {...// We can see that there is a slight flaw in the naming of the function; OnSubscribe is not a very good function, it's a little bit too general
    @Override
    public void onSubscribe(final PluginData pluginData) {
        subscribeDataHandler(pluginData, DataEventTypeEnum.UPDATE);
    }
    
    @Override
    public void unSubscribe(final PluginData pluginData) {
        subscribeDataHandler(pluginData, DataEventTypeEnum.DELETE);
    }

    public void onSelectorSubscribe(final SelectorData selectorData) {
        subscribeDataHandler(selectorData, DataEventTypeEnum.UPDATE);
    }
    
    @Override
    public void unSelectorSubscribe(final SelectorData selectorData) {
        subscribeDataHandler(selectorData, DataEventTypeEnum.DELETE);
    }

    @Override
    public void onRuleSubscribe(final RuleData ruleData) {
        subscribeDataHandler(ruleData, DataEventTypeEnum.UPDATE);
    }
    
    @Override
    public void unRuleSubscribe(final RuleData ruleData) {
        subscribeDataHandler(ruleData, DataEventTypeEnum.DELETE);
    }
    
    private <T> void subscribeDataHandler(final T classData, final DataEventTypeEnum dataType) {
        Optional.ofNullable(classData).ifPresent(data -> {
            if (data instanceof PluginData) {
                PluginData pluginData = (PluginData) data;
                if (dataType == DataEventTypeEnum.UPDATE) {
                    // Update the plug-in configuration data
                    BaseDataCache.getInstance().cachePluginData(pluginData);
                    Optional.ofNullable(handlerMap.get(pluginData.getName())).ifPresent(handler -> handler.handlerPlugin(pluginData));
                } else if (dataType == DataEventTypeEnum.DELETE) {
                    // Delete plug-in configuration dataBaseDataCache.getInstance().removePluginData(pluginData); Optional.ofNullable(handlerMap.get(pluginData.getName())).ifPresent(handler -> handler.removePlugin(pluginData)); }}else if (data instanceof SelectorData) {
                SelectorData selectorData = (SelectorData) data;
                if (dataType == DataEventTypeEnum.UPDATE) {
                    // Update the selector data
                    BaseDataCache.getInstance().cacheSelectData(selectorData);
                    Optional.ofNullable(handlerMap.get(selectorData.getPluginName())).ifPresent(handler -> handler.handlerSelector(selectorData));
                } else if (dataType == DataEventTypeEnum.DELETE) {
                    // Delete the selector dataBaseDataCache.getInstance().removeSelectData(selectorData); Optional.ofNullable(handlerMap.get(selectorData.getPluginName())).ifPresent(handler -> handler.removeSelector(selectorData)); }}else if (data instanceof RuleData) {
                RuleData ruleData = (RuleData) data;
                if (dataType == DataEventTypeEnum.UPDATE) {
                    // Update the rule data
                    BaseDataCache.getInstance().cacheRuleData(ruleData);
                    Optional.ofNullable(handlerMap.get(ruleData.getPluginName())).ifPresent(handler -> handler.handlerRule(ruleData));
                } else if (dataType == DataEventTypeEnum.DELETE) {
                    // Delete rule dataBaseDataCache.getInstance().removeRuleData(ruleData); Optional.ofNullable(handlerMap.get(ruleData.getPluginName())).ifPresent(handler -> handler.removeRule(ruleData)); }}}); }}Copy the code

In the code above, we see that it encapsulates the update of the related data, and we find a point where the naming is not very good

Let’s take a look at these: where a function like onSelectorSubscribe is called, found by Alt+F7 (check the test class and itself), there are three modules that reference it:

  • soul-sync-data-http : PluginDataRefresh
  • soul-sync-data-nacos : NacosCacheHandler
  • soul-sync-data-websocket : PluginDataHandler
  • soul-sync-data-zookeeper : ZookeeperSyncDataService

Combined with the previous understanding, it can be seen that there are four synchronization modules: HTTP, Nacos, Websocket and ZooKeeper

The idea of synchronization module of the code difference is relatively large, that is the analysis of the four articles ah

conclusion

This article Outlines the basic data synchronization comparison classes:

  • BaseDataCache: Configure the cache, update, delete, and query
  • CommonPluginDataSubscriber: BaseDataCache encapsulation, providing update and delete
  • Synchronization module: call CommonPluginDataSubscriber interface for data synchronization
    • soul-sync-data-http : PluginDataRefresh
    • soul-sync-data-nacos : NacosCacheHandler
    • soul-sync-data-websocket : PluginDataHandler
    • soul-sync-data-zookeeper : ZookeeperSyncDataService

This article has a general understanding of data synchronization, and the following article starts to analyze the four synchronization modules

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

  • 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