【Spring Cloud Alibaba系列】Nacos 服务端长轮询处理机制

1,174 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

深入/listener接口分析实现长轮询请求

@PostMapping("/listener")
public void listener(HttpSerlvetRequest request,HttpSerlvetRespnse response) throw SerlvetException,IOException{
    request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED",true);
    String probeModify=request.getParameter("Listening-Configs");
    if(StringUtils.isBlank(probeModify)){
        throw new IllegalArgmentException("invalid probeModify");
    }
    probeModify=URLDecoder.decode(probeModify,Constants.ENCODE);
    Map<String,String> clientMd5Map;
    try{
        
    }catch(Throwable e){
        throw new IllegalArgumentException("invalid probeModify");
        
    }
    inner.doPollingConfig(request,response,clientMd5Map,probeModify.length());
}

doPollingConfig方法是一个长轮询的处理接口,部分核心代码如下:

public String doPollingConfig(HttpServletRequest request,HttpServletResponse response,Map<String,String> clientMd5Map,int probeRequestSize) throws IOException{
    //长轮询开始
    if(LongPollingService.isSupportLongPolling(request)){
        longPollingService.addPollingClient(request,response,clientMd5Map,probeRequestSize);
        return HttpServletResponse.SC_OK+“”;
    }
    //短轮询逻辑
    List<String> changedGroups=Md5Util.compareMd5(request,response,clientMd5Map);
   //短轮询结果
    
    String oldResult = Md5Util.compareMd5OldResult(changedGroups);
    String newResult=Md5Util.compareMd5ResultString(changedGroups);
}

先判断请求是否长轮询,如果是,则调用addLongPollingClient。

  • 获取客户端请求的超时时间,减去500ms后赋值给timeout
  • 判断isFixedPolling,如果为true,定时任务将会在30s后开始执行,否则,在29.5s后开始执行
  • 和服务端的数据进行Md5对比,如果发生修改则直接返回。
  • scheduler.execute执行ClientLongPolling线程
public void addLongPollingClient(HttpServletRequest request,HttpServletResponse response,Map<String,String> clientMd5Map,int probeRequestSize){
    //获取客户端设置的请求超时时间
    String str=request.getHeader(LongPollingService.LONG_POLLING_HEADER);
    String noHangUpFlag=request.getHeader(LongPollingService.LONG_POLLING_NO_HANG_UP_HEADER);
	String appName = request.getHeader(RequestUtil.CLIENT_APPNAME_HEADER);
    String tag=request.getHeader("Vipserver-Tag");
    int delayTime=SwitchService.getSwitchInteger(SwitchService.FIXED_DELAY_TIME,500);
    //提前500ms返回响应,避免客户端超时
    long timeout = Math.max(10000,Long.parseLong(str)-delayTime);
    if(isFixedPolling()){
        timeout = Math.max(10000,getFixedPollingInterval());
    }else{
        long start=Sysetm.currentTimeMills();
        List<String> changeGroups=MD5Util.compareMd5(request,response,clientMd5Map);
    	if(changeGroups.size()>0){
            generateResponse(request,response,changedGroups);
            return;
        }else if(noHangUpFlag != null && noHangUpFlag.equalsIgnore(TRUE_STR)){
            return;
        }
    }
    String IP=RequestUtil.getRemoteIp(request);
    //由HTTP线程调用,否则离开后容器会马上发送响应
    final AsyncContext asyncContext=request.startAsync();
    //AsyncContext.setTimeOut()超时时间不准,由自己控制
    asyncContext.setTimeOut(0L);
    
    scheduler.excute(
    new ClientLongPolling(asyncContext,clientMd5Map,ip,probeRequestSize,timeout,appName,tag));
}

从addLongPollingClient方法得出,它的作用是把客户端的长轮询请求封装成ClientPolling交给scheduler执行。