soul源码分析数据同步篇之HTTP长轮询同步流程

本文详细分析了Soul框架中HTTP长轮询数据同步的实现,包括soul-admin和soul-bootstrap的配置,以及源码中的HttpLongPollingDataChangedListener。通过启动日志和初始化过程,揭示了长轮询的工作机制,帮助读者理解数据同步的流程。
摘要由CSDN通过智能技术生成

说明

本文代码基于soul 2021.2.4 master分支版本。

准备

请先阅读soul官方文档 数据同步原理,对soul数据同步原理有个基本的了解。

如何开启HTTP同步策略

这个小节主要引自soul官网 使用不同的数据同步策略

soul-admin的配置

application.yml中添加如下配置,或是在启动参数中添加--soul.sync.http='',然后重启服务:

soul:
  sync:
    http:
       enabled: true

soul-bootstrap的配置

引入如下依赖:

 <!--soul data sync start use http-->
<dependency>
   <groupId>org.dromara</groupId>
    <artifactId>soul-spring-boot-starter-sync-data-http</artifactId>
    <version>${last.version}</version>
</dependency>

然后修改配置文件,开启HTTP长轮询配置:

soul:
    sync:
        http:
             url : http://localhost:9095

重启soul-bootstrap即可。

HTTP长轮询原理

主要参考、整理官网文档 数据同步设计

首先,还是得拿出官方图说事儿.

在这里插入图片描述

一般客户端、服务端之间数据同步,无非推、拉两种模型。官方这张图清晰的指出HTTP长轮询是拉模式,另外的WebSocketZooKeeper则是推模式。

HTTP长轮询机制借鉴AplloNacos等框架的思想,网关soul-bootstrap会发HTTP查询请求给soul-admin,查询目前最新的配置,该查询请求超时时间为90s,即读取配置信息时soul-bootstrap最多等待就是90s。而soul-admin收到查询请求后,将会异步处理,先将其放到阻塞队列中,soul-admin会额外创建一个60s后执行的调度任务,该任务会从阻塞队列中拿到这个请求、进行处理,保证请求肯定得到响应。另一方面,如果在60s内,管理员在soul-admin中更改了配置,soul-admin会挨个移除阻塞队列中的长轮询请求、响应数据,并告知哪个group发生了变更,网关soul-bootstrap还需要额外发起请求更新对应group的数据。

知道上面信息后,再回过头来看官网这张图,是不是更清晰一些了?

在这里插入图片描述

注意:因为soul一直在迭代中,官网文档、图可能有滞后,建议一切以代码为准。

这个是思路,我们接下来分析代码,会更清晰一些。

HTTP长轮询同步流程源码分析

soul-admin源码分析

从日志分析

我个人感觉,学习开源框架源码,主要就是看官方文档、看日志输出来寻找蛛丝马迹、还有就是看初始化过程的代码。

首先,还是看日志信息:

soul-admin启动日志中,有关HTTP长轮询的部分:

......
2021-02-07 10:53:53.680  INFO 5484 --- [           main] o.d.s.a.l.AbstractDataChangedListener    : update config cache[PLUGIN], old: null, updated: {
   group='PLUGIN', md5='fad546b10dbe417e5ded73ea359eace4', lastModifyTime=1612666433680}
2021-02-07 10:53:53.694  INFO 5484 --- [           main] o.d.s.a.l.AbstractDataChangedListener    : update config cache[RULE], old: null, updated: {
   group='RULE', md5='d751713988987e9331980363e24189ce', lastModifyTime=1612666433694}
2021-02-07 10:53:53.704  INFO 5484 --- [           main] o.d.s.a.l.AbstractDataChangedListener    : update config cache[SELECTOR], old: null, updated: {
   group='SELECTOR', md5='d751713988987e9331980363e24189ce', lastModifyTime=1612666433704}
2021-02-07 10:53:53.722  INFO 5484 --- [           main] o.d.s.a.l.AbstractDataChangedListener    : update config cache[META_DATA], old: null, updated: {
   group='META_DATA', md5='d751713988987e9331980363e24189ce', lastModifyTime=1612666433722}
2021-02-07 10:53:53.723  INFO 5484 --- [           main] a.l.h.HttpLongPollingDataChangedListener : http sync strategy refresh interval: 300000ms
......

那我们基本就可以从上面日志基本可以确定,需要看AbstractDataChangedListenerHttpLongPollingDataChangedListener。看下这两个类结构、代码即可知道这里使用了模板方法设计模式,主要流程由AbstractDataChangedListener定义,HttpLongPollingDataChangedListener则实现一些细节逻辑。

在这里插入图片描述

有关细节逻辑后面分析,我们接下来从初始化过程验证一下。

从soul-admin初始化过程分析

soul-admin初始化类DataSyncConfiguration中可以看到涉及HTTP长轮询同步的代码如下:

@Configuration
public class DataSyncConfiguration {
   
    ......
        
    @Configuration
    @ConditionalOnProperty(name = "soul.sync.http.enabled", havingValue = "true")
    @EnableConfigurationProperties(HttpSyncProperties.class)
    static class HttpLongPollingListener {
   
        @Bean
        @ConditionalOnMissingBean(HttpLongPollingDataChangedListener.class)
        public HttpLongPollingDataChangedListener httpLongPollingDataChangedListener(final HttpSyncProperties httpSyncProperties) {
   
            return new HttpLongPollingDataChangedListener(httpSyncProperties);
        }
    }
    ......
}

可以看到只有配置了soul.sync.http.enabled属性,才会实例化HttpLongPollingDataChangedListener。那结合上述soul官网中提到的长轮询机制,我们可以想见,这个HttpLongPollingDataChangedListener就应该包含调度任务、阻塞队列、对于请求的处理等逻辑。

HttpLongPollingDataChangedListener分析

由于采用了模板方法设计模式,我们要对HttpLongPollingDataChangedListener分析,必须先把父类AbstractDataChangedListener逻辑搞清。

AbstractDataChangedListener主要代码如下(略去了结构重复的n多内容):

@Slf4j
@SuppressWarnings("all")
public abstract class AbstractDataChangedListener implements DataChangedListener, InitializingBean {
   
	 //常量缓存
     protected static final ConcurrentMap<String, ConfigDataCache> CACHE = new ConcurrentHashMap<>();
    //AppAuthService, PluginService, RuleService, SelectorService, MetaDataService的引用,用于读写数据库
    ......
 
    //实现DataChangedListener接口,此处仅截取了selector相关,实际还有onAppAuthChanged、onPluginChanged等实现。实现思路跟下面selector这个完全一致,都是在执行完刷新对应缓存后、调用对应的afterXxxChanged方法。
    @Override
    public void onSelectorChanged(final List<SelectorData> changed, final DataEventTypeEnum eventType) {
   
        if (CollectionUtils.isEmpty(changed)) {
   
            return;
        }
        this.updateSelectorCache();
        this.afterSelectorChanged(changed, eventType);
    }
	//更新selector缓存后,调用该方法。
    protected void afterSelectorChanged(final List<SelectorData> changed, final DataEventTypeEnum eventType) {
   
    }

    //InitializingBean接口,属性赋值后、初始化之前执行
    @Override
    public final void afterPropertiesSet() {
   
        updateAppAuthCache();
        updatePluginCache();
        updateRuleCache();
        updateSelectorCache();
        updateMetaDataCache();
        afterInitialize();
    }
	//模板方法
    protected abstract void afterInitialize();
	//更新缓存
    protected <T> void updateCache(final ConfigGroupEnum group, final List<T> data) {
   
        String json = GsonUtils.getInstance().toJson(data);
        ConfigDataCache newVal = new ConfigDataCache(group.name(), json, Md5Utils.md5(json), System.currentTimeMillis());
        ConfigDataCache oldVal = CACHE.put(newVal.getGroup(), newVal);
        log.info("update config cache[{}], old: {}, updated: {}", group, oldVal, newVal);
    }
	//更新selector、rule、plugin、appAuth、metadata缓存的工具方法
  	.......
}

可以看到AbstractDataChangedListener主要是实现DataChangedListener接口,同时利用模板方法设计模式,提供了扩展的余地,在数据变化时刷新缓存、调用对应的模板方法。

之前也分析过,在soul-admin中利用Spring事件监听机制,收到DataChangedEvent事件后会将其发给对应的listener,由listener进一步处理:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值