为了账号安全,请及时绑定邮箱和手机立即绑定

nacos入门系列之配置中心后续

之前比较概览的介绍了nacos配置中心的使用:https://www.imooc.com/article/306481
这一次针对配置中心监听配置变更进行进一步的学习。

nacos如何实现配置更新

1-首先我们需要了解,nacos分为客户端和服务端。我们使用客户端的代码依赖来进行
发布配置和监听配置的更新。而配置信息会保存到nacos的服务端。
2-使用客户端的代码去监听配置的变更
configService.addListener(dataId, group, new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }
            @Override
            public void receiveConfigInfo(String configInfo) {
                System.out.println("receiveConfigInfo:"+configInfo);
            }
        });

3-NacosConfigService会进行初始化,并且每隔10ms去定期校验配置,方法为
checkConfigInfo()
checkConfigInfo方法中会对所有配置进行分批,默认每3000个配置属于同一批次,
并且一个批次的配置拥有相同的taskId。然后将每个批次交由另一个线程池去进行检
查。
executorService.execute(new LongPollingRunnable(i));

4-每个LongPollingRunnable任务中会对相同taskId的一批次配置进行检查。

5-在nacos中通过CacheData来表示一个配置信息。上面所说的taskId是属于
CacheData中的一个属性。CacheDat还包含具体的配置内容,md5值等信息。并且通过
dataId, group可以获取到对应的CacheData。

6-每个CacheData都维护了一个listeners集合
CopyOnWriteArrayList<ManagerListenerWrap> listeners;
并且提供了add和remove方法:
当使用客户端代码进行监听配置的时候,会进行addListener,
cache.addListener(listener);
listeners.addIfAbsent(wrap);
会将其添加到当前CacheData的listeners集合中。
当配置信息发生变更,则会调用safeNotifyListener方法去回调客户端添加的
listener的方法:listener.receiveConfigInfo(contentTmp);让客户端获取到最
新的配置。

7-LongPollingRunnable中的run方法中的checkUpdateDataIds方法会返回当前批次
发生变更的配置信息。
到这里,客户端需要通过http请求和服务端进行交互,获取变更的配置信息。

8-checkUpdateConfigStr方法向服务端发送http请求,设置了超时时间
 headers.add("Long-Pulling-Timeout");
 headers.add("" + timeout);//默认30s
HttpResult result = agent.httpPost(Constants.CONFIG_CONTROLLER_PATH + "/listener",
headers, params, agent.getEncode(), readTimeoutMs);


9-服务端通过ConfigController类(@PostMapping("/listener"))接口来处理客
户端的http请求。
这里触发了一个长轮询的方法
// do long-polling
inner.doPollingConfig(request, response, clientMd5Map, 
probeModify.length());

longPollingService.addLongPollingClient(request, response, 
clientMd5Map, probeRequestSize);

10-先来看看LongPollingService类,继承自AbstractEventListener,
在初始化的时候构造函数中会进行如下操作:
public AbstractEventListener() {
            /**
             * automatic register
             */
            EventDispatcher.addEventListener(this);
 }
也就是LongPollingService会将自己加入到EventDispatcher中的集合中,如下:
CopyOnWriteArrayList<AbstractEventListener> listeners;

11-LongPollingService会将http请求提交给线程池去处理,每个任务封装在
ClientLongPolling中。ClientLongPolling首先会去比较当前请求批次的配置
是否有变更,通过md5值比较:
List<String> changedGroups = MD5Util.compareMd5(  
(HttpServletRequest)asyncContext.getRequest(),      
(HttpServletResponse)asyncContext.getResponse(), clientMd5Map)
如果当前批次有变更的配置,则会返回当前的http请求。否则则会等待,直到超时(30s)

12-如果超时之前有配置发生了变更,会怎么办?
首先nacos服务端会收到客户端关于配置变更的请求,由CommunicationController
类的notifyConfigInfo接口去处理:
dumpService.dump(dataId, group, tenant, lastModifiedTs, handleIp, 
true);
dumpTaskMgr.addTask(groupKey,new DumpTask(groupKey, lastModified, 
handleIp, isBeta));
dumpTaskMgr 初始化的时候会启动一个线程去处理每个配置的DumpTask任务,并且
最终会调用
ConfigService的updateMd5(groupKey, md5, lastModifiedTs);      方法,
 //这里触发LocalDataChangeEvent事件,对长连接的请求做返回处理。及时通
 //知客户端,配置的变更
 if (cache.md5 == null || !cache.md5.equals(md5)) {
            cache.md5 = md5;
            cache.lastModifiedTs = lastModifiedTs;
  EventDispatcher.fireEvent(newLocalDataChangeEvent(groupKey))
        }
      
  这里触发了    EventDispatcher.fireEvent方法,会去遍历所有添加的listener
                      
   for (AbstractEventListener listener : getEntry(event.getClass()).listeners) {
            try {
                listener.onEvent(event);
            } catch (Exception e) {
                log.error(e.toString(), e);
            }
        }                            

最终会调用LongPollingService的onEvent方法,
 public void onEvent(Event event) {
        if (isFixedPolling()) {
            // ignore
        } else {
            if (event instanceof LocalDataChangeEvent) {

                LocalDataChangeEvent evt = (LocalDataChangeEvent)event;

                //  //groupKey: test+DEFAULT_GROUP
                scheduler.execute(new DataChangeTask(evt.groupKey, evt.isBeta, evt.betaIps));
            }
        }
    }

13-DataChangeTask任务会将变更的配置信息通过groupKey获取到其所属的
ClientLongPolling任务,并且进行http的返回:
 clientSub.sendResponse(Arrays.asList(groupKey));


14-最终http请的结果返回到客户端,LongPollingRunnable中,会进行
cacheData.checkListenerMd5();
调用CacheData的safeNotifyListener(dataId, group, content, type, 
md5, wrap);方法。将变更的配置返回给客户端。
最后的最后,LongPollingRunnable又将自己提交到线程池进行下次的执行:
executorService.execute(this);

总结

所有的内容都在上面了。
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
6396
获赞与收藏
157

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消