SpringCloud与微服务-第8章-Nacos分布式配置中心

在微服务架构中,当系统从一个单体应用,被拆分成分布式系统上一个个服务节点后,配置文件也必须跟着迁移(分割)。在系统架构中,配置中心是整个微服务基础架构体系中的一个组件,它的功能看上去并不起眼,无非就是配置的管理和存取,但它是整个微服务架构中不可或缺的一环。


应用程序在启动和运行的时候往往需要读取一些配置信息,配置基本上伴随着应用程序的整个生命周期,应用在启动时通过读取配置来初始化,在运行时根据配置调整行为。同一份程序在不同的环境(开发、测试、生产)、不同的集群(如不同的数据中心)经常需有不同的配置,所以需要有完善的环境、集群配置管理。


Spring Cloud Alibaba Nacos 的一大优势是整合了注册中心、配置中心功能,部署和操作更加直观简单,它简化了架构复杂度,并减轻运维及部署工作。在之前的章节中,我们已经使用 Nacos 作为注册中心,本章节我们将详细介绍 Nacos 配置中心的功能。


目标

在本章中,您将学习:

  • Nacos 配置管理
  • 配置拉取
  • 配置热更新
  • 多环境配置共享
  • Nacos 集群搭建

快速入门

当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置是一件效率非常低的事情,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理所有实例的配置。下面我们就通过一个小案例来感受一下 Spring Cloud Alibaba Nacos 配置中心的强大功能吧。


在 Nacos 中创建配置

我们以 userservice 服务为例,在 Nacos 配置中心创建一份配置文件。进入 Nacos 的管理界面,然后选择配置管理菜单,点击配置列表选项,点击右侧"+"符号,如下图所示:


bg fit


点击之后,填写弹出的表单页,最后点击发布,我们就创建好一份 userservice 服务的配置,如下图所示:


image-20220731211155187


发布成功之后,我们在控制台的配置列表中可以看到新增配置,并且可以进行再次编辑,查看详情,删除等操作。


image-20220731211354245


此时,在 Nacos 配置中心的工作暂时告一段落,我们已经创建好一份 userservice 服务的配置文件,那么怎么样才能让 userservice 服务读取到这份配置呢?


读取 Nacos 中配置

userservice 服务要读取 Nacos 中管理的配置,并且与本地的 application.yml 配置合并,才能完成项目启动。但是此时有一个问题必须解决: 尚未读取 application.yml,又如何得知 nacos 地址呢?


为解决此问题,Spring 引入了一种新的配置文件:bootstrap.yaml 文件,该配置文件的优先级很高,会在 application.yml 之前被读取,流程如下:


image-20220731213028366


首先,我们要给 userservice 引入 Nacos 配置中心的 Maven 依赖:



    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-config

其次,在 resources 目录下创建 bootstrap.yml 文件,并进行配置:

spring:
  application:
    name: userservice # 服务名称
  profiles:
    active: dev #开发环境,这里是dev
  cloud:
    nacos:
      server-addr: localhost:8848 # Nacos地址
      config:
        file-extension: yaml # 文件后缀名

此时,同学们会发现,在 bootstrap.yml 中配置的这些信息,正好可以满足我们的需求: 去 nacos 中查找一个名字为 userservice-dev.yaml 文件。这些信息正是${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}的值拼接而成。


image-20220731213648989


这也是我们在 nacos 中创建配置文件时的命名规则的含义所在。


测试验证

我们在 userservice 中新增一个控制器类,进行测试:

@Slf4j
@RestController
@RequestMapping("/config")
public class NacosConfigTestController {
    @Value("${myconfig.msg}")
    private String msg;

    @RequestMapping("/msg")
    public String getMsg(){
        return this.msg;
    }
}

修改完成之后,我们重启 userservice 服务,访问: http://localhost:8081/config/msg ,结果如图所示:

image-20220731214102597

我们通过简单的几个步骤,成功的使用 Nacos 配置中心的功能,实现了在 Nacos 控制台对配置文件的简单管理。


现在如果尝试修改 Nacos 配置中心的config.msg的值,然后再次访问 http://localhost:8081/config/msg ,会发现返回的结果并没有发生变化,
要想使新的配置生效仍需重启服务.


配置热更新

如果每次线上修改修改了配置文件,都需要重启服务才能生效,这样的话,就会造成服务的中断,这是我们不希望看到的。那么,有没有一种方式,可以实现在线上修改配置文件,而不需要重启服务呢?

答案是可以的, 我们可以通过为 Nacos 的配置热更新来实现此类需求。

所谓的热更新是指,在 Nacos 中的配置文件变更后,对应的微服务无需重启就可以感知到最新的配置。


所谓的 Nacos 配置热更新,就是指 Nacos 中的线上配置变更后, 无需重启服务就可以感知到最新的配置变化。

在微服务中,可以通过 SpringBoot 的方式进行配置的注入 :

  • 通过 @Value 注解进行注入单个配置
  • 通过 @AutoWired 注解进行注入包含多个配置属性的对象
  • 在需要注入配置的类上添加 @RefreshScope 注解,使得注入的配置可以和线上配置保持同步

使用@Value 注解进行注入

@Value 注入的变量所在类上添加注解@RefreshScope,:

@Slf4j
@RestController
@RequestMapping("/config")
@RefreshScope // 添加此注解, 使得配置文件可以热更新
public class NacosConfigTestController {
    @Value("${myconfig.msg}") // 通过@Value 注解进行注入响应的配置
    private String msg;

    @RequestMapping("/msg")
    public String getMsg(){
        return this.msg;
    }
}

通过查看@RefreshScope 的注解发现,其底层是重新创建了实例,并进行了依赖注入。

/**
 * 添加了@RefreshScope的Bean 可以在运行时刷新
 * 任何使用它们的组件都将在下一次方法调用时获得一个新实例,完全初始化并注入所有依赖项。
 * @author Dave Syer
 */
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {
   ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}

使用@Autowire 注解进行注入

@Value 可以进行简单值的属性注入,如果我们想要在 Bean 中注入一个对象,往往使用@Autowire 注解进行注入。针对这种注入方式,我们可以使用@ConfigurationProperties 注解进行配置读取。


我们仍然以myconfig.msg配置为例,使用@ConfigurationProperties 进行配置读取。​ 首先,编写一个 Java Bean:

@Data
@Component
@ConfigurationProperties(prefix = "myconfig")
public class UserNacosConfig {
    private String msg;
    private String chapter;
}

在编写 JavaBean 时,@ConfigurationProperties 注解的 prefix 属性和 Nacos 中配置的属性前缀保持一致,成员变量的名字和 Nacos 中配置的属性的 Key 保持一致。 Nacos 中配置我们修改如下:

w:35em

修改完 Nacos 中配置之后,一定要记得点击发布按钮进行发布。


最后修改 NacosConfigTestController,注入我们编写的 JavaBean:

@Slf4j
@RestController
@RequestMapping("/config")
@RefreshScope
public class NacosConfigTestController {
    @Value("${myconfig.msg}")
    private String msg;

    @Autowired
    private UserNacosConfig userNacosConfig;

    @RequestMapping("/msg")
    public String getMsg() {
        return this.msg;
    }

    @RequestMapping("/message")
    public String getMessage() {
        return userNacosConfig.getMsg() + userNacosConfig.getChapter();
    }
}

重启 userservice 应用,访问:http://localhost:8081/config/message ,结果如图所示:

image-20220801112128380

此时是因为我们重启了服务,所以能够读取到最新的配置,这是可以预知的结果。


现在,我们继续修改配置,而不重启服务,观察是否能够得到最新的配置内容。

最新配置更改如下:

w:35em


点击发布之后,我们不用重启 userservice 服务,直接再次访问:http://localhost:8081/config/message , 结果如图所示:

w:35em

可以看到,我们已经可以实现配置的热更新。


加载指定的 Nacos 配置

配置默认的 GroupID 为 DEFAULT_GROUP, 也可以创建自定义的 GroupID, 但是在加载配置时,需要指定 GroupID。


在 Nacos 配置中心, 创建配置如下:

w:24em


pom.xml 加入依赖

  
    com.alibaba.boot
    nacos-config-spring-boot-starter
    0.2.12
  

启动类加入注解

// 读取 Nacos 配置中心
@NacosPropertySource(dataId = "retryTimes", groupId = "RiskModule",autoRefreshed = true)
@MapperScan("com.niit.user.mapper")
@SpringBootApplication
public class UserApplication {...}

使用时通过@NacosValue 注解进行注入

    @NacosValue(value = "${readRetryTimes}", autoRefreshed = true)
    private String readRetryTimes;
    @NacosValue(value = "${writeRetryTimes}", autoRefreshed = true)
    private String writeRetryTimes;

此外, 也可以通过 Nacos 的 API 进行配置的设置和读取

发布配置
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"

获取配置
curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"


注意:

  1. 不是所有的配置都适合放到配置中心,维护起来比较麻烦。
  2. 建议将一些关键参数,需要在运行时进行调整的参数放到 Nacos 配置中心,这些参数一般都是自定义配置信息。

多环境配置

微服务系统中, 及存在共通的配置比如应用的名称。而有些配置在不同的环境下,比如开发环境和生产环境下的微服务的配置是不尽相同的, 比如端口号, 数据库的链接,Nacos 的地址。

此时,我们想尽量减少重复性工作,提升开发和维护的效率,那就需要将这些跨环境的那些相同配置提取出来。我们将共同配置提取到一个地方,就可以做到只用设置一次, 所有环境(比如开发.测试以及生产环境)都会读取该配置,这样就达到了配置共享的目的。


配置读取

在微服务启动的时候,会去 Nacos 中读取多个配置:

  • bootstrap.yml 启动配置:
    会优先加载,用于加载一些系统级别的配置,比如连接到配置中心的配置。
  • ${spring.application.name}.yaml
    例如 userservice.yaml。无论微服务的环境是开发环境也好, 是生产环境也好,${spring.application.name}.yaml这个配置文件都会userservice加载。

在 Nacos 中添加共享配置

我们在 nacos 中添加一个 userservice.yaml 文件:

w:22em

注意: 命名规则是 ${spring.application.name}.yaml ,该共享配置与环境无关。


读取新增配置

userservice 服务中,修改配置类,读取新增的author属性:

@Data
@Component
@ConfigurationProperties(prefix = "myconfig")
public class UserNacosConfig {
    private String chapter;
    private String msg;
    private String author;
}

新增一个控制器方法,以便于进行测试验证:

@Slf4j
@RestController
@RequestMapping("/config")
@RefreshScope
public class NacosConfigTestController {

    @Autowired
    private UserNacosConfig userNacosConfig;
    ...
    @RequestMapping("/author")
    public String getAuthor() {
        return userNacosConfig.getAuthor();
    }
}

多环境测试

使用 dev 环境启动一个 userservice 实例,端口号 8081,再用 test 环境启动另一个 userservice 实例,端口号 8082,然后我们分别访问: http://localhost:8081/config/authorhttp://localhost:8082/config/author:


结果如图所示:

w:28em


我们知道,在 bootstrap.yml 文件中指定了应用读取 Nacos 中的 userservice-dev.yaml 文件,并且 Nacos 中并没有 userservice-test.yaml 配置文件,但是我们访问 8082 端口的 userservice 时,仍然能够读取myconfig.author的值,这说明userservice.yaml文件确实是多环境共享的一个配置文件。


配置优先级

我们现在考虑一个问题,如果多个配置文件中都对某个属性进行了定义,那么微服务究竟应该读取那个配置来使用呢?我们不妨来做一个小小的测验。

在每一个配置文件中都定义一个相同的属性,比如myconfig.bookName属性,如下所示:

  • userservice-dev.yaml 中,bookName 的值是 Spring Cloud Dev
  • userservice.yaml 中,bookName 的值是 Spring Cloud Default
  • 在本地 application-dev.yaml 中,bookName 的值是 Spring Cloud Local。

修改配置类,读取 bookName 属性:

@Data
@Component
@ConfigurationProperties(prefix = "myconfig")
public class UserNacosConfig {
    private String chapter;
    private String msg;
    private String author;
    private String bookName;
}

新增控制器方法,读取myconfig.bookName属性的值:

@Slf4j
@RestController
@RequestMapping("/config")
@RefreshScope
public class NacosConfigTestController {
    @Autowired
    private UserNacosConfig userNacosConfig;
    ...
    @RequestMapping("/bookName")
    public String getBookName() {
        return userNacosConfig.getBookName();
    }
}

在 dev 环境下,重启 userservice,端口号 8081,现在我们访问: http://localhost:8081/config/bookName ,结果如图所示:

w:32em


这说明,Nacos 线上配置的带有环境变量的配置文件的优先级是最高的。那么线上的共享配置和本地配置,哪个优先级更高呢?我们暂时删除 Nacos 线上配置的带有环境变量的配置文件中的属性,重新访问: http://localhost:8081/config/bookName ,结果如图所示:

image-20220801174120879


通过这个小小的测验,对于配置优先级问题,我们总结出如下规律:

  • 线上配置优先于本地配置
  • 线上自定义环境配置优先于线上共享配置

bg right fit


这样的优先级规律,也恰恰符合配置中心的设计原则,即线上可配置优先于本地预配置,自定义个性化配置优先于多环境共享配置。详见 Nacos-config 参考文档


搭建 Nacos 高可用集群


在之前的内容中,我们已经学习了 Nacos 的基本用法。不过我们一直是使用的 nacos 单节点服务,Nacos 单节点模式只适用于线下环境,在企业的生产环境中,我们是不能使用 Nacos 单节点进行业务架构部署的。


单节点对于高可用设计来说是远远不够的,因为单节点一旦出先故障,那么所有依赖于该节点的其他微服务,都会出现问题,这样会导致整个业务系统的大崩溃。所以,我们接下来就开始学习如何搭建 Nacos 集群,构建一个高可用的服务治理体系。


Nacos 集群

一个 Nacos 集群,至少要有三个节点。下方是 Spring Cloud Alibaba Nacos 官方给出的最简易的 Nacos 集群架构图:


image-20220802110040457

其中包含 3 个 nacos 节点,然后一个负载均衡器代理 3 个 Nacos。这里负载均衡器可以使用 nginx。接下来,我们以 windows 系统为例,搭建一个最简单的 Nacos 集群进行学习。


注意:

在实际生产环境中,需要给做反向代理的 nginx 服务器设置一个域名,这样后续如果有服务器迁移,nacos 的客户端也无需更改配置。Nacos 的各个节点应该部署到多个不同服务器,做好容灾和隔离。Mysql 应该搭建一个主从高可用的集群。 本案例以单机 windows 系统为例,模拟三个 Nacos 节点,并且使用单机的 Mysql8.0 以上的版本进行集群搭建的演示。


Nacos 集群搭建步骤如下:

  1. 搭建数据库,初始化数据库表结构
  2. 下载 nacos 安装包
  3. 配置 nacos 节点
  4. 启动 nacos 集群
  5. nginx 反向代理
  6. 修改微服务 Nacos 地址

初始化数据库

Nacos 默认数据存储在内嵌数据库 Derby 中,不属于生产可用的数据库。官方推荐的最佳实践是使用带有主从的高可用数据库集群。这里我们以单点的数据库为例来演示。首先新建一个数据库,命名为 nacos,而后导入 Nacos 的 MySQL 数据库的初始化 SQL 文件.


使用 Nacos 项目官方提供的初始化 sql 文件进行初始化操作, 具体位置在 conf 目录下的mysql-schema.sql文件


h:13em

Nacos 的 MySQL 初始化脚本在线地址
https://github.com/alibaba/nacos/tree/develop/config/src/main/resources/META-INF


在本地 Mysql 中执行成功后,nacos 数据库中将会出现下面的表:

image-20220802111857744


下载 Nacos 安装包

本知识点在本书第三章节已经介绍过,不再赘述,我们以 nacos2.1.0 版本为例,进行搭建。

image-20220802112128986


配置 Nacos 节点

我们在本地 windows 系统上配置三个 Nacos 节点,各个节点的 IP 和端口如下表所示:

节点 IP port
nacos1 127.0.0.1 8858
nacos2 127.0.0.1 8868
nacos3 127.0.0.1 8878

注意: 本地 windows 系统上,如果端口被占用,可以修改端口号,但是要保证三个节点的端口号不一样, 且不要相邻(容易冲突)。


我们先配置好一个 nacos 节点,然后再复制成三个节点。

下面以一个节点操作为例:


1.解压缩

将下载的安装包,解压缩至一个没有中文目录的文件夹,命名为 nacos1,解压完成之后,Nacos 目录如图所示:

image-20220802114728043


-目录说明:

  • bin:启动脚本
  • conf:配置文件

2.修改配置

进入 nacos 的 conf 目录,修改配置文件 cluster.conf.example,重命名为 cluster.conf:

image-20220802114924887


编辑此文件,添加 nacos 集群配置:

192.168.65.1:8858
192.168.65.1:8868
192.168.65.1:8878

192.168.65.1 为本机真实的 IP 地址
真实 ip 可以在启动单机版 nacos 后从日志提示中查看


然后修改 application.properties 文件,进行数据库配置:

image-20220802115229225


属性说明:

  • spring.datasource.platform=mysql: 指定数据库平台为 mysql,Nacos 目前只支持 Mysql。
  • db.num=1 : Mysql 的实例个数,本案例中为 1 个 Mysql 实例。
  • db.url.0: 数据库链接信息,本案例中我们使用的是 Mysql8.0 以上的版本,并且创建了 nacos 数据库,所以链接如上所示。
  • db.user.0: 数据库用户名
  • db.password.0: 数据库密码

接着修改应用的端口号,第一个节点是: 8858,如下图所示:

server.port=8858

3.复制节点

修改完上述配置并保存后,我们将该节点复制两份,命名为 nacos2 和 nacos3,并将 nacos1的端口修改为8858, nacos2 的端口修改为 8868,将 nacos3 的端口修改为 8878。完成之后,nacos 三个节点的集群整体如下所示:


启动 Nacos 集群

在每个 Nacos 节点的 bin 目录下,使用 cmd 命令窗口执行: startup.cmd。 Nacos 的该命令,默认就是以集群方式进行启动。启动成功,最后会打印出日志信息:

image-20220802150700225


Nginx 反向代理

经过以上步骤,我们已经成功搭建好具有三个节点的 Nacos 集群,现在我们使用 Nginx 给该集群配置负载均衡和反向代理。


1.下载 Nginx

下载 Nginx,下载地址:https://nginx.org/en/download.html 我们选择最新的稳定版本。

h:12em


2.解压缩

将安装包解压缩到任意的非中文目录下:

image-20220802153243148


3.添加代理配置

修改 conf/nginx.conf 文件,将下面的配置放在配置文件的 http 节点之内:

upstream nacos-cluster {
  server 127.0.0.1:8858;
    server 127.0.0.1:8868;
    server 127.0.0.1:8878;
}

server {
    listen       8848;
    server_name  localhost;

    location /nacos {
        proxy_pass http://nacos-cluster;
    }
}

该代理配置监听 8848 端口,虚拟路径为nacos


4.启动 Nginx

修改完配置并保存之后,回到 Nginx 的安装目录,双击nginx.exe即可启动。此时,我们可以访问: http://localhost/nacos

bg right fit


通过固定访问方式 http://localhost:8848/nacos 访问集群管理 - 节点列表, 如果看到集群中的三个节点都已经启动成功, 且为 UP 状态, 则说明 Nginx 反向代理配置成功。


微服务配置 Nacos 地址

由于我们现在已经搭建了 Nacos 集群,并且使用 Nginx 做了负载均衡和反向代理,所以各个微服务之前配置的 Nacos 地址肯定无法再使用,微服务中的 Nacos 地址配置要与 Nginx 中保持一致。

以 userservice 服务为例,修改其 bootstrap.yaml 文件即可:


spring:
  application:
    name: userservice
  profiles:
    active: dev #环境
  cloud:
    nacos:
      server-addr: localhost:8848 #nacos集群的NGINX反向代理地址
      config:
        file-extension: yaml #配置文件后缀名

现在我们启动三个 userservice 服务的实例进行测试,启动成功之后,我们可以在 Nacos 控制台看到如下信息:
image-20240320190015616

当我们搭建完成 Nacos 集群之后,在使用的时候几乎完全和我们之前所学的单节点 Nacos 的使用方法一致。


活动 8.1:

Nacos 配置中心使用


练习问题


  1. 当使用@Value 注解进行属性注入时,在需要的类上加上什么注解可以实现动态刷新配置。 ()
    a. @Service
    b. @Component
    c. @RestController
    d. @RefreshScope

    查看答案

    正确答案: d


  1. Nacos 配置中心的 artifactId 是下列的哪一个? ()
    a. spring-cloud-starter-alibaba-nacos-config
    b. spring-cloud-starter-alibaba-nacos-discovery
    c. spring-cloud-starter-Netflix-nacos-config
    d. spring-cloud-starter-alibaba-config-config

    查看答案

    正确答案: a


  1. 下列配置文件,哪个是 userservice 服务的多环境共享配置? ()
    a.userservice-dev.yaml
    b.application-dev.yaml
    c.userservice.yaml
    d.userservice-common.yaml

    查看答案

    正确答案: c


  1. 搭建 Nacos 集群,最少需要几个 Nacos 实例节点?
    a. 1
    b. 2
    c. 3
    d. 4

    查看答案

    正确答案: c


小结

在本章中,您学习了:

  • Nacos 配置中心快速入门

  • 配置热更新

    • 使用@Value 注解进行注入
    • 使用@Autowire 注解进行注入
  • 多环境配置共享

    • 配置优先级
  • 搭建 Nacos 集群

    • 初始化数据库
    • 配置 Nacos 节点
    • 启动 Nacos 集群
    • Nginx 反向代理

Views: 11

SpringCloud与微服务-第3章-服务治理(Nacos/Eureka)

第 3 章 - 服务治理


服务治理可以说是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册与发现。为什么我们在微服务架构中那么需要服务治理模块呢?


在最初开始构建微服务系统的时候可能服务并不多,我们可以通过做一些静态配置来完成服务的调用。比如,有两个服务 A 和 B,其中服务 A 需要调用服务 B 来完成一个业务操作时,为了实现服务 B 的高可用,不论采用服务端负载均衡还是客户端负载均衡,都需要手工维护服务 B 的具体实例清单。


但是随着业务的发展,系统功能越来越复杂,相应的微服务应用也不断增加,我们的静态配置就会变得越来越难以维护。并且面对不断发展的业务,我们的集群规模、服务的位置、服务的命名等都有可能发生变化,如果还是通过手工维护的方式,那么极易发生错误或是命名冲突等问题。同时,对于这类静态内容的维护也必将消耗大量的人力。


为了解决微服务架构中的服务实例维护问题,产生了大量的服务治理框架和产品。这些框架和产品的实现都围绕着服务注册与服务发现机制来完成对微服务应用实例的自动化管理。

目标:


在本章中,您将学习:

  • 构建服务注册中心
  • 服务注册与服务发现

常见方案

Netflix Eureka

Spring Cloud Eureka,它既包含了服务端组件,也包含了客户端组件,并且服务端与客户端均采用 Java 编写,所以 Eureka 主要适用于通过 Java 实现的分布式系统,或是与 JVM 兼容语言构建的系统。但是,由于 Eureka 服务端的服务治理机制提供了完备的 RESTful API,所以它也支持将非 Java 语言构建的微服务应用纳入 Eureka 的服务治理体系中来。


zookeeper

ZooKeeper 是一个开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 Hbase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。ZooKeeper 的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。


Consult

Consul 是一个服务网格(微服务间的 TCP/IP,负责服务之间的网络调用、限流、熔断和监控)解决方案,它是一个分布式的,高度可用的系统,而且开发使用都很简便。它提供了一个功能齐全的控制平面,主要特点是:服务发现、健康检查、键值存储、安全服务通信、多数据中心。


Spring Cloud Alibaba Nacos

Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。


方案对比

服务治理的方案不一而论,现将主流的技术框架进行横向比对:


bg fit


从上面的对比可以知道,Nacos 作为服务发现中心具备更多的功能支持,且从长远来看 Nacos 在以后的版本会支持 SpringCloud+K8s 的组合,填补两者的鸿沟,在两套体系下可以采用同一套服务发现和配置管理的解决方案,这将大大的简化使用和维护成本.本节课程将以 Nacos 为例,讲解服务治理的相关概念.


服务治理

在服务治理框架中,通常都会构建一个注册中心,每个服务单元向注册中心登记自己提供的服务,将主机与端口号、版本号、通信协议等一些附加信息告知注册中心,注册中心按服务名分类组织服务清单。


搭建 Nacos 服务

Nacos 的安装和使用都非常简单.下面我们就在 Windows 系统上搭建一个 Nacos 服务吧.


1.下载安装包

在 Nacos 的 GitHub 页面,提供有下载链接,可以下载编译好的 Nacos 服务端或者源代码:

GitHub 主页:https://github.com/alibaba/nacos

GitHub 的 Release 下载页:https://github.com/alibaba/nacos/releases


如图所示: Windows 系统下载对应的 zip 压缩包即可.

image-20220715095333038


2.解压

将 nacos-server-2.1.0.zip 解压到任意非中文目录,此处将其解压到 D 盘的 develop 目录下:

image-20220715104229949


目录说明:

  • bin:启动脚本
  • conf:配置文件

3.修改端口

Nacos 的默认端口是 8848,如果你电脑上的其它进程占用了 8848 端口,请先尝试关闭该进程。如果无法关闭占用 8848 端口的进程,也可以进入 nacos 的 conf 目录,修改配置文件中的端口:


image-20220715104440506


修改其中的内容:

image-20220715104601567


4.启动

启动非常简单,进入 bin 目录,结构如下:

image-20220715104737161


然后执行命令即可:

当前目录下,打开 cmd 黑窗口,执行 windows 命令:

startup.cmd -m standalone

(以单实例本机启动)。

也可以打开 startup.cmd, 修改
set MODE="clusterset MODE="standalone",然后执行startup.cmd


启动成功界面如下:

image-20220715105459284


5.访问

在浏览器中访问 Console 给出的 URL: http://192.168.1.4:8848/nacos/index.html ,Nacos 默认的账号密码都是 nacos 。


image-20220715105806185


登录成功:

image-20220715105710888


本章节,我们通过两个简单的微服务模块来了解 Nacos 是如何进行服务注册和发现.

  • 服务提供者
  • 服务消费者

注册服务提供者

现在我们已经成功构建了两个微服务业务模块,接下来我们尝试将这两个业务模块加入 Nacos 的服务治理体系中去.服务之间通过 HTTP 协议进行通信,所以当我们使用 Nacos 进行管理的时候,Nacos 也需要知道相关的信息,比如 IP,端口号等。


1. 添加依赖

由于 Spring Cloud Alibaba 是新加入 Spring Cloud 的组件,所以没有在 spring-cloud-dependencies 里面,我们需要在项目的父工程 pom.xml 文件中加入如下依赖管理:


    com.alibaba.cloud
    spring-cloud-alibaba-dependencies
    2.2.5.RELEASE
    pom
    import

2. 添加 Nacos 的客户端依赖

在上一节,我们已经搭建了 Nacos 服务,而想将我们的应用注册到 Nacos 中,我们还需要在模块中添加 Nacos 的客户端依赖。现在将依赖添加到其中一个模块的 pom.xml 文件中:



    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-discovery

3. 添加 Nacos 地址

引入以上依赖之后,我们就可以在 application.yml 文件中配置相关信息,将服务注册到 Nacos 中。

在服务治理框架中,通常都会构建一个注册中心,每个服务单元向注册中心登记自己提供的服务,将主机与端口号、版本号、通信协议等一些附加信息告知注册中心,注册中心按服务名分类组织服务清单。


所以我们需要配置本服务的服务名以及 nacos 的服务端地址信息,如下:

spring:
  application:
    name: orderservice #注册到注册中心的服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 #nacos 服务端地址

4. 启动测试

重启当前应用,观察 nacos 控制台服务管理下的服务列表菜单,注册成功则会将该应用实例显示在列表中。


bg fit


按照以上步骤,我们可以将另一个服务也注册到 Nacos 中,注册成功后,可以在 Nacos 中看到两条服务信息.


bg fit


服务发现与消费

通过上面的内容介绍与实践,己经搭建起了微服务架构中的核心组件——服务注册中心。同时,还对两个业务模块做了改造。通过简单的配置,使该程序注册到 Nacos 注册中心上,成为该服务治理体系下的服务。

现在我们己经有了服务注册中心和服务提供者,服务消费者,下面就来尝试让服务消费者完成两个目标,发现服务以及消费服务。我们通过构建一个简单的示例,看看在 Nacos 的服务治理体系下如何实现服务的发现与消费。


1.添加@LoadBalanced 注解

在没有将服务交由 Nacos 管理之前,我们通过简单的 RestTemplate 对象的方法即可模拟 HTTP 请求,而现在我们将使用服务名代替传统的 IP+端口号的这种 URL,并且实现简单的负载均衡(负载均衡的内容我们将在之后的章节详细介绍).


在声明 RestTemplate 的地方添加注解:

/**
     * 在容器中注册 RestTemplate 方便项目内调用
     * @return
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

2.使用服务名

在发送请求的时候,使用服务名替换掉原 IP+端口。服务消费方 Controller 关键代码如下所示:


@RestController
@RequestMapping("order")
public class OrderController {
   @Autowired
   private OrderService orderService;
   @Autowired
   private RestTemplate restTemplate;
    @GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
        // 根据id查询订单并返回
        Order order = orderService.queryOrderById(orderId);
        //通过RestTemplate查询用户信息 使用服务名代替ip和端口号
        String url = "http://userservice/user/"+order.getUserId();
        User forObject = restTemplate.getForObject(url, User.class);
        //封装返回的数据
        order.setUser(forObject);
        return order;
    }
}

3.测试

当以上步骤完成之后,我们就构建了一个简单但完整的
服务消费方->注册中心->服务提供方
的这样一个简单体系。当我们使用浏览器访问一个服务的时候,该服务内部如何去调用其他服务能力接口的整个过程我们是感知不到的。所以我们像以前一样正常访问即可.


如果测试通过,我们将得到包含两个模块数据的结果集,如下所示案例:

image-20220715163624909


如果希望查询到的 User 实例包含配置文件中的端口信息, 可以这样修改 userservcie 模块 中的 UserController 类:

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {
        User user = userService.queryById(id);
        user.setServerPort(serverPort);
        return user;
    }
}

4.如何启动多个服务提供方

在上面的案例中,我们只启动了一个服务提供方,如果我们想要启动多个服务提供方,并且让服务消费方能够负载均衡的访问到这些服务提供方,那么我们需要做一些额外的配置.


  1. 首先修改运行配置, 开启允许并行运行

bg auto


  1. 准备多个配置文件,并且修改端口号使其各互不冲突, 然后修改运行配置的 active profile 为不同的配置方案, 启动多个服务:

bg cover


  1. 也可以
    直接修改运行配置中的 VM options,添加 -Dserver.port=XXXX,
    其中 XXXX 为不同的端口号, 分别启动多个服务.

bg cover


  1. 找到现有的运行配置服务, 选择复制配置后修改配置文件或者端口设置, 通过不同的运行配置来启动多个服务.

h:14em


  1. 当同时运行 2 个或者多个 springboot 服务时, 可以alt+8打开服务列表, 添加 SpringBoot 的配置类型, 可以方便的统一管理多个服务.


  1. 在 Nacos 运行的运行的情况下可以查看到服务列表, 包括服务的名称, 实例数量, 以及服务的运行状态.
    h:17em

Q: Nacos 服务注册中心的作用是什么?

A: 服务注册中心是一个服务的注册表, 用于存储服务提供方的信息, 以便服务消费方能够找到服务提供方, 从而实现服务的调用.


w:28em


搭建 Eureka 服务

pom.xml



    org.springframework.cloud
    spring-cloud-starter-netflix-eureka-server

application.yml

server:
  port: 10086 # 服务端口
#将Eureka服务注册到Eureka注册中心上,方便以后做集群管理
spring:
  application:
    name: eurekaserver # eureka的服务名称
eureka:
  client:
    service-url: # eureka的地址信息, 如果搭建Eureka集群则需要配置多个地址, 以逗号分隔, 交叉注册
      defaultZone: http://127.0.0.1:10086/eureka

运行 Eureka 服务, 查看可视化界面

h:16em


启用 Eureka 客户端

user 和 order 模块:

@MapperScan("com.niit.user.mapper")
@SpringBootApplication
@EnableEurekaClient  // for uereka
public class MainApplication {
...
}

application.yml

# Eureka 的地址信息
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

Q: Nacos 的服务注册中心和 Eureka 的服务注册中心有什么区别?

A: Nacos 的服务注册中心和 Eureka 的服务注册中心都是用于存储服务提供方的信息, 但是 Nacos 的服务注册中心是一个更加完善的服务注册中心, 它不仅仅是一个服务注册中心, 还是一个配置中心, 服务发现中心, 以及服务管理中心.


活动 3.1

使用 Nacos 实现服务调用


练习问题

  1. 下面哪个选项不是常见的服务治理方案?
    a. Netflix Eureka
    b. Zookeeper
    c. Spring Cloud Alibaba Nacos
    d. Spring Boot Application

    答案

    d


  1. 我们在使用 Spring Cloud Alibaba Nacos 作为注册中心,可以在发送请求的时候,使用服务名替换掉原 IP+端口。
    a. 错误
    b. 正确

    答案

    b


  1. 下面哪条命令是在本机以单实例启动 Nacos 服务?
    a. startup.cmd -m standalone
    b. startup.cmd -f standalone
    c. startup.exe -m standalone
    d. startup.cmd

    答案

    a


  1. 下面哪个是 Nacos 注册中心的客户端依赖?
    a. spring-cloud-starter-alibaba-nacos-config
    b. spring-cloud-starter-alibaba-nacos-discovery
    c. spring-cloud-alibaba-starter-nacos-discovery
    d. spring-cloud-alibaba-nacos-starter-discovery

    答案

    b


小结

在本章中,您学习了:

  • 服务治理的常见方案
  • 搭建 Nacos 服务
    • 注册服务提供者
    • 服务发现与消费

Views: 5