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