前言
在soul新版本中添加了nacos的数据同步策略,大致的同步流程如下
1
2
3
4
5
6graph LR
admin[admin启动向nacos中发送数据] --> nacos[nacos]
web[web启动时从nacos中拿取数据更新本地缓存] -->nacos[nacos]
nacos1[nacos中的数据发生更改,发送更改数据到web] --> web1[web]因为目前版本admin中的nacos数据同步,没有在启动时将数据同步到nacos中,所以目前来说,nacos数据同步方案在启动的时候需要手动进行同步,关于nacos同步策略的使用以及可能遇到的坑,可以参考Soul网关源码阅读(十六)Nacos数据同步示例运行
Admin同步数据到Nacos
- 首先,我们启动admin因为没有把数据同步到nacos,我们可以手动同步的同时观察admin同步数据到nacos的流程,结合前面的文章介绍,我们知道在admin中soul的数据同步是使用SpringEventPublisher将同步事件分发到DataChangedEventDispatcher监听器之后,再根据配置的同步策略和数据类型进行具体的同步处理
- 实际进行处理的是NacosDataChangedListener,里面各个数据同步的具体方式基本一致,随便挑一个(AppAuth的数据修改)来做说明
1 | // 更新appAuth的主体 |
- 整体的发布流程就是这样:
1 | graph LR |
Bootstrap从Nacos同步数据
- 在admin修改的数据被同步到nacos后,利用nacos的监听机制,nacos在发生数据变更,会向bootstrap发送修改的数据,接下来看看在bootstrap中,接收到nacos的数据后的具体处理流程,首先把bootstrap的同步配置改为nacos
1 | soul: |
- 我们把bootstrap的数据同步配置改为nacos之后,在bootstrap启动时,会注册一个nacos的监听,用于监听nacos发送的请求,而注册这个nacos监听的位置在NacosCacheHandler#watcherData之中,但是,实际上调用到这个方法,是在NacosSyncDataService里面调用,我们看下二者关系。
- NacosSyncDataService继承了NacosCacheHandler,而在NacosSyncDataService的start方法里是这么写的
1 | public void start() { |
- 在watcherData中就进行了nacos的Listener注册操作
1 | protected void watcherData(final String dataId, final OnChange oc) { |
- 等到有数据来了,执行对应的updatexxxMap方法,我们以updatePluginMap为例,看下具体实现
1 | protected void updatePluginMap(final String configInfo) { |
- 这里面的关键点pluginDataSubscriber,其类型为PluginDataSubscriber。而这个PluginDataSubscriber的唯一实现则是CommonPluginDataSubscriber,所以实际上调用的是CommonPluginDataSubscriber#unSubscribe和CommonPluginDataSubscriber#onSubscribe方法,这个CommonPluginDataSubscriber,之前数据同步相关文章也提及过,在bootstrap进行数据处理的时候,这是公共的处理bootstrap内本地缓存的地方,根据不同的数据类型和不同的数据操作类型,选择具体的处理器进行对应缓存更新处理,而具体的处理器,都实现了PluginDataHandler接口,但是并没有重写PluginDataHandler中的所有方法,因此在具体的处理过程中也许会使用默认实现,具体要看数据类型所对应的处理器
1 | private <T> void subscribeDataHandler(final T classData, final DataEventTypeEnum dataType) { |
- 当此处数据处理完成之后,一次数据同步就完成了,再来看下bootstrap进行数据同步的流程
1 | graph LR |
总结
- 整个nacos的同步流程大致就介绍完成了,其中有个点比较费解,在NacosDataChangedListener中,将Auth修改的数据发送到nacos之前会执行这样的代码
1 | private void updateAuthMap(final String configInfo) { |
- 不明白这样写的目的是什么,因为在执行这个更新操作之前,在admin修改了数据之后,controller到service只是先存入了数据库,然后调用Spring Publisher把数据发送到对应的listener进行修改,此时本地缓存和nacos中还是老的数据,如果要更新缓存和nacos,需要先执行上面的代码,但是上面代码的configInfo是从nacos中拿取的老数据,AUTH_MAP中也是老数据,两个老数据这样操作,不是等于没操作么???🤷♂️
后来经过讨论,这个地方应该是为了集群情况下确保修改缓存之前是从nacos的数据为基础来修改的。