第三章-Nacos配置中心

# 第三章 Nacos 配置中心

微服务的配置文件:

- 不同的微服务可能共享配置文件,只有部分的内容不同

- 同一个微服务集群的配置文件是相同的。

这个时候,对配置文件的更新维护就是一个麻烦的问题,并且某些业务的配置在配置文件中写死了,每次修改配置文件都要重启微服务。

**配置中心**可以解决这些问题,将**同一个集群的相同配置文件**都交给配置中心统一管理,将**不同集群的共享配置文件**也交给配置中心统一管理。

配置中心的产品有很多:Spring Cloud Config、Zookeeper、Apollo、Disconf等。Spring Cloud Alibaba推荐使用Nacos作为微服务的配置中心。

## 配置中心产品

### Spring Cloud Config

![SpringCloudConfig.drawio.png](https://obsidian-1320529117.cos.ap-beijing.myqcloud.com/pic/202402121111621.png)

我们更新配置文件后,需要手动向Config Client提交POST请求更新配置文件,Config Client通过Config Server从远程库拉取配置文件。

假设向微服务集群a提交POST请求,会分为两步:

1. Config Client a 通过Config Server从远程库拉取配置文件更新到本地。
2. Config Client a 将请求封装,通过消息总线系统告知Config Client b 和 Config Client c,重复上步操作。

存在的问题:

1. Config Client无法主动感知更新
2. 如果只想修改Config Client a的配置文件,会导致注册在消息总线系统上的服务都更新配置文件,羊群效应,影响系统
3. 架构过于复杂,GitLab是集群,Config Server是集群,Config Server 和 Config Client 之间需要 Nginx 反向代理负载均衡,Nginx也是个集群,MQ也是集群。

### Nacos

![Nacos.drawio.png](https://obsidian-1320529117.cos.ap-beijing.myqcloud.com/pic/202402121136119.png)

前提:必须使用外置数据库MySQL

我们更新配置文件后,更新自动推送到**对应的Config Client中**,没有羊群效应。

架构比Apollo简单,支持的类型比Apollo多,可以实时更新。

![config-desc-pro.jpeg | 650](https://obsidian-1320529117.cos.ap-beijing.myqcloud.com/pic/202402010322952.jpeg)

配置文件交给Nacos保存和管理,在Nacos控制台修改配置后,Nacos自动将配置推送给相关的微服务,无需重启即可生效。

## 一致性问题

配置中心的配置数据一般都是持久化在第三方服务器的,例如MySQL或GitLab。这些配置中心server中没有数据,不存在数据一致性问题

但像zookeeper,作为配置中心时数据是存在zookeeper服务器中的,所以zookeeper集群是存在数据一致性问题的,zookeeper采用的是CP模式,保证了一致性牺牲可用性。

## 当前服务配置文件

微服务会自动拉取和自身相关的配置文件,也就是每个微服务集群独有的配置文件。

在nacos控制台创建**同一个微服务集群使用的相同配置**文件:

![image.png](https://obsidian-1320529117.cos.ap-beijing.myqcloud.com/pic/202402121200538.png)

注意:

- data id 为 depart-provider.yml
- file-extension 为 yaml/yml

发布之后修改本地的application.yml文件:

```yml
spring:  
  # 微服务名称  
  application:  
    name: depart-provider
```

参照[官网](https://nacos.io/docs/v2/ecology/use-nacos-with-spring-cloud/) - [生态融合-配置中心](https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config)引入依赖:

```xml
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
```

### 2021.x之后版本

application.yml:

```yml
#application.yml

spring:  
  # 微服务名称  
  application:  
    name: depart-provider  
 
  cloud:  
    nacos:  
      #拉取共享配置  
      config:  
        server-addr: localhost:8848  
        # 指定文件格式为yaml
        file-extension: yaml
```

> 官网上说明默认的文件格式是properties,需要指定为yaml或yml

在老版本的Spring Cloud中,这样配置就可以了,会自动在nacos中寻找名称为:

**`${spring.application.name}.${spring.cloud.nacos.config.file-extension}` 的文件拉取**,所以不指定file-extension默认拉取的是...properties文件。

但是新版本直接启动会报错:

```sh
***************************
APPLICATION FAILED TO START
***************************

Description:

No spring.config.import property has been defined

Action:

Add a spring.config.import=nacos: property to your configuration.
    If configuration is not required add spring.config.import=optional:nacos: instead.
    To disable this check, set spring.cloud.nacos.config.import-check.enabled=false.
```

需要添加一个配置:

```yml
spring:  
  # 微服务名称  
  application:  
    name: depart-provider  
 
  cloud:  
    nacos:  
      #拉取共享配置  
      config:  
        server-addr: localhost:8848  
        file-extension: yml  
        username: nacos  
        password: nacos  
 
  config:  
    import:  
      - optional:nacos:depart-provider.yml
```

需要指定加载的配置文件名称:depart-provider.yml

此处也可以使用动态配置:

```yml
spring:  
  # 微服务名称  
  application:  
    name: depart-provider  
 
  cloud:  
    nacos:  
      #拉取共享配置  
      config:  
        server-addr: localhost:8848  
        file-extension: yml  
        username: nacos  
        password: nacos  
 
  config:  
    import:  
      #- optional:nacos:depart-provider.yml  
      - optional:nacos:${spring.application.name}.${spring.cloud.nacos.config.file-extension}
```

注意:这种方式必须将file-extension配置为yml。

### 2021.x及之前版本

使用Nacos Config拉取配置文件替代本地配置,在[官网](https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config)中说明:

**必须使用 bootstrap.properties 配置文件来配置Nacos Server 地址**,例如:

bootstrap.properties

```ini
spring.application.name=nacos-config
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
```

这个配置对于2021.x及其之前版本有效,2021.x之后版本读取的就是application.yml,不需要配置bootstrap.yml。

- Spring Boot启动流程:

![image.png | 250](https://obsidian-1320529117.cos.ap-beijing.myqcloud.com/pic/202402010352398.png)

- Spring Cloud启动流程:

![image.png | 650](https://obsidian-1320529117.cos.ap-beijing.myqcloud.com/pic/202402010353271.png)

我们想拉取Nacos的配置文件并和本地的application.yml合并完成上下文初始化,但是读取Nacos配置是Spring Cloud上下文初始化时完成的,然后才会初始化Spring Boot上下文(读取application.yml文件)。

**在Spring Cloud初始化时,未读取application.yml文件,不知道nacos的地址,如何从配置中心加载文件?**

Spring Cloud上下文初始化时会先加载bootstrap.yml文件,将nacos的地址配置在bootstrap.yml文件中在初始化Spring Cloud时就知道nacos的地址了。

![image.png | 650](https://obsidian-1320529117.cos.ap-beijing.myqcloud.com/pic/202402010357920.png)

因此,2021.x整合nacos配置的步骤如下:

pom:

```xml
  <!--nacos配置管理-->
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  </dependency>
  <!--读取bootstrap文件-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-bootstrap</artifactId>
  </dependency>
```

bootstrap.yml:

```yml
spring:
    application:
        name: depart-provider
    cloud:
        naocs:
            server-addr: localhost:8848
            config:
                file-extension: yml
```

此时就会自动在nacos中寻找名称为 `${spring.application.name}.${spring.cloud.nacos.config.file-extension}`的文件拉取。

## 共享配置文件

上例实现的是同一个微服务集群拉取相同的配置文件,拉取的文件名称是默认的

`${spring.application.name}.${spring.cloud.nacos.config.file-extension}`

我们也**可以指定拉取某一个配置**,这样就能实现:**多个微服务集群之间共享配置**

通过shared-config指定要拉取的配置文件:

```yml
spring:  
  # 微服务名称  
  application:  
    name: depart-provider  
 
  cloud:  
    nacos:  
      #拉取共享配置  
      config:  
        server-addr: localhost:8848  
        file-extension: yml  
        username: nacos  
        password: nacos  
        shared-configs:  
          - data-id: shared-template.yml  
            refresh: true  
 
  config:  
    import:  
      #- optional:nacos:depart-provider.yml  
      - optional:nacos:shared-template.yml
      - optional:nacos:${spring.application.name}.${spring.cloud.nacos.config.file-extension}
```

shared-config配置项会加载指定共享的配置,refresh指定对该配置文件热更新。

## 扩展配置文件

在某些版本的Spring Cloud中,shared-config拉取的配置文件只能是和当前微服务处于同一个三元组中的,如果要拉取其他三元组的配置文件需要使用extension-config:

```yml
spring:  
  datasource:  
    url: jdbc:mysql://localhost:3306/rc2?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=true  
    password: root  
    username: root  
    driver-class-name: com.mysql.cj.jdbc.Driver  
  # 微服务名称  
  application:  
    name: depart-provider  
  #nacos注册中心地址  
  cloud:  
    nacos:  
      discovery:  
        server-addr: 127.0.0.1:8848  
        username: nacos  
        password: nacos  
      config:  
        server-addr: 127.0.0.1:8848  
        username: nacos  
        password: nacos  
        file-extension: yml  
        # 共享配置
        shared-configs:  
          - data-id: shared-template.yml  
            refresh: true  
        # 扩展配置
        extension-configs:  
          - data-id: extension-template.yml
```

## 配置文件优先级

微服务会加载三类配置文件:自己的配置文件,shared-config共享配置文件,extension-config扩展配置文件

如果这三类配置文件中设置了同一个属性,例如:server.port,但是这三类配置文件的值都不相同,最终的值是哪个?

当前服务配置、共享配置、扩展配置加载顺序是:

- 共享配置
- 扩展配置
- 当前服务配置

**后加载的会覆盖之前加载的内容**。

优先级由高到低是:

- 当前服务配置
- 扩展配置
- 共享配置

并且如果Nacos和本地有相同的配置,会以Nacos的配置为主。

当前服务配置 > 扩展配置 > 共享配置 > 本地配置

## 配置动态更新

在nacos中添加一个配置:

![image.png](https://obsidian-1320529117.cos.ap-beijing.myqcloud.com/pic/202402130039791.png)

### @ConfirguationProperties读取数据

```java
@Data  
//@RefreshScope 2021.x不需要添加
@ConfigurationProperties(prefix = "depart")  
public class DepartProperties {  
    private String name;  
}
```

```java
@RestController   
@RequestMapping("/provider/depart")  
@EnableConfigurationProperties(DepartProperties.class)  
public class DepartController {  
 
    @Resource  
    private DepartService departService;  
 
    @Value("${server.port}")  
    private String port;  
 
    @Autowired  
    private DepartProperties departProperties;  
 
    @GetMapping("/{id}")  
    public ResponseResult<Depart> getHandler(@PathVariable Long id){  
        Depart depart = departService.getById(id);  
        depart.setName(depart.getName() + " this provider port:" + port + " this depart name:" + departProperties.getName());  
        return ResponseResult.success(depart);  
    }  
}
```

在nacos控制台修改了共享配置后,此处自动会更新,2021.x版本不需要添加@RefreshScope

### @Value读取数据

如果使用@Value读取数据:

```java
//provider#DepartController

@Value("${server.port}")  
private String port;  
 
@Value("${depart.name}")  
private String departName;  
 
@GetMapping("/{id}")  
public ResponseResult<Depart> getHandler(@PathVariable Long id){  
    Depart depart = departService.getById(id);  
    depart.setName(depart.getName() + " this provider port:" + port + " this depart name:" + departName);  
    return ResponseResult.success(depart);  
}
```

第一次访问得到的是销售部,将nacos中的配置文件更换为行政部,再次访问,得到的还是销售部。

**使用@Value读取的配置文件数据需要在类上标注@RefreshScope才能动态刷新**

```java
@RestController  
@RefreshScope  
@RequestMapping("/provider/depart")  
public class DepartController {  
 
    @Resource  
    private DepartService departService;  
    
    @Value("${server.port}")  
    private String port;  
 
    @Value("${depart.name}")  
    private String departName;  
 
    @GetMapping("/{id}")  
    public ResponseResult<Depart> getHandler(@PathVariable Long id){  
        Depart depart = departService.getById(id);  
        depart.setName(depart.getName() + " this provider port:" + port + " this depart name:" + departName);  
        return ResponseResult.success(depart);  
    }  
}
```

## 多环境选择

dev、local、test

前文中说明了微服务会自动拉取当前服务的配置文件:`${spring.application.name}.${spring.cloud.nacos.config.file-extension}`

如果要区分不同的环境,在nacos中配置文件的命名是:

`${spring.application.name}-${spring.profiles.activity}.${spring.cloud.nacos.config.file-extension}`

例如:

- depart-provider-dev.yml
- depart-provider-test.yml

在application.yml/bootstrap.yml中指定要激活的环境:

```yml
spring:  
  # 微服务名称  
  application:  
    name: depart-provider  
 
  cloud:  
    nacos:  
      #拉取共享配置  
      config:  
        server-addr: localhost:8848  
        file-extension: yml  
        username: nacos  
        password: nacos  
        shared-configs:  
          - data-id: shared-template.yml  
            refresh: true  
        extension-configs:  
          - data-id: extension-config.yml  
 
  config:  
    import:  
      #- optional:nacos:depart-provider.yml  
      - optional:nacos:shared-template.yml  
      - optional:nacos:${spring.application.name}-${spring.profiles.active}
                                                          .${spring.cloud.nacos.config.file-extension}
 
  profiles:  
    active: dev
```

此时就会去nacos中拉取depart-provider-dev.yml的配置文件。

在开发时,如果要修改环境配置,不必修改这个配置文件,直接修改edit-config的active profiles即可
## 配置隔离





















posted @   EUNEIR  阅读(237)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示