Alibaba微服务组件Nacos配置中心

01 Nacos配置中心实战

引入依赖

         <!--nacos配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

配置文件的优先级 从高到低

# ${spring.application.name}-${profile}.${file-extension:properties}
#${spring.application.name}.${file-extension:properties}
#${spring.application.name}
#extensionConfigs    nacos.yml
#sharedConfigs     多个微服务公共配置  redis
@RestController
@RefreshScope // 此注解可以感知value变化
public class TestController {

    @Value("${common.age}")
    private String age;

    @GetMapping("/common")
    public String hello() {
        return age;
    }

}

Alibaba微服务组件Nacos配置中心

在bootstrap.properties文件中配置,可以配置profile/namespace/group/dataId(直接指定文件名),dataId也可以是共享sharedConfigs也可以是独立extensionConfigs

spring.application.name=nacos-config
# 配置中心地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
# 关闭配置中心
#spring.cloud.nacos.config.enabled = false

# dataid 为 yaml 的文件扩展名配置方式
# `${spring.application.name}.${file-extension:properties}`
spring.cloud.nacos.config.file-extension=yaml
#profile粒度的配置   `${spring.application.name}-${profile}.${file-extension:properties}`
# nacos-config-prod.yaml
spring.profiles.active=prod

#自定义 namespace 的配置
spring.cloud.nacos.config.namespace=39e1e969-15f9-46d2-832d-fa052da55377

# 自定义 Group 的配置
spring.cloud.nacos.config.group=DEFAULT_GROUP

# 自定义 Data Id 的配置
#不同工程的通用配置 支持共享的 DataId   redis
spring.cloud.nacos.config.sharedConfigs[0].data-id= common.yaml
spring.cloud.nacos.config.sharedConfigs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.sharedConfigs[0].refresh=true

# config external configuration
# 支持一个应用多个 DataId 的配置   nacos.yml  mybatis.yml
spring.cloud.nacos.config.extensionConfigs[0].data-id=nacos.yaml
spring.cloud.nacos.config.extensionConfigs[0].group=REFRESH_GROUP
spring.cloud.nacos.config.extensionConfigs[0].refresh=true

springboot 和nacos整合

<dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>nacos-config-spring-boot-actuator</artifactId>
            <version>${nacos-config-spring-boot.version}</version>
        </dependency>
application.properties配置文件就这一句就够了 nacos.config.server-addr=127.0.0.1:8848
@SpringBootApplication
// 配置使用哪个dataId做为数据源
@NacosPropertySource(dataId = "example", autoRefreshed = true)
public class NacosConfigApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosConfigApplication.class, args);
    }
}

@Controller
@RequestMapping("config")
public class ConfigController {
    // 这个 获取配置的值
    @NacosValue(value = "${useLocalCache:false}", autoRefreshed = true)
    private boolean useLocalCache;

    @RequestMapping(value = "/get", method = GET)
    @ResponseBody
    public boolean get() {
        return useLocalCache;
    }
}

02 Nacos配置中心架构剖析

Alibaba微服务组件Nacos配置中心

 

03 Nacos Config client源码分析

入口:接口 核心方法

多个配置优先级是怎么样的

springboot加载属性配置:org.springframework.boot.env.PropertySourceLoader接口有两个实现类

把某个实现类的load方法作为他的入口 org.springframework.boot.env.PropertiesPropertySourceLoader#load

启动过程中,也是走了SpringApplication的run方法,发布了ApplicationEnvironmentPreparedEvent 环境准备事件 ,org\springframework\cloud\bootstrap\BootstrapApplicationListener监听器触发,过程中又调回springboot的方法,ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); 又把事件传给了springboot的监听器ConfigFileApplicationListener,他会加载所有的配置文件,过程中 PropertiesPropertySourceLoader#load方法先加载bootstrap.properties,再加载application.properties...

04 client端是如何从配置中心获取配置的

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

05 配置中心配置发生变更Client是如何感知的

所有的配置文件加载完成之后,会给所有的dataid添加一个相应的listener,后台会有一个线程定时去检查配置文件信息,发现文件md5发生改变后,就会触发监听器 的方法,方法内部有会发布RefreshEvent,这个RefreshEventListener会触发ContextRefresher的refresh,刷新环境,替换之前的环境, 注解@RefreshScope修饰的bean会存在一个容器里,旧的bean会被remove,替换成新bean

06 Nacos Config Server源码分析


public class ConfigServerDemo {

    public static void main(String[] args) throws NacosException, InterruptedException {
        String serverAddr = "localhost:8848";
        String dataId = "nacos-config-demo.yaml";
        String group = "DEFAULT_GROUP";
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
        
        //获取配置中心服务
        ConfigService configService = NacosFactory.createConfigService(properties);
        
        //从配置中心拉取配置
        String content = configService.getConfig(dataId, group, 5000);
        System.out.println(content);
        //注册监听器
        configService.addListener(dataId, group, new Listener() {
            @Override
            public void receiveConfigInfo(String configInfo) {
                System.out.println("感知配置变化:" + configInfo);
            }

            @Override
            public Executor getExecutor() {
                return null;
            }
        });

        //发布配置 发送properties格式
        configService.publishConfig(dataId,group,"common.age=30", ConfigType.PROPERTIES.getType());

        Thread.sleep(3000);
        //从配置中心拉取配置
        content = configService.getConfig(dataId, group, 5000);
        System.out.println(content);
        
        Thread.sleep(Integer.MAX_VALUE);

    }
}

07 集群架构下其他节点是如何同步配置数据的

Alibaba微服务组件Nacos配置中心

 服务端启动时就会依赖 DumpService 的 init 方法,从数据库中 load 配置存储在本地磁盘上,并将一些重要的元信息例如 MD5 值缓存在内存中。服务端会根据心跳文件中保存的最后一次心跳时间,来判断到底是从数据库 dump 全量配置数据还是部分增量配置数据(如果机器上次心跳间隔是 6h 以内的话)。

全量 dump 当然先清空磁盘缓存,然后根据主键 ID 每次捞取一千条配置刷进磁盘和内存。增量 dump 就是捞取最近六小时的新增配置(包括更新的和删除的),先按照这批数据刷新一遍内存和文件,再根据内存里所有的数据全量去比对一遍数据库,如果有改变的再同步一次,相比于全量 dump 的话会减少一定的数据库 IO 和磁盘 IO 次数。

如果想改mysql的配置也立即更新到客户端,需要写一个监听器监听变化发布一个ConfigDataChangeEvent事件,否则不重启服务端是不会感知到的。

上一篇:微服务架构 | 2.2 Alibaba Nacos 的统一配置管理


下一篇:使用 openFeign 报初始化 空指针的问题:at org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer.