soul网关系列(九):soul-admin与网关数据同步之http长轮询-admin端

一、HTTP长轮询概述

在这里插入图片描述
http 长轮询机制如上所示,soul-web 网关请求 admin 的配置服务,读取超时时间为 90s,意味着网关层请求配置服务最多会等待 90s,这样便于 admin 配置服务及时响应变更数据,从而实现准实时推送。

二、soul-admin流程分析

  1. 根据官方文档,soul-admin的入口在ConfigController
//前提注入内容
@ConditionalOnBean(HttpLongPollingDataChangedListener.class)
@RestController
@RequestMapping("/configs")
@Slf4j
public class ConfigController {

    @Resource
    private HttpLongPollingDataChangedListener longPollingListener;

    /**
     * Fetch configs soul result.
     *
     * @param groupKeys the group keys
     * @return the soul result
     */
    @GetMapping("/fetch")
    public SoulAdminResult fetchConfigs(@NotNull final String[] groupKeys) {
        Map<String, ConfigData<?>> result = Maps.newHashMap();
        for (String groupKey : groupKeys) {
            ConfigData<?> data = longPollingListener.fetchConfig(ConfigGroupEnum.valueOf(groupKey));
            result.put(groupKey, data);
        }
        return SoulAdminResult.success(SoulResultMessage.SUCCESS, result);
    }

    /**
     * Listener.
     *
     * @param request  the request
     * @param response the response
     */
    @PostMapping(value = "/listener")
    public void listener(final HttpServletRequest request, final HttpServletResponse response) {
        longPollingListener.doLongPolling(request, response);
    }

}
  1. 前提需注入类HttpLongPollingDataChangedListener
    /**
     * Instantiates a new Http long polling data changed listener.
     * @param httpSyncProperties the HttpSyncProperties
     */
    public HttpLongPollingDataChangedListener(final HttpSyncProperties httpSyncProperties) {
    	// 初始化一个1024的BlockingQueue
        this.clients = new ArrayBlockingQueue<>(1024);
        // 启动一个定时长轮询用的守护线程
        this.scheduler = new ScheduledThreadPoolExecutor(1,
                SoulThreadFactory.create("long-polling", true));
        this.httpSyncProperties = httpSyncProperties;
    }
  1. 初始化之后全量同步一次
  2. 收到/configs/listener post请求
    这里是一个异步机制,提前会记录每个group的改动情况
    /**
     * 收到客户端请求,如果admin记录数据该group有变化,则会立即向该客户端发起更新数据
     * 否则,这个客户端的请求会等待,直到再有数据变化或者轮询时间到
     * Otherwise, the client's request thread is blocked until any data changes or the specified timeout is reached.
     */
    public void doLongPolling(final HttpServletRequest request, final HttpServletResponse response) {

        // 因为soul-web可能未收到某个配置变更的通知,因此MD5值可能不一致,则立即响应
        List<ConfigGroupEnum> changedGroup = compareChangedGroup(request);
        String clientIp = getRemoteIp(request);
        if (CollectionUtils.isNotEmpty(changedGroup)) {
            this.generateResponse(response, changedGroup);
            log.info("send response with the changed group, ip={}, group={}", clientIp, changedGroup);
            return;
        }

        // Servlet3.0异步响应http请求
        final AsyncContext asyncContext = request.startAsync();
        asyncContext.setTimeout(0L);
        // SERVER_MAX_HOLD_TIMEOUT = 60000ms
        scheduler.execute(new LongPollingClient(asyncContext, clientIp, HttpConstants.SERVER_MAX_HOLD_TIMEOUT));
    }
  1. LongPollingClient的run方法
        @Override
        public void run() {
            this.asyncTimeoutFuture = scheduler.schedule(() -> {
            	//加入定时任务,如果60s之内没有配置变更,则60s后执行,响应http请求
                clients.remove(LongPollingClient.this);
                List<ConfigGroupEnum> changedGroups = compareChangedGroup((HttpServletRequest) asyncContext.getRequest());
                // 发送变更,不管有没有变化
                sendResponse(changedGroups);
            }, timeoutTime, TimeUnit.MILLISECONDS);
            // 先扔进去,存起来
            clients.add(this);
        }
  1. 当收到任何变更通知的时候都会启动DataChangeTask
// soul-admin发生了配置变更,挨个将队列中的请求移除,并予以响应
class DataChangeTask implements Runnable {
    DataChangeTask(final ConfigGroupEnum groupKey) {
        this.groupKey = groupKey;
    }
    @Override
    public void run() {
        try {
            for (Iterator<LongPollingClient> iter = clients.iterator(); iter.hasNext(); ) {
                LongPollingClient client = iter.next();
                iter.remove();
                client.sendResponse(Collections.singletonList(groupKey));
            }
        } catch (Throwable e) {
            LOGGER.error("data change error.", e);
        }
    }
}

当 soul-web 网关层接收到 http 响应信息之后,拉取变更信息(如果有变更的话),然后再次请求 soul-admin 的配置服务,如此反复循环。
在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值