携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
前言
关于配置中心,我们在分布式微服务的业务中可以对不同业务的配置,进行一个标准化、统一格式化、集中式的管理。当然我们用的比较多的就是Nacos、Apollo、Config。Apollo是相对比较重的配置中心,而Config配置中心需要新构建一个项目存放配置,也没有对应的可视化的配置页面。
这里着重介绍下Nacos的配置中心,也是我们在日常开发中使用起来相对方便、简洁的配置中心,通过Nacos的注册中心和配置中心,让我们很清楚的知道服务的实例状态和配置文件的配置情况。
当然我们也希望我们对服务的配置进行变更后,不用重新去启动我们的服务,达到热部署的效果,显然Nacos是支持的,让我们一起来探究下Nacos是如何实现热部署的。
Nacos热部署原理
首先让我们先去跟踪源码来看下,Nacos的热部署主要是基于什么机制。 通过去查找Nacos clinet的jar包看到,ClientWorker个类,然后看到这个构造方法初始化了executor和executorService通过线程池执行,通过定时任务提交。
executor定时任务里面通过提交checkConfigInfo方法,看这个方法首先对执行的任务进行分组,然后循环调用executorService定时任务,通过创建LongPollingRunnable对象去执行分组任务,对LongPollingRunnable这个类从字面意思上看是长轮训任务实现了Runnable,通过线程去执行。
主要看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接口来获取服务端更新的配置
这里是Nacos服务端接口请求地址
HttpResult result = agent.httpPost(Constants.CONFIG_CONTROLLER_PATH + "/listener", headers, params,
agent.getEncode(), readTimeoutMs);
复制代码
这里会通过循环changedGroupKeys,将key、dataId、group通过getServerConfig方法获取配置中心真正改变的内容,加入cacheMap缓存
接下来这个循环就是通知CacheData监听器去刷新Nacos更改的配置,checkListenerMd5这个方法主要是通过监听器Listener里面创建线程池去执行Runnable里面的任务。
这个receiveConfigInfo方法,通过追踪代码,可以看到有三个抽象Listener类实现的顶级接口是Listener。
再找到innerReceive方法,最终是通过NacosContextRefresher类的registerNacosListener方法来去实现innerReceive这个抽象方法,链表的方式来记录Nacos更新的配置。
这里面还有applicationContext.publishEvent,Spring 通过事件的方式刷新容器的。但是这里有个问题,Spring又是怎么在不重启的情况下,获取Nacos服务端动态变更的配置信息呢?这里又涉及到Spring和Nacos的一个交互。
通过看Nacos—config的源码发现了,NacosConfigManager这个类,Spring容器在第一次启动的时候会通过加载Nacos的jar包,通过NacosConfigManager把Nacos的组件加载到容器里,包括创建定时任务。 随后在通过长轮询的方式去服务端请求,看是否有配置进行更更新。
总结
Nacos实现配置的动态刷新,主要是靠客户端的长轮询去请求服务端获取更新的配置,在通过Spring的ApplicationContext.publishEvent() 发布事件的方式去刷新容器。
其实主要是靠Nacos—config包下的NacosContextRefresher、NacosConfigManager这两个核心。
NacosContextRefresher主要是做桥梁的作用,通过ApplicationContext获取上下文信息,通过ApplicationListener来通知事件的发布更新Spring容器。
NacosConfigManager作为配置的启动,创建长轮询的定时任务,定时执行任务获取更新的配置。