【Spring Cloud Alibaba系列】深入Nacos 服务端长轮询处理核心代码

602 阅读1分钟

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

ClientLongPolling

ClientLongPolling是一个线程,其run方法的代码如下:

  • 通过scheduler.schedule启动一个定时任务,并且延时时间为29.5s
  • 将ClientLongPolling实例添加allSubs队列中,它主要维护一个长轮询的订阅关系
  • 定时任务执行后,先把ClientLongPolling实例从allSubs队列中移除
  • 通过MD5比较客户端请求的groupKeys是否发生了变更,并将变更的结果通过response返回给客户端
class ClientLngPolling implements Runnable{
    @Override
    public void run(){
        //启动定时任务
        scheduler.schedule(new Runnable(){
            @Override
            public void run(){
                try{
                    asyncTimeoutFuture=getRetainIps().put(ClientLongPolling.this.ip,System.currentTimeMillis());
                    allSubs.remove(ClientLongPolling.this);
                    if(isFixedPolling(){
                        //比较数据的md5值判断是否发生了修改
                        List<String> changedGroups = MD5Util.compareMd5((HttpServletRequest)asyncCOntext.getRequest(),(HttpServletResponse)asyncContext.getResponse,clientMd5Map);
                        if(changedGroups.size()>0){
                            sendResponse(changedGroups);
                        }else{
                            sendResponse(null);
                        }
                    }else{
                        sendResponse(null);
                    }
                }catch(Throwable t){
                    LogUtil.defaultLog.error("long polling error:"+t.getMessage(),t.getCause());
                }
            }
        },timeoutTime,TimeUnit.MILLSECONDS);
    	allSubs.add(this);
                }
}

从以上代码分析,长轮询就是服务端收到请求后,不立即返回,而是在延时后29.5s才把请求结果返回给客户端,客户端和服务端之间在30s之内数据没有修改下一直处于连接状态。 当通过控制台或OpenAPI的方式修改配置后,如何实时通知呢?定时任务是延迟29.5s执行,没有达到以上的实时通知的结果。通过类图发现,LongPollingService继承了AbstractEventListener

AbstractEventListener是一个事件抽象类,它有一个onEvent抽象方法,而LongPollingService实现了以下方法:

@Override
public void onEvent(Event event){
    if(isFixedPolling()){
        
    }else{
        if(event instanceof LocalDataChangeEvent){
            LocalDataChangeEvent localDataChangeEvent=(LocalDataChangeEvent)event;
            scheduler.execute(new DataChangeTask(localDataChangeEvent.groupKey,localDataChangeEvent.isBeta,localDataChangeEvent.betaIps));
        }
    }
}

涉及到事件处理机制,LongPollingService的onEvent方法看到一个LocalDataChangeEvent事件,这事件是在服务端的配置数据修改时发布一个事件,接着关注收到事件后处理行为。