Soul 网关源码分析(八)使用http长轮询 同步数据到网关

10 篇文章 0 订阅

今天我们使用 http长轮询来同步数据到soul-bootstrap,相比websocket方式更为轻量,但同时时效性会略为降低。首先我们来看看什么是http长轮询。

短连接:client每向server发起一次http请求,就建立一个tpc连接,任务结束则中断。

在http长轮询机制中,client一样向server请求数据。然而,如果server没有可以立即返回给client的数据,则不会立刻返回一个空结果,而是保持这个请求等待数据到来(或者恰当的超时:小于ajax的超时时间),此时client进入之pending状态,server将数据准备好或超时后返回给client。

整个流程如图所示:
在这里插入图片描述
网关配置(记得重启)

首先在 pom.xml 文件中 引入以下依赖:

   <!--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>

在 springboot的 yml 文件中进行如下配置:

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

深入源码

/**
 * 根据配置项加载HttpLongPollingDataChangedListener这个bean
 */
@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);
    }

}
/**
  * 使用 ArrayBlockingQueue 存放客户端,并创建一个单线程的 ScheduledThreadPoolExecutor 来实现周期性任务的调度
  * @param httpSyncProperties the HttpSyncProperties
  */
 public HttpLongPollingDataChangedListener(final HttpSyncProperties httpSyncProperties) {
     this.clients = new ArrayBlockingQueue<>(1024);
     this.scheduler = new ScheduledThreadPoolExecutor(1,
             SoulThreadFactory.create("long-polling", true));
     this.httpSyncProperties = httpSyncProperties;
 }

HttpLongPollingDataChangedListener 中比较精髓的函数是 checkCacheDelayAndUpdate:

	/**
     * 检查客户端是否需要更新缓存
     * @param serverCache the admin local cache
     * @param clientMd5 the client md5 value
     * @param clientModifyTime the client last modify time
     * @return true: the client needs to be updated, false: not need.
     */
    private boolean checkCacheDelayAndUpdate(final ConfigDataCache serverCache, final String clientMd5, final long clientModifyTime) {

        // 如果MD5 值相等,则不用更新
        if (StringUtils.equals(clientMd5, serverCache.getMd5())) {
            return false;
        }

        // 如果MD5 值不相等,则比较 lastModifyTime
        long lastModifyTime = serverCache.getLastModifyTime();
        if (lastModifyTime >= clientModifyTime) {
            // the client's config is out of date.
            return true;
        }

        // the lastModifyTime before client, then the local cache needs to be updated.
        // Considering the concurrency problem, admin must lock,
        // otherwise it may cause the request from soul-web to update the cache concurrently, causing excessive db pressure
        boolean locked = false;
        try {
        	//尝试去获取锁, 超过5秒后放弃
            locked = LOCK.tryLock(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return true;
        }
        if (locked) {
            try {
                ConfigDataCache latest = CACHE.get(serverCache.getGroup());
                if (latest != serverCache) {
                    // the cache of admin was updated. if the md5 value is the same, there's no need to update.
                    // 如果 admin 的缓存更新了 但 MD5 相等, 则不需要更新
                    return !StringUtils.equals(clientMd5, latest.getMd5());
                }

                // 从数据库中读取数据并加入缓存
                this.refreshLocalCache();
                latest = CACHE.get(serverCache.getGroup());
                return !StringUtils.equals(clientMd5, latest.getMd5());
            } finally {
                LOCK.unlock();
            }
        }

        // not locked, the client need to be updated.
        return true;

    }

总结

其实 checkCacheDelayAndUpdate 跟最近做的 安卓更新检测接口很像, 巧妙地通过 时间 和 数据MD5 这两个因子对缓存做比较, 同时考虑到了并发场景, 添加了一个锁保证更新的原子性.

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值