2 Nacos服务注册与发现

课程视频:https://www.bilibili.com/video/BV1VW4y1o7n5 本课程使用的是目前最新版本2022.0.0.0-RC2。基于Spring Boot 3.0与JDK20的开发环境。

2.1 概述

2.1.1 注册中心简介

所有提供者将自己提供服务的名称及自己主机详情(IP、端口、版本等)写入到另一台主机中的一个列表中,这台主机称为服务注册中心,而这个表称为服务注册表。 所有消费者需要调用微服务时,其会从注册中心首先将服务注册表下载到本地,然后根据消费者本地设置好的负载均衡策略选择一个服务提供者进行调用。这个过程称为服务发现。 可以充当Spring Cloud服务注册中心的服务器很多,如Zookeeper、Eureka、Consul等。Spring Cloud Alibaba中使用的注册中心为Alibaba的中间件Nacos。

2.1.2 Nacos简介

Nacos简介在其官网[https://nacos.io/](https://nacos.io/) 中描述的很详细。
云原生应用简单来说就是SaaS,就是跑在IaaS、PaaS上的SaaS。
云原生 = 微服务 + DevOps + CD + 容器化

2.2 Nacos下载与启动

2.2.1 下载

从官网页面可以看出,有两种资源下载方式:源码下载与打过包的工程下载。点击“最新稳定版本”,可以选择性地下载最新版的这两种资源。这里选择编译过的zip压缩资源。

2.2.2 安装与配置

2.2.2.1 配置端口号
解压压缩包。在压缩包的conf目录中,找到application.properties文件。

从配置文件可以看出,默认Nacos服务器的端口号为8848,上下文路径为/nacos。一般都是采用默认值,但也可以修改。

2.2.2.2 配置鉴权

从nacos2.2.0.1版本开始,nacos配置文件中去掉了默认的鉴权配置,需要用户手工添加,否则无法启动nacos。

2.2.2.3 启动

在nacos/bin目录中有启动命令文件。其中cmd是Windows系统中的命令,sh是Linux系统中的命令。 由于其默认是集群方式启动,所以若要单机启动,则需要在cmd中通过命令启动。

2.2.3 访问控制台

2.2.3.1 登录

在浏览器地址栏通过http://localhost:8848/nacos/index.html可打开Nacos控制台的登录页面。 默认账号/密码为nacos/nacos。不过,该默认账号与密码存放在nacos内置mysql数据库中的,而非存放在某配置文件中。若要添加账号或修改密码,可在登录后通过页面修改。 输入账号/密码后即可看到如下界面,说明nacos server已经启动成功了。

2.2.3.2 修改登录信息
在该页面中可以添加、删除普通用户,修改所有用户的密码。但不能删除管理员用户,也不能将普通用户指定为管理员角色。

2.3 定义提供者02-provider-nacos-8081

2.3.1 定义工程

复制01-provider-8081工程,并重命名为02-provider-nacos-8081。

2.3.2 添加spring cloud依赖管理

当前的工程首先是个Spring Cloud工程,所以需要在pom文件中添加Spring Cloud依赖管理模块。

| <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2022.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies>

</dependencyManagement>

2.3.3 添加alibaba依赖管理

还需要添加上spring cloud alibaba的依赖。

| <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2022.0.0.0-RC1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies>

</dependencyManagement>

2.3.4 添加nacos-discovery依赖

在<dependencies>标签下添加Nacos Discovery依赖。

| <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>

</dependency>

2.3.5 pom内容

修改后的pom文件依赖如下:

| <properties> <java.version>19</java.version> </properties>

<dependencies>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.8</version>
    </dependency>
    _<!--修改MySQL驱动版本-->
    _<dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2022.0.0.0-RC1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2022.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>
</project>

2.3.6 修改配置文件

添加如下配置,指定nacos server的地址及微服务名称。

2.3.7 查看nacos控制台

启动该工程后,在浏览器中直接访问该提供者是没有问题的,说明该提供者已经启动。

在nacos server已经启动的情况下,查看nacos控制台,就可以看到该提供者。说明该微服务已经被nacos发现。

2.4 定义消费者02-consumer-nacos-8080

2.4.1 定义工程

复制01-consumer-8080工程,并重命名为02-consumer-nacos-8080。这个消费者是通过RestTemplate进行消费的。

2.4.2 修改pom

与定义provider时的相同,consumer的pom也做了如下几处的修改:

  • 添加spring cloud依赖管理
  • 添加spring cloud alibaba依赖管理
  • 添加nacos-discovery依赖
  • 添加spring-cloud-starter-loadbalance依赖

修改后的POM文件中的依赖情况如下:

| <properties> <java.version>19</java.version> </properties> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>

  <dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
     <optional>true</optional>
  </dependency>
  <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-test</artifactId>
     <scope>test</scope>
  </dependency>

</dependencies>

<dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2022.0.0.0-RC1</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2022.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build>

</project>

2.4.3 修改配置文件

2.4.4 修改控制器类

原来consumer中采用的是直连方式访问provider,现在要根据微服务名称来访问。

2.4.5 修改JavaConfig类

当使用微服务名称来访问provider时,其是通过负载均衡方式进行访问的。所以,需要添加如下注解。这里的负载均衡采用的是spring cloud自己开发的spring cloud loadbalancer。

2.4.6 查看ncos控制台

当启动consumer后,直接在浏览器访问consumer,可以看到正确的结果,说明consumer已经发现并调用到了provider。然后查看nacos控制台,也可以看到这两个服务。

2.5 获取服务列表

除了可以在Nacos控制台直观的查看到Nacos注册中心中注册的微服务信息外,也可以在代码中通过DiscoveryClient API获取服务列表。

2.5.1 修改controller

在任何微服务的提供者或消费者处理器中,只要获取到“服务发现Client”,即可读取到注册中心的微服务列表。本例直接修改02-provider-nacos-8081中的控制器类。

2.5.2 运行效果

启动02-provider-nacos-8081与02-consumer-nacos-8080两个工程。 在provider的控制台,可以看到如下的服务信息。

2.5.3 注册表缓存

服务在启动后,当发生调用时会自动从Nacos注册中心下载并缓存注册表到本地。所以,即使Nacos发生宕机,会发现消费者仍然是可以调用到提供者的。只不过此时已经不能再有服务进行注册了,服务中缓存的注册列表信息无法更新。

2.6 临时实例与持久实例

Nacos中的实例分为临时实例与持久实例。

2.6.1 配置

在服务注册时有一个属性ephemeral用于描述当前实例在注册时是否以临时实例出现。为true则为临时实例,默认值;为false则为持久实例。

2.6.2 区别

临时实例与持久实例的实例存储的位置与健康检测机制是不同的。

  • 临时实例:默认情况。服务实例仅会注册在Nacos内存,不会持久化到Nacos磁盘。其健康检测机制为Client模式,即Client主动向Server上报其健康状态。默认心跳间隔为5秒。在15秒内Server未收到Client心跳,则会将其标记为“不健康”状态;在30秒内若收到了Client心跳,则重新恢复“健康”状态,否则该实例将从Server端内存清除。
  • 持久实例:服务实例不仅会注册到Nacos内存,同时也会被持久化到Nacos磁盘。其健康检测机制为Server模式,即Server会主动去检测Client的健康状态,默认每20秒检测一次。健康检测失败后服务实例会被标记为“不健康”状态,但不会被清除,因为其是持久化在磁盘的。

2.7 将数据持久化到外置MySQL

默认情况下,Nacos使用的是内置storage,使用内置storage存在两个很大的问题:

  • 数据是存放在内存中的,无法持久化
  • 无法搭建集群。当Nacos作为配置中心时,要求必须是外置的DBMS

2.7.1 DBMS说明

Nacos对于DBMS的要求:

  • 安装数据库,版本要求:5.6.5+
  • 初始化mysql数据库,数据库初始化文件:mysql-schema.sql
  • 修改conf/application.properties文件,增加支持mysql数据源配置(目前只支持mysql),添加mysql数据源的url、用户名和密码。

2.7.2 修改SQL脚本文件

若要连接外置MySQL,则外置MySQL中就要有相应的数据库及表。这些表的创建脚本文件在Nacos解压目录的config子目录中的mysql-schema.sql。 打开mysql-schema.sql文件,发现其中只能表的创建语句,并没有数据库的创建语句,且文件中给出数据库的名称建议使用nacos_config。为了方便后面对这个脚本文件的执行,在该文件中添加如下的DB创建语句。

2.7.3 运行脚本文件

这里对于该脚本文件的运行,放在Idea中进行。在Idea的数据库连接上右击,选择SQL Scripts/Run SQL Scripts,在弹出的窗口中找到这个sql文件运行即可。

2.7.4 修改Nacos配置

打开Nacos安装目录下的conf/application.properties文件,把用于注释的#去掉。 变为以下内容:

2.7.5 修改Nacos平台登录账号

为了验证已经换为了外置MySQL,现在MySQL中添加一个新的nacos用户。

2.7.5.1 添加新用户

插入一个新的用户,用户名为hello,密码仍为nacos。当然,若要使用新密码,可以通过MD5工具加密后,将加密后的字符串放到这里。

2.7.5.2 重启Nacos后再登录

SQL执行成功后,将原来启动的Nacos服务器关闭后重新启动。 在启动日志中可以看到,已经使用外部存储设备了。 然后再次打开Nacos浏览器平台,登出原来的账号后,使用hello账号nacos密码再次登录,可以正常登录到平台,说明现在已经由内置MySQL成功转换到了外置MySQL了。

2.8 Nacos集群搭建

单机版Nacos都存在单点问题,所以需要搭建高可用的Nacos集群。

2.8.1 Nacos集群搭建

2.8.1.1 修改配置

这里要搭建的Nacos集群中包含三台Nacos服务器,由于这些Nacos都在同一台主机,所以这里创建的集群实际只有端口号不同,是个伪集群。 首先随意创建一个目录,用于存放三个Nacos服务器。例如在D盘创建一个nacos_cluster目录。然后再复制原来配置好的单机版的Nacos到这个目录,并重命名为nacos8847。将来要这里要存放三个子目录,分别为nacos8847、nacos8849、nacos8851。 打开nacos8847/conf,重命名其中的cluster.conf.example为cluster.conf。然后打开该文件,在其中写入三个nacos的ip:port。注意,不能写为localhost与127.0.0.1,且这三个端口号不能连续。否则会报地址被占用异常。 然后再打开nacos8847/conf/application.properties文件,修改端口号为8847。

2.8.1.2 复制目录
将nacos8847目录复制三份,分别命名为nacos8849、nacos8851。

并修改各自目录中conf/application.properties文件中nacos的端口号为8849与8851。

2.8.1.3 启动集群
逐个双击三个nacos目录中的bin/startup.cmd命令,逐个启动三台nacos。
从启动日志上可以看到其提供的SLB服务访问地址及三台Nacos节点地址。

2.8.1.4 查看nacos平台

在浏览器中使用SLB的VIP访问地址即可打开nacos服务器平台,查看到集群节点列表。点击“节点元数据”可查看nacos的节点元数据。

2.8.2 Client连接Nacos集群

直接将微服务配置文件application.yml中的nacos地址更换为Nacos集群的VIP地址。 微服务重启后便可以Nacos平台中查看到它们的信息了。

2.8.3 Nacos的CAP模式

默认情况下,Nacos Discovery集群的数据一致性采用的是AP模式。但其也支持CP模式,需要进行转换。若要转换为CP的,可以提交如下PUT请求,完成AP到CP的转换。 http://localhost:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP

2.9 服务隔离

2.9.1 数据模型

Nacos中的服务是由三元组唯一确定的:namespace、group与服务名称service。namespace与group的作用是相同的,用于划分不同的区域范围,隔离服务。不同的是,namespace的范围更大,不同的namespace中可以包含相同的group。不同的group中可以包含相同的service。namespace的默认值为public,group的默认值为DEFAULT_GROUP。

它们之间的关系就如官方给出的下图所示。

2.9.2 新建命名空间

新建一个命名空间hello,其会自动生成该命名空间的ID。

2.9.3 启动三个provider

启动三个02-provider-nacos-8081实例,它们提供的服务相同,不同的是namespace、group与port:

  • public + DEFAULT_GROUP + 8081
  • public + MY_GROUP + 8082
  • hello + MY_GROUP + 8083

2.9.4 查看Nacos服务列表

查看Nacos服务列表,在public命名空间中有两个服务,服务名称相同,但分组不同。 查看hello命名空间,其中也有一个服务,服务名称与public中的相同,但分组为MY_GROUP。

2.9.5 调用provider

修改02-consumer-nacos-8080的配置文件,指定nacos服务发现的group与namespace,就只会调用到指定范围中的服务。这就是namespace+group的服务隔离。