首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Nacos长轮询底层是怎么实现的?

Nacos长轮询底层是怎么实现的?

作者头像
JavaEdge
发布2025-05-31 14:42:07
发布2025-05-31 14:42:07
20800
代码可运行
举报
文章被收录于专栏:JavaEdgeJavaEdge
运行总次数:0
代码可运行

免责声明~ 任何文章不要过度深思! 万事万物都经不起审视,因为世上没有同样的成长环境,也没有同样的认知水平,更「没有适用于所有人的解决方案」; 不要急着评判文章列出的观点,只需代入其中,适度审视一番自己即可,能「跳脱出来从外人的角度看看现在的自己处在什么样的阶段」才不为俗人。 怎么想、怎么做,全在乎自己「不断实践中寻找适合自己的大道」

Nacos 也是通过 AsyncContext 实现长轮询机制来管理配置更新。

来观察下 Nacos#LongPollingService的源码实现,从中抄到并学习如何利用好长轮询机制。

341ec343b1b16b878c2a1e29d2b7a589.png
341ec343b1b16b878c2a1e29d2b7a589.png

1 获取头信息和延迟时间

从请求头中获取长轮询相关的标识符和延迟时间信息:

代码语言:javascript
代码运行次数:0
运行
复制
public static final String LONG_POLLING_HEADER = "Long-Pulling-Timeout";
    public static final String LONG_POLLING_NO_HANG_UP_HEADER = "Long-Pulling-Timeout-No-Hangup";

String str = req.getHeader(LongPollingService.LONG_POLLING_HEADER);
String noHangUpFlag = req.getHeader(LongPollingService.LONG_POLLING_NO_HANG_UP_HEADER);
int delayTime = SwitchService.getSwitchInteger(SwitchService.FIXED_DELAY_TIME, 500);

2 计算超时时间

如用固定轮询间隔,则设置一个固定超时时间(最小10s)。

否则,计算一个基于请求头中提供的超时时间减去延迟时间的超时值:

代码语言:javascript
代码运行次数:0
运行
复制
long timeout = -1L;
if (isFixedPolling()) {
    timeout = Math.max(10000, getFixedPollingInterval());
} else {
    timeout = Math.max(10000, Long.parseLong(str) - delayTime);
}

3 检测配置变更

通过 MD5Util.compareMd5 比较客户端的MD5和服务器的MD5,判断配置是否变化:

代码语言:javascript
代码运行次数:0
运行
复制
long start = System.currentTimeMillis();
List<String> changedGroups = MD5Util.compareMd5(req, rsp, clientMd5Map);
if (changedGroups.size() > 0) {
    generateResponse(req, rsp, changedGroups);
    LogUtil.CLIENT_LOG.info("{}|{}|{}|{}|{}|{}|{}", System.currentTimeMillis() - start, "instant",
            RequestUtil.getRemoteIp(req), "polling", clientMd5Map.size(), probeRequestSize,
            changedGroups.size());
    return;
} else if (noHangUpFlag != null && noHangUpFlag.equalsIgnoreCase(TRUE_STR)) {
    LogUtil.CLIENT_LOG.info("{}|{}|{}|{}|{}|{}|{}", System.currentTimeMillis() - start, "nohangup",
            RequestUtil.getRemoteIp(req), "polling", clientMd5Map.size(), probeRequestSize,
            changedGroups.size());
    return;
}

4 连接限制检查

检查当前请求是否超过限制,是,则返回503响应:

代码语言:javascript
代码运行次数:0
运行
复制
String ip = RequestUtil.getRemoteIp(req);
ConnectionCheckResponse connectionCheckResponse = checkLimit(req);
if (!connectionCheckResponse.isSuccess()) {
    generate503Response(req, rsp, connectionCheckResponse.getMessage());
    return;
}

5 启动异步上下文

使用 AsyncContext 启动异步处理,防止 HTTP 线程阻塞,并设置超时时间为0(不超时):

代码语言:javascript
代码运行次数:0
运行
复制
final AsyncContext asyncContext = req.startAsync();
asyncContext.setTimeout(0L);

6 创建和提交长轮询任务

创建 ClientLongPolling 实例,并将其提交到定时线程池中执行:

代码语言:javascript
代码运行次数:0
运行
复制
String appName = req.getHeader(RequestUtil.CLIENT_APPNAME_HEADER);
String tag = req.getHeader("Vipserver-Tag");
ConfigExecutor.executeLongPolling(
        new ClientLongPolling(asyncContext, clientMd5Map, ip, probeRequestSize, timeout, appName, tag));

7 结论

Nacos 也是通过Servlet3.0 新增的 AsyncContext 实现长轮询机制,来处理配置更新。

当客户端发起长轮询请求时,服务器会异步等待配置变更或超时,若:

  • 检测到配置变更,服务器立即响应客户端
  • 没有变更,服务器会在预定的超时时间内保持连接

实际的长轮询处理中,通过将请求处理从主线程分离出来,Nacos 可以有效地处理大量的长轮询请求而不阻塞服务器线程,提高系统的可扩展性和响应效率。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-05-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 获取头信息和延迟时间
  • 2 计算超时时间
  • 3 检测配置变更
  • 4 连接限制检查
  • 5 启动异步上下文
  • 6 创建和提交长轮询任务
  • 7 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档