Nacos配置中心是如何实现动态刷新原理

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

前言

关于配置中心,我们在分布式微服务的业务中可以对不同业务的配置,进行一个标准化、统一格式化、集中式的管理。当然我们用的比较多的就是Nacos、Apollo、Config。Apollo是相对比较重的配置中心,而Config配置中心需要新构建一个项目存放配置,也没有对应的可视化的配置页面。

这里着重介绍下Nacos的配置中心,也是我们在日常开发中使用起来相对方便、简洁的配置中心,通过Nacos的注册中心和配置中心,让我们很清楚的知道服务的实例状态和配置文件的配置情况。

当然我们也希望我们对服务的配置进行变更后,不用重新去启动我们的服务,达到热部署的效果,显然Nacos是支持的,让我们一起来探究下Nacos是如何实现热部署的。

Nacos热部署原理

首先让我们先去跟踪源码来看下,Nacos的热部署主要是基于什么机制。 通过去查找Nacos clinet的jar包看到,ClientWorker个类,然后看到这个构造方法初始化了executor和executorService通过线程池执行,通过定时任务提交。

1F2F9B3E-4166-4D69-8723-D25F69DAC087.png

executor定时任务里面通过提交checkConfigInfo方法,看这个方法首先对执行的任务进行分组,然后循环调用executorService定时任务,通过创建LongPollingRunnable对象去执行分组任务,对LongPollingRunnable这个类从字面意思上看是长轮训任务实现了Runnable,通过线程去执行。

D398DFAD-C797-4A6A-B648-C11F34083BFA.png

主要看LongPollingRunnable 的run方法里面做了什么。

class LongPollingRunnable implements Runnable {
    private int taskId;

    public LongPollingRunnable(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {

        List<CacheData> cacheDatas = new ArrayList<CacheData>();
        List<String> inInitializingCacheList = new ArrayList<String>();
        try {
            // check failover config 
              ....
            // check server config
              ...

}

复制代码

首先要从Nacos 服务端获取值变化了的DataID列表,通过请求/configs/listener接口来获取服务端更新的配置

E404A345-3F65-4C20-B603-65046A29A00D.png 这里是Nacos服务端接口请求地址

HttpResult result = agent.httpPost(Constants.CONFIG_CONTROLLER_PATH + "/listener", headers, params,
    agent.getEncode(), readTimeoutMs);

复制代码

这里会通过循环changedGroupKeys,将key、dataId、group通过getServerConfig方法获取配置中心真正改变的内容,加入cacheMap缓存

6494073B-C05E-4A34-8A57-62FA1BB45C1A.png

接下来这个循环就是通知CacheData监听器去刷新Nacos更改的配置,checkListenerMd5这个方法主要是通过监听器Listener里面创建线程池去执行Runnable里面的任务。

CC4B759E-15B4-4C47-A25E-570658145A92.png

这个receiveConfigInfo方法,通过追踪代码,可以看到有三个抽象Listener类实现的顶级接口是Listener。

E90E8CFA-7676-4DBD-A991-F7A3D8385BD5.png

1CA49C92-E35F-41D8-A4B6-A015B8A6D7CF.png

再找到innerReceive方法,最终是通过NacosContextRefresher类的registerNacosListener方法来去实现innerReceive这个抽象方法,链表的方式来记录Nacos更新的配置。

F51B86C6-E719-4F00-A4A7-0F6631DBE29C.png

这里面还有applicationContext.publishEvent,Spring 通过事件的方式刷新容器的。但是这里有个问题,Spring又是怎么在不重启的情况下,获取Nacos服务端动态变更的配置信息呢?这里又涉及到Spring和Nacos的一个交互。

42371BFC-DA1F-4EAC-B7A4-E315166A929C.png

通过看Nacos—config的源码发现了,NacosConfigManager这个类,Spring容器在第一次启动的时候会通过加载Nacos的jar包,通过NacosConfigManager把Nacos的组件加载到容器里,包括创建定时任务。 随后在通过长轮询的方式去服务端请求,看是否有配置进行更更新。

259E2E70-9848-430D-B9BD-57A70EDBDBB0.png

总结

Nacos实现配置的动态刷新,主要是靠客户端的长轮询去请求服务端获取更新的配置,在通过Spring的ApplicationContext.publishEvent() 发布事件的方式去刷新容器。

其实主要是靠Nacos—config包下的NacosContextRefresher、NacosConfigManager这两个核心。

NacosContextRefresher主要是做桥梁的作用,通过ApplicationContext获取上下文信息,通过ApplicationListener来通知事件的发布更新Spring容器。

NacosConfigManager作为配置的启动,创建长轮询的定时任务,定时执行任务获取更新的配置。

猜你喜欢

转载自juejin.im/post/7129708687954247688