SpringCloud中的nacos配置中心分析

一、概述
nacos可以作为配置管理使用,为各个微服务之间提供统一的配置中心,方便管理所有服务的配置。

二、什么是配置中心?

配置中心:一般SpringBoot项目都使用在resources下创建类似application.yml之类的配置文件来管理整个项目的一些配置信息。

当微服务部署的实例越来越多时,这时候逐个修改配置效率非常低,也容易出错,那么提供统一的配置中心就可以集中管理各个服务配置了。

三、nacos配置中心原理解析
1.配置中心核心接口ConfigService获取配置
在这里插入图片描述
获取配置的主要方法是 NacosConfigService 类的 getConfig 方法,通常情况下该方法直接从本地文件中取得配置的值,如果本地文件不存在或者内容为空,则再通过 HTTP GET 方法从远端拉取配置,并保存到本地快照中。当通过 HTTP 获取远端配置时,Nacos 提供了两种熔断策略,一是超时时间,二是最大重试次数,默认重试三次。

2.nacos客户端获取服务配置

public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {
        return this.getConfigInner(this.namespace, dataId, group, timeoutMs);
    }

具体实现

private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {
        group = this.blank2defaultGroup(group);
        ParamUtils.checkKeyParam(dataId, group);
        ConfigResponse cr = new ConfigResponse();
        cr.setDataId(dataId);
        cr.setTenant(tenant);
        cr.setGroup(group);
        String content = LocalConfigInfoProcessor.getFailover(this.worker.getAgentName(), dataId, group, tenant);
        String encryptedDataKey;
        if (content != null) {
            LOGGER.warn("[{}] [get-config] get failover ok, dataId={}, group={}, tenant={}, config={}", new Object[]{this.worker.getAgentName(), dataId, group, tenant, ContentUtils.truncateContent(content)});
            cr.setContent(content);
            encryptedDataKey = LocalEncryptedDataKeyProcessor.getEncryptDataKeyFailover(this.agent.getName(), dataId, group, tenant);
            cr.setEncryptedDataKey(encryptedDataKey);
            this.configFilterChainManager.doFilter

以下是读取本地配置具体实现。

public static String getFailover(String serverName, String dataId, String group, String tenant) {
        File localPath = getFailoverFile(serverName, dataId, group, tenant);
        if (localPath.exists() && localPath.isFile()) {
            try {
                return readFile(localPath);
            } catch (IOException var6) {
                LOGGER.error("[" + serverName + "] get failover error, " + localPath, var6);
                return null;
            }
        } else {
            return null;
        }
    }

当本地文件为空时,则需要去向这个服务端的配置中心发起http请求,最后会通过这个接口回调来判断这个响应的状态码。
基本实现调getServerConfig方法。

 public ConfigResponse getServerConfig(String dataId, String group, String tenant, long readTimeout, boolean notify) throws NacosException {
        if (StringUtils.isBlank(group)) {
            group = "DEFAULT_GROUP";
        }

        return this.agent.queryConfig(dataId, group, tenant, readTimeout, notify);
    }

内部调queryConfig方法获取远端配置,这里就不具体细说了。

3.nacos的服务配置监听
在整个容器启动完成后,就会去调用这个监听器,nacos在NacosContextRefresher类下实现监听。其实现了这个ApplicationListener这个接口,就是一个nacos的一个上下文的一个刷新流。

public NacosContextRefresher(NacosConfigManager nacosConfigManager, NacosRefreshHistory refreshHistory) {
        this.nacosConfigProperties = nacosConfigManager.getNacosConfigProperties();
        this.nacosRefreshHistory = refreshHistory;
        this.configService = nacosConfigManager.getConfigService();
        this.isRefreshEnabled = this.nacosConfigProperties.isRefreshEnabled();
    }

    public void onApplicationEvent(ApplicationReadyEvent event) {
        if (this.ready.compareAndSet(false, true)) {
            this.registerNacosListenersForApplications();
        }

    }

这个类里面,会调用一个onApplicationEvent的事件方法,里面就会去进行nacos的监听的一个注册。

private void registerNacosListenersForApplications() {
        if (this.isRefreshEnabled()) {
            Iterator var1 = NacosPropertySourceRepository.getAll().iterator();

            while(var1.hasNext()) {
                NacosPropertySource propertySource = (NacosPropertySource)var1.next();
                if (propertySource.isRefreshable()) {
                    String dataId = propertySource.getDataId();
                    this.registerNacosListener(propertySource.getGroup(), dataId);
                }
            }
        }

    }

这个方法会去获取nacos的全部的配置文件,然后在获取dataId 之后,通过这个dataId对这个服务进行一个监听。

其中registerNacosListener 方法的具体实现如下,当配置发生变化的时候,这个监听方法就会发起一个调用。

private void registerNacosListener(final String groupKey, final String dataKey) {
        String key = NacosPropertySourceRepository.getMapKey(dataKey, groupKey);
        Listener listener = (Listener)this.listenerMap.computeIfAbsent(key, (lst) -> {
            return new AbstractSharedListener() {
                public void innerReceive(String dataId, String group, String configInfo) {
                    NacosContextRefresher.refreshCountIncrement();
                    NacosContextRefresher.this.nacosRefreshHistory.addRefreshRecord(dataId, group, configInfo);
                    NacosContextRefresher.this.applicationContext.publishEvent(new RefreshEvent(this, (Object)null, "Refresh Nacos config"));
                    if (NacosContextRefresher.log.isDebugEnabled()) {
                        NacosContextRefresher.log.debug(String.format("Refresh Nacos config group=%s,dataId=%s,configInfo=%s", group, dataId, configInfo));
                    }

                }
            };
        });

        try {
            this.configService.addListener(dataKey, groupKey, listener);
            log.info("[Nacos Config] Listening config: dataId={}, group={}", dataKey, groupKey);
        } catch (NacosException var6) {
            log.warn(String.format("register fail for nacos listener ,dataId=[%s],group=[%s]", dataKey, groupKey), var6);
        }

    }
 

最后会去调用一个refresh方法,会进行一个环境的刷新,将新的参数和原来的参数进行一个比较,通过发布这个环境变更事件,对做出改变的值进行一个更新操作。

总结:
就是这个客户端进行启动的时候,就会优先拉取本地的配置,如果本地配置不存在,那么就会和这个服务端建立这个http请求,然后去拉取这个服务端的全部配置,就是配置中心的全部配置。在拉取到全部配置之后,会去获取每一个配置文件的dataId,然后通过这个id对服务端的每一个配置文件进行一个监听的操作。当服务端这边的配置文件出现修改的时候,就可以通过这个监听器进行感知,然后这个客户端也会对对应的配置文件进行修改,每一份修改的配置都会存储在这个nacos配置文件里面,会作为一个历史文件保留。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜空下的星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值