1. Nacos 配置中心

    Nacos Server 还可以作为配置中心,对 Spring Cloud 应用的外部配置进行统一地集中化管理。而我们只需要在应用的 POM 文件中引入 spring-cloud-starter-alibaba-nacos-config 即可实现配置的获取与动态刷新。

    从配置管理的角度看,Nacos 可以说是 Spring Cloud Config 的替代方案,但相比后者 Nacos 的使用更简单,操作步骤也更少。

    本文在 “Springcloud基础知识(11)- Spring Cloud Alibaba Nacos (一) | Nacos 简介、服务注册中心” 里 SpringcloudDemo04 项目基础上,创建一个 ConfigClient 子模块,演示配置的统一管理和动态刷新。

    1) 创建 Maven 模块

        选择左上的项目列表中的 SpringcloudDemo04,点击鼠标右键,选择 New -> Module 进入 New Module 页面:

            Maven -> Project SDK: 1.8 -> Check "Create from archtype" -> select "org.apache.maven.archtypes:maven-archtype-quickstart" -> Next

                Name: ConfigClient
                GroupId: com.example
                ArtifactId: ConfigClient

            -> Finish

    2) 修改 pom.xml,内容如下。

1         <?xml version="1.0" encoding="UTF-8"?>
 2         <project xmlns="http://maven.apache.org/POM/4.0.0"
 3                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4                 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
 5                                     http://maven.apache.org/xsd/maven-4.0.0.xsd">
 6             <parent>
 7                 <artifactId>SpringcloudDemo04</artifactId>
 8                 <groupId>com.example</groupId>
 9                 <version>1.0-SNAPSHOT</version>
10             </parent>
11             <modelVersion>4.0.0</modelVersion>
12 
13             <artifactId>ConfigClient</artifactId>
14 
15             <name>ConfigClient</name>
16             <!-- FIXME change it to the project's website -->
17             <url>http://www.example.com</url>
18 
19             <properties>
20                 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
21                 <maven.compiler.source>1.8</maven.compiler.source>
22                 <maven.compiler.target>1.8</maven.compiler.target>
23             </properties>
24 
25             <dependencies>
26                 <dependency>
27                     <groupId>junit</groupId>
28                     <artifactId>junit</artifactId>
29                     <scope>test</scope>
30                 </dependency>
31                 <dependency>
32                     <groupId>org.springframework.boot</groupId>
33                     <artifactId>spring-boot-starter-web</artifactId>
34                 </dependency>
35                 <dependency>
36                     <groupId>org.springframework.boot</groupId>
37                     <artifactId>spring-boot-starter-test</artifactId>
38                     <scope>test</scope>
39                 </dependency>
40                 <!-- SpringCloud2020 及以后的版本默认不启用 bootstrap 配置,需要在pom里面显式导入 -->
41                 <dependency>
42                     <groupId>org.springframework.cloud</groupId>
43                     <artifactId>spring-cloud-starter-bootstrap</artifactId>
44                 </dependency>
45                 <!--Spring Cloud Alibaba Config 依赖-->
46                 <dependency>
47                     <groupId>com.alibaba.cloud</groupId>
48                     <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
49                 </dependency>
50                 <!-- Spring Cloud Ailibaba Nacos 服务注册与发现模块 -->
51                 <dependency>
52                     <groupId>com.alibaba.cloud</groupId>
53                     <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
54                 </dependency>
55                 <!-- Spring Boot 监控模块 -->
56                 <dependency>
57                     <groupId>org.springframework.boot</groupId>
58                     <artifactId>spring-boot-starter-actuator</artifactId>
59                 </dependency>
60             </dependencies>
61 
62             <build>
63                 <plugins>
64                     <plugin>
65                         <groupId>org.springframework.boot</groupId>
66                         <artifactId>spring-boot-maven-plugin</artifactId>
67                         <configuration>
68                             <mainClass>com.example.App</mainClass>
69                             <layout>JAR</layout>
70                         </configuration>
71                         <executions>
72                             <execution>
73                                 <goals>
74                                     <goal>repackage</goal>
75                                 </goals>
76                             </execution>
77                         </executions>
78                     </plugin>
79                 </plugins>
80             </build>
81 
82         </project>

    3) 创建 src/main/resources/bootstrap.yml 文件

server:
            port: 6001 # 端口号
        spring:
            application:
                name: alibaba-config-client # 服务名
            cloud:
                nacos:
                    discovery:
                        server-addr: 127.0.0.1:8848 # Nacos 服务注册中心地址
                    config:
                        server-addr: ${spring.cloud.nacos.discovery.server-addr} # Nacos 作为配置中心地址
                        file-extension: yaml        # 指定 yaml 格式的配置
            profiles:
                active: dev # 激活 dev 的配置

    4) 创建 src/main/java/com/example/controller/IndexController.java 文件

1         package com.example.controller;
 2 
 3         import org.springframework.beans.factory.annotation.Value;
 4         import org.springframework.cloud.context.config.annotation.RefreshScope;
 5         import org.springframework.web.bind.annotation.GetMapping;
 6         import org.springframework.web.bind.annotation.RestController;
 7 
 8         @RestController
 9         @RefreshScope
10         public class IndexController {
11             @Value("${config.info}")
12             private String ConfigInfo;
13 
14             @GetMapping("/config/info")
15             public String getConfigInfo(){
16                 return ConfigInfo;
17             }
18         }

    5) 修改 src/main/java/com/example/App.java 文件

1         package com.example;
 2 
 3         import org.springframework.boot.SpringApplication;
 4         import org.springframework.boot.autoconfigure.SpringBootApplication;
 5         import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 6 
 7         @SpringBootApplication
 8         @EnableDiscoveryClient
 9         public class App {
10             public static void main(String[] args) {
11                 SpringApplication.run(App.class, args);
12             }
13         }

    6) 在 Nacos Server 上添加配置
    
        启动 Nacos Server,并在 Nacos Server 控制台的 “配置管理” 下的 “配置列表” 中,点击 “+” 按钮,新建如下配置。

            Data ID: alibaba-config-client-dev.yaml
            Group:   DEFAULT_GROUP
            配置格式: YAML
            配置内容: config:
                         info: com.example.nacos

        在 Nacos Server 中,配置的 dataId(即 Data ID)的完整格式如下:

            ${prefix}-${spring.profiles.active}.${file-extension}

        dataId 格式中各参数说明如下:

            (1) ${prefix}:默认取值为微服务的服务名,即配置文件中 spring.application.name 的值,我们可以在配置文件中通过配置 spring.cloud.nacos.config.prefix 来指定。
            (2) ${spring.profiles.active}:表示当前环境对应的 Profile,例如 dev、test、prod 等。当没有指定环境的 Profile 时,其对应的连接符也将不存在, dataId 的格式变成 ${prefix}.${file-extension}。
            (3) ${file-extension}:表示配置内容的数据格式,我们可以在配置文件中通过配置项 spring.cloud.nacos.config.file-extension 来配置,例如 properties 和 yaml。

    7) 运行

        启动 ConfigClient 模块,浏览器访问 “http://localhost:6001/config/info”,结果如下。

            com.example.nacos

        在 Nacos Server 中,将 alibaba-config-client-dev.yaml 中的配置修改成如下内容。

            config:
                info: com.example.nacos (modify 1)

        在不重启 ConfigClient 模块的情况下,浏览器再次访问 “http://localhost:6001/config/info”,结果如下。

            com.example.nacos (modify 1)

2. Nacos Server 集群化部署

    在实际的项目开发中,一个微服务系统往往由十几,几十个甚至几百个微服务组成。 这些服务若全部注册到同一台 Nacos Server,就极有可能导致 Nacos Server 因为不堪重负而崩溃,最终导致整个微服务系统瘫痪。解决这个问题最直接的办法就是使用 Nacos Server 集群。

    Nacos Server 的集群化部署有一个十分明显的优点,那就是可以保障系统的高可用性。在集群化部署中,只要不是所有的 Nacos Server 都停止工作,Nacos Client 就还可以从集群中正常的 Nacos Server 上获取服务信息及配置,而不会导致系统的整体瘫痪,这就是 Nacos Server 集群化部署的高可用性。

    下图展示了 Nacos Server 集群化部署的基本架构。

                      请求
                        |
                       V
                    Nginx
                /      |      \
        Nacos1  Nacos2  Nacos3
               \       |       /
            MariaDB(MySQL)


        架构说明:

            Nginx: 本文使用端口 8848,关于 Nginx 可以访问官方网站 http://nginx.org/en/

            Nacos1: 第一台 Nacos Server,192.168.0.2:8851
            Nacos2: 第二台 Nacos Server,192.168.0.3:8851
            Nacos3: 第三台 Nacos Server,192.168.0.4:8851

            MariaDB(MySQL):Nacos Server 集群化需要数据库的支持,创建一个 MariaDB(MySQL) 数据库名称为 nacos_config,生成数据库表的 SQL 脚本 nacos-mysql.sql 在 Nacos 安装目录下的 conf 文件夹中 ,也可以从 GitHub 下载,地址:https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql。

    本文在 Windows 下演示 Nacos Server 集群化部署,Ngnix 和 MariaDB(MySQL) 使用相应的 Windows 版本。

    1) Nacos Server 配置

        (1) 配置 cluster.conf
        
            在 Nacos1 安装目录下的 conf 文件夹中,将 cluster.conf.example 重命名为 cluster.conf,然后在该文件中添加以下内容。

                192.168.0.2:8851
                192.168.0.3:8851
                192.168.0.4:8851

            注:Nacos2、Nacos3 采用 Nacos1 同样的配置。

        (2) 配置 application.properties

            在 Nacos1 安装目录下的 conf 文件夹中,修改 application.properties 文件

1                 server.port=8851
 2                 server.address=192.168.0.2
 3 
 4                 #### MySQL 数据库配置 ####
 5                 spring.datasource.platform=mysql
 6 
 7                 db.num=1
 8                 db.url.0=jdbc:mysql://192.168.0.2:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
 9                 db.user=nacos
10                 db.password=nacos

            注: Nacos2、Nacos3 的 server.address 分别是 192.168.0.3、192.168.0.4,server.port 都是 8851。这里的数据库在 192.168.0.2 主机上,Nacos2、Nacos3 的数据库配置和 Nacos1 一样。

        (3) 启动 Nacos Server
        
            在 Nacos1 安装目录下的 bin 文件夹下,运行如下命令:

                > startup

1                 "nacos is starting with cluster"
 2 
 3                         ,--.
 4                     ,--.'|
 5                 ,--,:  : |                                                  Nacos 2.1.0
 6                 ,`--.'`|  ' :                       ,---.                   Running in cluster mode, All function modules
 7                 |   :  :  | |                      '   ,'\   .--.--.        Port: 8851
 8                 :   |   \ | :  ,--.--.     ,---.  /   /   | /  /    '       Pid: 35816
 9                 |   : '  '; | /       \   /     \.   ; ,. :|  :  /`./       Console: http://192.168.0.2:8851/nacos/index.html
10                 '   ' ;.    ;.--.  .-. | /    / ''   | |: :|  :  ;_
11                 |   | | \   | \__\/: . ..    ' / '   | .; : \  \    `.      https://nacos.io
12                 '   : |  ; .' ," .--.; |'   ; :__|   :    |  `----.   \
13                 |   | '`--'  /  /  ,.  |'   | '.'|\   \  /  /  /`--'  /
14                 '   : |     ;  :   .'   \   :    : `----'  '--'.     /
15                 ;   |.'     |  ,     .-./\   \  /            `--'---'
16                 '---'        `--`---'     `----'
17 
18                 2022-07-14 09:28:15,745 INFO The server IP list of Nacos is [192.168.0.2:8851, 192.168.0.3:8851, 192.168.0.4:8851]
19 
20                 2022-07-14 09:28:16,748 INFO Nacos is starting...
21 
22                 2022-07-14 09:28:17,750 INFO Nacos is starting...
23 
24                 ...
25 
26                 2022-07-14 09:28:28,301 INFO Nacos started successfully in cluster mode. use external storage

            注:Nacos2、Nacos3 采用 Nacos1 同样的方式运行。

    2) Nginx 配置

        修改 Nginx 中 conf 目录下的 nginx.conf 的配置,内容如下。

1             #user  nobody;
 2             worker_processes  1;
 3 
 4             #error_log  logs/error.log;
 5             #error_log  logs/error.log  notice;
 6             #error_log  logs/error.log  info;
 7 
 8             #pid        logs/nginx.pid;
 9 
10             events {
11                 worker_connections  1024;
12             }
13 
14 
15             http {
16                 include       mime.types;
17                 default_type  application/octet-stream;
18                 sendfile        on;
19                 keepalive_timeout  65;
20                 upstream cluster{
21                     server 192.168.0.2:8851;
22                     server 192.168.0.3:8851;
23                     server 192.168.0.4:8851;
24                 }
25 
26                 server {
27                     listen       127.0.0.1:8848;
28                     server_name  localhost;
29                     #charset koi8-r;
30                     #access_log  logs/host.access.log  main;
31                     location / {
32                         #root   html;
33                         #index  index.html index.htm;
34                         proxy_pass cluster;
35                     }
36                 }
37             }

        在本地运行 Nginx,浏览器访问 http://localhost:8848/nacos/,跳转到登陆页面,输入登录名和密码(默认 nacos/nacos),点击提交按钮,跳转到 Nacos Server 控制台页面。

    3) 运行

        这里使用 SpringcloudDemo04 项里的 ServiceProvider、Consumer 子模块和本文的 ConfigClient 子模块,来测试 Nacos Server 集群。

        运行 ServiceProvider,浏览器访问 “http://localhost:8001/service/1”,结果如下。

            Nacos - Service Provider
            Service Name: alibaba-service-provider
            Port: 8001
            Id: 1
         
        运行 Consumer,浏览器访问 “http://localhost:5001/consumer/service/3”,结果如下。

            Nacos - Service Provider
            Service Name: alibaba-service-provider
            Port: 8001
            Id: 3
    
        浏览器访问 http://localhost:8848/nacos/,在 Nacos Server 控制台的 “配置管理” 下的 “配置列表” 中,点击 “+” 按钮,新建如下配置。

            Data ID: alibaba-config-client-dev.yaml
            Group:   DEFAULT_GROUP
            配置格式: YAML
            配置内容: config:
                         info: com.example.nacos (modify 2)

            注:此时的配置被保存到了 nacos_config 数据库。

        运行 ConfigClient,浏览器访问 “http://localhost:6001/config/info”,结果如下。

            com.example.nacos (modify 2)

    注:在运行 ConfigClient 时,如果 Nignx 或 Nacos 所在的主机是多网卡环境并出现无法链接等情况,先查看 nacos 的 cluster.conf 里是否被添加了其它网卡的 IP,如果有,把它删除,并尝试暂时禁用其它网卡进行测试。