config 客户端

ClientWorker#ClientWorker 

构造方法中启动定时任务

ClientWorker.LongPollingRunnable

长轮询的任务,在 run 方法的结尾,重新把任务加入到线程池

ClientWorker#checkUpdateDataIds

客户端把所监听配置的元数据信息(namespace, group, dataId, md5)上报给 server

config server 处理请求

ConfigController#listener
LongPollingService#addLongPollingClient

server 比较客户端传过来的 md5 值,如果有变化,马上返回已变化配置的元数据,否则延迟返回。server 使用了 servlet 3.0 的异步机制,用 ScheduledExecutorService 线程池来返回延时响应,

final AsyncContext asyncContext = req.startAsync();
asyncContext.setTimeout(0L);
scheduler.execute(new ClientLongPolling(asyncContext, clientMd5Map, ip, probeRequestSize, timeout, appName, tag));

使用 ClientLongPolling 封装了 AsyncContext,timeout 参数,通过 AsyncContext 可以获取 request 和 response,
在 ClientLongPolling 的 run 方法中,用 ScheduledExecutorService 执行定时任务。所有客户端的 ClientLongPolling 放在 allSubs 中,是一个 ConcurrentLinkedQueue。

// com.alibaba.nacos.config.server.service.LongPollingService.ClientLongPolling
public void run() {
asyncTimeoutFuture = scheduler.schedule(new Runnable() {
@Override
public void run() {
try {
getRetainIps().put(ClientLongPolling.this.ip, System.currentTimeMillis());
/**
* 删除订阅关系
*/
allSubs.remove(ClientLongPolling.this); if (isFixedPolling()) {
LogUtil.clientLog.info("{}|{}|{}|{}|{}|{}",
(System.currentTimeMillis() - createTime),
"fix", RequestUtil.getRemoteIp((HttpServletRequest)asyncContext.getRequest()),
"polling",
clientMd5Map.size(), probeRequestSize);
List<String> changedGroups = MD5Util.compareMd5(
(HttpServletRequest)asyncContext.getRequest(),
(HttpServletResponse)asyncContext.getResponse(), clientMd5Map);
if (changedGroups.size() > 0) {
sendResponse(changedGroups);
} else {
sendResponse(null);
}
} else {
LogUtil.clientLog.info("{}|{}|{}|{}|{}|{}",
(System.currentTimeMillis() - createTime),
"timeout", RequestUtil.getRemoteIp((HttpServletRequest)asyncContext.getRequest()),
"polling",
clientMd5Map.size(), probeRequestSize);
sendResponse(null);
}
} catch (Throwable t) {
LogUtil.defaultLog.error("long polling error:" + t.getMessage(), t.getCause());
} } }, timeoutTime, TimeUnit.MILLISECONDS); allSubs.add(this);
}

如果在定时任务执行时,监听的配置文件依然没有变化,server 则返回空文本给 client;

如果发生了配置变更,会由 DataChangeTask 发送变化的配置 id 给客户端,同时取消定时任务。

// com.alibaba.nacos.config.server.service.LongPollingService.DataChangeTask#run
public void run() {
try {
ConfigService.getContentBetaMd5(groupKey);
for (Iterator<ClientLongPolling> iter = allSubs.iterator(); iter.hasNext(); ) {
ClientLongPolling clientSub = iter.next();
if (clientSub.clientMd5Map.containsKey(groupKey)) {
// 如果beta发布且不在beta列表直接跳过
if (isBeta && !betaIps.contains(clientSub.ip)) {
continue;
} // 如果tag发布且不在tag列表直接跳过
if (StringUtils.isNotBlank(tag) && !tag.equals(clientSub.tag)) {
continue;
} getRetainIps().put(clientSub.ip, System.currentTimeMillis());
iter.remove(); // 删除订阅关系
LogUtil.clientLog.info("{}|{}|{}|{}|{}|{}|{}",
(System.currentTimeMillis() - changeTime),
"in-advance",
RequestUtil.getRemoteIp((HttpServletRequest)clientSub.asyncContext.getRequest()),
"polling",
clientSub.clientMd5Map.size(), clientSub.probeRequestSize, groupKey);
clientSub.sendResponse(Arrays.asList(groupKey));
}
}
} catch (Throwable t) {
LogUtil.defaultLog.error("data change error:" + t.getMessage(), t.getCause());
}
}

客户端获得变化的配置元数据后,重新拉取新的配置。

config 客户端有有 2 种缓存文件,failover 和 snapshot,从代码看,server 不可用时,一般使用 snapshot

servlet 异步处理:
https://www.cnblogs.com/davenkin/p/async-servlet.html

final AsyncContext asyncContext = req.startAsync();
asyncContext 可以获取 request 和 response,
asyncContext.complete();

nacos 使用 servlet 异步处理客户端配置长轮询的更多相关文章

  1. 三周,用长轮询实现Chat并迁移到Azure测试

    公司的OA从零开始进行开发,继简单的单点登陆.角色与权限.消息中间件之后,轮到在线即时通信的模块需要我独立去完成.这三周除了逛网店见爱*看动漫接兼职,基本上都花在这上面了.简单地说就是用MVC4基于长 ...

  2. 长轮询实现Chat并迁移到Azure测试

    长轮询实现Chat并迁移到Azure测试 公司的OA从零开始进行开发,继简单的单点登陆.角色与权限.消息中间件之后,轮到在线即时通信的模块需要我独立去完成.这三周除了逛网店见爱*看动漫接兼职,基本上都 ...

  3. 基于HTTP的长轮询简单实现

    Web客户端与服务器之间基于Ajax(http)的常用通信方式,分为短连接与长轮询. 短连接:客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接. 在长轮询机制中,客户端像传统轮 ...

  4. 实现Comet(服务器推送)的两种方式:长轮询和http流

    Comet 是一种高级的Ajax技术,实现了服务器向页面实时推送数据的技术,应用场景有体育比赛比分和股票报价等. 实现Comet有两种方式:长轮询与http流 长轮询是短轮询的翻版,短轮询的方式是:页 ...

  5. Apollo 3 定时/长轮询拉取配置的设计

    前言 如上图所示,Apollo portal 更新配置后,进行轮询的客户端获取更新通知,然后再调用接口获取最新配置.不仅仅只有轮询,还有定时更新(默认 5 分钟一次).目的就是让客户端能够稳定的获取到 ...

  6. 网页实时聊天之js和jQuery实现ajax长轮询

    众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系.所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的长时间联系,从而源源不段地获取信息. 一直以来的方式 ...

  7. Web 通信 之 长连接、长轮询(转)

    Web 通信 之 长连接.长轮询(long polling) 基于HTTP的长连接,是一种通过长轮询方式实现"服务器推"的技术,它弥补了HTTP简单的请求应答模式的不足,极大地增强 ...

  8. Web 通信 之 长连接、长轮询(long polling)

    基于HTTP的长连接,是一种通过长轮询方式实现"服务器推"的技术,它弥补了HTTP简单的请求应答模式的不足,极大地增强了程序的实时性和交互性. 一.什么是长连接.长轮询? 用通俗易 ...

  9. Web 通信 之 长连接、长轮询(long polling)(转)

    基于HTTP的长连接,是一种通过长轮询方式实现"服务器推"的技术,它弥补了HTTP简单的请求应答模式的不足,极大地增强了程序的实时性和交互性. 一.什么是长连接.长轮询? 用通俗易 ...

随机推荐

  1. 一条简单的 SQL 查询语句到底经历了什么?

    一.MySQL 基础架构   整体来说 MySQL 主要分为两个部分,一个部分是:Server 层,另一部分是:存储引擎层. 其中 Server 层包括有连接器.查询缓存.分析器.优化器.执行器等,存 ...

  2. Resharper 2019.1.1 破解

    本文链接:https://blog.csdn.net/qq_21361809/article/details/92423949                           Resharper ...

  3. Redis数据类型及基本命令

    一.基础命令 提示:Redis不区分命令大小写 1.获得符合规则的键名列表 keys pattern    //pattern支持glob风格通配符格式 2.判断一个键是否存在 exists key  ...

  4. ntsysv - 用于配置运行级别的简单接口

    总览 SYNOPSIS ntsysv [--back] [--level <levels>] 描述 DESCRIPTION ntsysv 是个用于配置运行级别服务(也可通过 chkconf ...

  5. FPGA 物理时序不合理的体现(体现方式:数字钟的行扫描和列扫描)

    本人在这只讨论建模好的模块来比较解释现象,如有不周到请大家指正. 软件功能仿真和在硬件上的区别:可以从这个数码管的行扫描和列扫描实例来体会一下,物理时序的影响和改进方法. 数码管的行扫描.列扫描要求同 ...

  6. Vue中的组件及缓存 keep-alive

    <script> import { mapState } from "vuex"; export default { data() {      return {    ...

  7. Python---进阶---多线程---threading

    一. 使用多线程去播放两个播放列表,一个是movie,一个是music _thread threading ------------------------------------------ imp ...

  8. 多模字符串匹配算法-Aho–Corasick

    背景 在做实际工作中,最简单也最常用的一种自然语言处理方法就是关键词匹配,例如我们要对n条文本进行过滤,那本身是一个过滤词表的,通常进行过滤的代码如下 for (String document : d ...

  9. jq元素左边距

    获取页面某一元素的绝对X,Y坐标,可以用offset():var X = $(‘#DivID’).offset().top;var Y = $(‘#DivID’).offset().left; 获取相 ...

  10. HDU 4758 Walk Through Squares ( Trie图 && 状压DP && 数量限制类型 )

    题意 : 给出一个 n 行.m 列的方格图,现从图左上角(0, 0) 到右下角的 (n, m)走出一个字符串(规定只能往下或者往右走),向右走代表' R ' 向下走则是代表 ' D ' 最后从左上角到 ...