点击下方“JavaEdge”,选择“设为星标”

第一时间关注技术干货!

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

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

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

1 获取头信息和延迟时间
打开网易新闻 查看精彩图片
1 获取头信息和延迟时间

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

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)。

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

long timeout = -1L;
if (isFixedPolling()) {
    timeout = Math.max(10000, getFixedPollingInterval());
} else {
    timeout = Math.max(10000, Long.parseLong(str) - delayTime);
}
3 检测配置变更

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

long start = System.currentTimeMillis();
List
        
  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响应:

String ip = RequestUtil.getRemoteIp(req);
ConnectionCheckResponse connectionCheckResponse = checkLimit(req);
if (!connectionCheckResponse.isSuccess()) {
    generate503Response(req, rsp, connectionCheckResponse.getMessage());
    return;
}
5 启动异步上下文

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

final AsyncContext asyncContext = req.startAsync();
asyncContext.setTimeout(0L);
6 创建和提交长轮询任务

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

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 可以有效地处理大量的长轮询请求而不阻塞服务器线程,提高系统的可扩展性和响应效率。

编程严选网:http://www.javaedge.cn/ 专注分享软件开发全生态相关技术文章、视频教程资源、热点资讯等,全站资源免费学习,快来看看吧~

欢迎长按图片加好友,我会第一时间和你分享软件行业趋势面试资源学习方法等等。

添加好友备注【技术群交流】拉你进技术交流群

关注公众号后,在后台私信:

  • 更多教程资源应有尽有,欢迎关注并加技术交流群,慢慢获取