Soul-源码阅读19-Http长轮询总结3

Soul-源码阅读19-Http长轮询3

继上一节ConfigController# fetchConfigs 从admin 获取响应数据后,bootstrap 更新本地缓存。

boostrap刷新数据

  • HttpSyncDataService# doFetchGroupConfig

    private void doFetchGroupConfig(final String server, final ConfigGroupEnum... groups) {
        // ......
        String  json = this.httpClient.getForObject(url, String.class);
        // update local cache
        boolean updated = this.updateCacheWithJson(json);
        // ......
    }
    
  • DataRefreshFactory # executor 刷新数据缓存:dataRefresh.refresh

    public boolean executor(final JsonObject data) {
        final boolean[] success = {false};
        ENUM_MAP.values().parallelStream().forEach(dataRefresh -> success[0] = dataRefresh.refresh(data));
        return success[0];
    }
    
  • 刷新数据缓存之前,再比对MD5值和 最后一次更新缓存的时间判断是否需要更新。

    protected boolean updateCacheIfNeed(final ConfigData<T> newVal, final ConfigGroupEnum groupEnum) {
        // first init cache
        if (GROUP_CACHE.putIfAbsent(groupEnum, newVal) == null) {
            return true;
        }
        ResultHolder holder = new ResultHolder(false);
        GROUP_CACHE.merge(groupEnum, newVal, (oldVal, value) -> {
            // MD5值不相等 且 旧数据的修改时间小于新数据的修改时间
            if (!StringUtils.equals(oldVal.getMd5(), newVal.getMd5()) && oldVal.getLastModifyTime() < newVal.getLastModifyTime()) {
                log.info("update {} config: {}", groupEnum, newVal);
                holder.result = true;
                return newVal;
            }
            log.info("Get the same config, the [{}] config cache will not be updated, md5:{}", groupEnum, oldVal.getMd5());
            return oldVal;
        });
        return holder.result;
    }
    

最近几节总结

  • http长轮询60秒的秘密:bootstrap调用admin的“/configs/listener” 接口,有数据更新的时候会马上返回,bootstrap 就再调用 fetch 接口获取最新数据,没有数据更新的时候会60s再返回数据HttpLongPollingDataChangedListener# doLongPolling

    public void doLongPolling(final HttpServletRequest request, final HttpServletResponse response) {
    
        // compare group md5
        List<ConfigGroupEnum> changedGroup = compareChangedGroup(request);
        String clientIp = getRemoteIp(request);
    
        // response immediately.
        if (CollectionUtils.isNotEmpty(changedGroup)) {
            this.generateResponse(response, changedGroup);
            log.info("send response with the changed group, ip={}, group={}", clientIp, changedGroup);
            return;
        }
    
        // listen for configuration changed.
        final AsyncContext asyncContext = request.startAsync();
    
        // AsyncContext.settimeout() does not timeout properly, so you have to control it yourself
        asyncContext.setTimeout(0L);
    
        // block client's thread.
        scheduler.execute(new LongPollingClient(asyncContext, clientIp, HttpConstants.SERVER_MAX_HOLD_TIMEOUT));
    }
    
    public void run() {
        this.asyncTimeoutFuture = scheduler.schedule(() -> {
            clients.remove(LongPollingClient.this);
            List<ConfigGroupEnum> changedGroups = compareChangedGroup((HttpServletRequest) asyncContext.getRequest());
            sendResponse(changedGroups);
        }, timeoutTime, TimeUnit.MILLISECONDS);
        clients.add(this);
    }
    
  • admin 启动后每隔300s 从数据库同步一次数据到本地缓存。

  • 在 admin 管理后台修改数据,会马上返回响应给 bootstrap。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值