一、Nacos介绍

Nacos /na:kaus/是 Dynamic Naming and Configuration Service 的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

Nacos主要功能为以下两个:

  • 配置中心
  • 注册中心

1.1、配置中心和注册中心的概念

配置中心

是一种集中化管理配置的服务。

它的主要作用有以下几个:

  • 集中管理配置信息:配置中心将不同服务的配置信息集中放在一起进行管理,实现了配置信息的集中存储
  • 动态更新配置:配置中心中的配置信息可以通过操作界面或 API进行动态更新,无需重启服务就可以应用最新的配置信息。
  • 配置信息共享:将配置集中在配置中心中,不同的服务实例可以共享同一套配置信息。
  • 配置信息安全:配置中心可以对配置信息提供安全管理、权限控制等管理功能。
  • 信息追溯:支持配置版本管理、历史记录等管理功能。

注册中心

是微服务架构中的一个重要组件,用于实现服务的注册与发现。注册中心的主要作用包括以下几个:


  • 服务注册:服务实例启动时,将自身信息注册到注册中心,包括服务名称、地址、端口等
  • 服务发现:消费者向注册中心查询服务,并获取服务实例信息来访问服务
  • 服务健康检查:注册中心定期检查服务实例健康状况,过滤不健康实例。
  • 服务路由:提供服务的路由与负载均衡功能。
  • 服务监控: 统计服务调用次数,时长等,用于监控服务状态6.服务更新:当服务实例信息变更时,向注册中心发送更新信息通知。通过注册中心,服务提供者和消费者只需与注册中心交互即可,从而实现服务的注册与发现,降低了服务间的耦合度。

最重要的一点是:

通过注册中心,服务提供者和消费者只需与注册中心交互即可,从而实现服务的注册与发现,降低了服务间的耦合度。

1.2 Nacos 优点

  • 简单易用:经过几万人使用反馈优化,简单易用。
  • 特性丰富:阿里十年软负载在这个领域积累丰富特性,提供了丰富的特性。
  • 超高性能:苛刻场景要求极致性能。
  • 超大容量:经受了阿里规模经济的强大容量测试,可用于生产级别的超大型系统。
  • 高可用:双十一不能失败,造就了高可用能力。

二、Nacos的使用

2.1 以单机模式启动Nacos

首先,需要进入 Nacos 运行目录,及bin目录:

SpringCloud之Nacos入门与实战系列_Nacos


用命令行的方式,启动 Nacos 服务

Linux/MacOS: sh startup.sh -m standalone 启动 Nacos 单机模式;

Windows: startup.cmd -m standalone 启动 Nacos 单机模式。

效果如下:

SpringCloud之Nacos入门与实战系列_Feign_02


Nacos 单机模式默认使用的是内置的嵌入式数据库 Derby 作为数据存储的,但是 Derby 不适合承载生产环境大规模部署,因为它有以下限制:

数据存储容量最大只有 2GB;

不支持集群模式下数据的高可用复制:

性能和并发能力有限。

因此,在生产环境中使用单机模式时,可以使用外置数据库作为数据存储,比如 MySQL。

2.2 Nacos部署方式介绍

Nacos 有以下三种部署方式,了解为主:

  • 单机模式: 将注册中心、配置中心等功能集成在一个进程内,全部部署在一台机器上,适用于测试和单机试用。
  • 集群模式: 多个 Nacos 服务器实例组成一个集群。这些实例通过相互通信和协调工作,共同提供服务注册、配置管理和服务发现等功能。在集群模式下,所有的实例共享相同的数据,数据变更会自动同步到所有的实例中,客户端可以随机选择任意一个实例进行注册和发现服务。
  • 多集群模式: 多集群模式是为了满足在不同区域或网络中进行部署和扩展的需求。在多集群模式中,可以选择将不同的 Nacos 实例组成多个相互独立的集群,每个集群可以拥有自己独立的配置和注册中心,并可以跨集群进行服务注册和发现。多集群模式适用于分布式系统的多区域部署,并可以使用不同的网络和存储设施。每个集群具有独立的数据和配置,但可以通过自定义的同步机制在集群之间共享数据。

2.3 配置数据源

修改Naco安装目录中 conf/application.properties 文件可以自定义Nacos的配置:

SpringCloud之Nacos入门与实战系列_Feign_03

Nacos默认使用Derby数据库,但生产环境下Mysql的性能更好。

增加支持MySQL数据源配置,添加Mysql的URL,用户名和密码,配置如下:

#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.
spring.datasource.platform=mysql
# spring.sql.init.platform=mysql
 
### Count of DB:
db.num=1
 
### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=youpassword

然后先运行Nacos的初始化的sql文件。

SpringCloud之Nacos入门与实战系列_Nacos_04

最后重启Nacos服务即可生效

2.4 开启控制台权限登录

如果想要进入控制台界面,控制台的URL可在如下界面查看:

控制台界面如下所示:

SpringCloud之Nacos入门与实战系列_Spring cloud_05

就需要在配置文件中配置相应的数据。同样的,还是在刚刚的 conf/application.properties 文件中,修改以下配置:


### If turn on auth system:
nacos.core.auth.enabled=true
### Since 1.4.1, worked when nacos.core.auth.enabled=true and nacos.core.auth.enable.userAgentAuthWhite=false.
### The two properties is the white list for auth and used by identity the request from other server.
nacos.core.auth.server.identity.key=nacos
nacos.core.auth.server.identity.value=nacos
### The default token (Base64 String):
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey01234567890123456790123456789012345678901234567890123456789

基本都是在原有的配置项中设置即可,没设置之前,大多处于被注释或者是为空的状态:

三、配置中心的使用

3.1 创建配置信息

SpringCloud之Nacos入门与实战系列_Feign_06

SpringCloud之Nacos入门与实战系列_Spring cloud_07

参数说明:

  • 命名空间:Nacos 基于命名空间(Namespace)帮助用户逻辑隔离多个命名空间,这可以帮助用户更好的管理测试、预发、生产等多环境服务和配置,让每个环境的同一个配置(如数据库数据源)可以定义不同的值。默认是public
  • Data ID:配置的唯一标识,如果后端想要获取配置中心的信息,须在保证配置文件中的名称与其一致,后文会详细介绍。
  • Group:配置分组,用于设置小组信息,例如 DEV_GROUP 开发小组,TEST_GROUP 测试小组。

3.2 SpringBoot使用配置中心

SpringBoot项目使用配置中心,实现的步骤大致如下三种:

项目中添加 nacos-config 依赖。

在项目配置文件中设置Nacos相关信息。

使用@Value注解和@RefreshScope实现配置的读取和自动跟新。

在pom.xml中引入以下依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.6</version>
    </parent>
    <groupId>com.eclink.iot</groupId>
    <artifactId>eclink-iot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eclink-iot</name>
    <description>eclink-iot</description>
    <packaging>pom</packaging>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <modules>
        <module>producer</module>
        <module>consumer</module>
    </modules>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>2022.0.0.0</version>
        </dependency>

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


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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>

            </plugin>
        </plugins>
    </build>

</project>

在项目配置文件中添加以下信息;

spring.application.name=iot-gateway

# Nacos认证信息
spring.cloud.nacos.config.contextPath=/nacos
# 设置配置中心服务端地址
spring.cloud.nacos.config.server-addr=localhost:8848
# Nacos 配置中心的namespace。需要注意,如果使用 public 的 namcespace ,请不要填写这个值,直接留空即可
# spring.cloud.nacos.config.namespace=
# 逻辑隔离,设置分组的
#spring.cloud.nacos.config.group=
#这里填的应该是 nacos: ${配置中心的 data id}
spring.config.import=nacos:nacos-config-iot

需要注意的是,这里 spring.config,import的值需要与我们配置中心的Data ID 保持一致:

创建Controller层,读取配置文件.代码如下:


package com.example.demo;
 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
@RefreshScope //加了这个注解之后,@value注解才可以实时的获取配置中心的数据
public class TestController {
    @Value("${title}")
    private String config;
 
    @RequestMapping("/getconfig")
    public String getMyconfig() {
        return config;
    }
}


访问接口:


SpringCloud之Nacos入门与实战系列_Spring cloud_08


这里需要注意的是,如果配置中心存储的是yml文件的话:

需要手动指定file-extension为yml:

否则会造成获取配置文件失败, 因为观察注释可以发现,默认的是properties:

四、注册中心的使用

注册中心的交互流程:

SpringCloud之Nacos入门与实战系列_Feign_09

主要流程如下:


  • 启动注册中心:注册中心作为一个独立的服务,需要先启动起来。
  • 服务注册:当服务启动的时候,它会向注册中心发送一个注册请求,包含自己的元数据信息。Nacos服务器接收到注册请求后,在内存中维护一个注册表,将服务器的元数据保存起来,用于后续的服务发现。
  • 心跳机制:注册成功后,服务实例会定期向Nacos服务器发送心跳请求,以表明自己的健康状态和可用性。这样Nacos服务器可以监控各个服务实例的状态,并及时剔除不可用或下线的实例。
  • 服务发现:当服务消费者需要访问某个服务时,它会向 Nacos 服务器发送一个服务发现请求,包含所需服务的名称。Nacos 服务器根据服务名称查找注册表,并返回该服务的实例列表给消费者。
  • 负载均衡:在服务发现的过程中,Nacos 还提供了负载均衡的支持。消费者可以选择合适的负载均衡策略来选择其中一个或多个服务实例进行调用。

注册中心通常由两个角色:

  • 服务提供者(也叫生产者):对外提供服务的微服务应用,它会把自身的服务地址注册到注册中心,以提供消费者发现和调用。
  • 服务调用者(也叫消费者):调用其他微服务的应用程序,它会向注册中心订阅自己需要的服务,并基于服务提供者的信息发起远程调用。

4.1 多模块开发

由于我们接下来演示的生产者和消费者,需要使用多模块开发的模式,所以这里先进行介绍。

需要先创建一个父模块,并在父模块的pom.xml作出以下配置:

需要注意的是:这里的module的顺序是不能轻易改变的,因为这里需要现有生产者才能有消费者,消费者里面调用的服务是需要依赖生产者的。

SpringCloud之Nacos入门与实战系列_Spring cloud_10


4.2 生产者实现

生产者实现步骤总共有以下2步:


  • 配置nacos 服务器端信息
  • 编写调用接口


配置Nacos服务端信息


spring:
  application:
    name: nacos-discovery-demo # 注意这里填写的是服务名 (并且命名不要使用 下划线_)
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
        ephemeral: true # 设置为false 创建永久实例
server:
  port: 0 # 动态端口

编写调用接口:

这里通过注入ServletWebServerApplicationContext的方式获取动态端口:

package com.example.producer.controller;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
@RequestMapping("/user")
public class UserController {
    // 获取动态端口
    @Autowired
    private ServletWebServerApplicationContext context;
 
    @RequestMapping("/getnamebyid")
    public String getNameById(Integer id) {
        return "provider-name " + id +
                "server-port " + context.getWebServer().getPort();
    }
}

小插曲:解决设置永久实例(临时实例)报错解决方案:

SpringCloud之Nacos入门与实战系列_Spring cloud_11

停止Nacos服务,并且删除掉 Nacos文件夹下的 /data/protocol 目录后,最后重启Nacos即可:

启动之后,可在控制台中进行查看:

SpringCloud之Nacos入门与实战系列_Feign_12

访问接口,可以正常访问:

SpringCloud之Nacos入门与实战系列_Feign_13


4.3 消费者实现

注册中心中的消费者的实现比生产者要复杂一些,首先是消费者调用生产者的HTTP接口,其次引入 Spring Cloud OpenFeign 进行HTTP调用,其次为了实现负载均衡,我们还需要添加客户端负载均衡器 SpringCloudLoadBalancer。


Spring Cloud OpenFeign: Spring Cloud OpenFeign 是 Spring Cloud 生态系.统中的一个组件,它是基于 Netflix 的 Feign 库开发的,用于简化和优化微服务架构中的服务间通信。Spring Cloud OpenFeign 提供了一种声明式的方式来定义和调用 HTTP API,使得服务间的通信变得更加简单和直观。通过使用注解和接口定义,开发人员可以轻松地声明需要调用的远程服务的接口和方法,并且无需编写繁琐的 HTTP 请求代码。

Spring Cloud LoadBalancer:Spring Cloud 团队提供的一种客户端负载均衡甜。

负载均衡(Load Balancer):一种在多个服务实例之间分配负载和流量的技术,目的是提高服务的整体性能和可靠性。

消费者的实现步骤如下:


添加依赖(注册中心,Openfeign、SpringCloudBalancer)

配置Nacos服务端信息

在项目中开启Openfeign

编写Openfeign调用代码

编写代码通过Openfeign调用生产者

添加依赖:Nacos注册中心,Openfeign和SpringCloud LoadBalancer

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
            <version>4.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>4.0.2</version>
        </dependency>

配置Nacos服务端信息(yml文件)


spring:
  application:
    name: nacos-consumer-demo # 注意这里填写的是服务名 (并且命名不要使用 下划线_)
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
        register-enabled: false #由于是消费者,所以这里不进行注册到注册中心
server:
  port: 8080 # 作为消费者,那就需要设置一个固定的端口号,

项目中开启Openfeign


在SpringBoot启动类上添加 @EnableFeignClients 注解


package com.example.consumer;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
 
@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
 
}

在服务层通过Openfeign调用生产者的代码


package com.example.consumer.service;
 
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
 
@Service
@FeignClient("nacos-discovery-demo") // 表示调用 nacos 中的 nacos-discovery-demo 服务
public interface UserService {
 
    @RequestMapping("/user/getnamebyid") // 调用生产者中的 /user/getnamebyid 接口
    public String getNameById(@RequestParam("id") Integer id);
}

这里调用的接口是我们刚刚在生产者模块中写的:

在消费者中调用Openfeign接口代码

package com.example.consumer.controller;

import com.example.consumer.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class BusinessController {
    @Autowired
    private UserService userService;
    @RequestMapping("/getnamebyid")
    public String test(Integer id) {
        return userService.getNameById(id);
    }
}

这里我们为了实现负载均衡的效果,所以我们多创建一个生产者,以供消费者调用,步骤如下:

1.点击复制按钮,完成对我们生产者的复制:

点击完成按钮,即可实现对其的复制。


SpringCloud之Nacos入门与实战系列_Feign_14


现在我们将三个模块都运行起来:分别为消费者1,生产者1,生产者2:


SpringCloud之Nacos入门与实战系列_Feign_15


观察Nacos控制台,我们可以发现,我们的两个生产者已经成功注册到注册中心,并且运行正常。

SpringCloud之Nacos入门与实战系列_Feign_16

SpringCloud之Nacos入门与实战系列_Feign_17

访问接口,可以通过ctrl+r 进行对网页的刷新,这样可以实现手动轮询,让其访问我们刚刚生产者所产生的服务器端口。


SpringCloud之Nacos入门与实战系列_Spring cloud_18

SpringCloud之Nacos入门与实战系列_Feign_19

五、Nacos参数介绍

重要参数说明:


分组:注册服务所在的组名,默认是 DEFAULT GROUP,例如:研发小组,测试小组等

保护阈值:健康节点要求的最小百分比。用于在服务出现不健康实例时,阻止流量过度向少量健康实例集中保护服务的整体可用性。保护阈值应设置为一个0到1之间的浮点数,默认值为 0。当集群中的健康实例占比小于设置的保护阈值时,就会触发阈值保护功能。触发保护阈值后,Nacos 会将全部实例(健康实例+非健康实例)返回给调用者,虽然可能会损失一部分流量,但能保证集群中剩余的健康实例能正常工作。

服务路由类型:用于实现不同的路由需求,常见的路由类型有以下两种:                               1.none:  默认路由,基于权重的轮询负载均衡路由策略。                                                         2.label:  标签路由,相同标签的实例会被聚合为一个集群,不同标签则实现流量隔离。

临时实例:Nacos 中的实例分为临时实例和永久实例(也叫持久实例),临时实例的生命周期和服务的运行周期相同,服务停止运行 Nacos 中就会将临时实例删除;而永久示例即时程序终止,也会保留在 Nacos 中。在配置文件中通过:spring.cloud.nacos.discovery.ephemeral=true 设置。

权重: 用于实现负载均衡,取值范围0到 10000,数值越大,权重越大,负载均衡被分配的概率也就越高。设置为 0 的时候表示下线。

5.0 服务路由类型Label (可以实现CMDB:地域就近访问)

可以通过表达式的方式,让其实现地域就近访问,比如调用者为北京的一个ip,那么如果机房有两个,分别为北京和上海,那么就可以让这个北京的ip取访问北京的机房。

我们知道Nacos是有负载均衡策略的(不过默认不走Nacos的负载均衡,如果要走,需要手动配置),其主要依靠下面两者实现:

  • 权重
  • 地域就近访问

5.1 永久实例和临时实例的区别

永久实例和临时实例是注册中心的两种不同的服务类型。

永久实例(Persistent Instance):是指注册到 Nacos 的服务实例,其注册信息会一直保留在 Nacos 服务器上,直到主动注销或被删除。这意味着即使服务实例下线或不可用,它的注册信息仍然会保留在 Nacos 上,直到显式取消注册。永久实例适用于需要长期存在的服务,比如稳定部署的服务或长时间运行的后端服务。

临时实例(Ephemeral Instance):是指注册到 Nacos 的服务实例,其注册信息在实例下线或不可用时会自动被删除。如果服务实例下线、断开连接或主动注销,Nacos 会自动从注册表中删除这些实例的信息。临时实例适用于临时性的服务实例,比如临时加入集群的短期任务或特定场景下的临时服务。

临时实例和持久化实例的区别主要有以下两点:

临时实例在非健康状态下会被自动剔除,而永久实例不会被自动剔除。                                  临时实例超过 15 秒未收到心跳包,会将临时实例设置为不健康的状态。                              临时实例超过 30 秒未收到心跳包,会将临时实例删除。

临时实例的健康状况是 Nacos 客户端以固定频率(5s一次)上报给 Nacos 服务器端的,而永久实例是 Nacos服务器端主动探测的。

这里我们来演示一下临时实例和永久实例:首先我们需要将生产者这个模块的ephemeral设置为false。


由于我们这里设置生产者配置的是随机端口,所以只要我们后端服务终止运行,那么这个实例就会处于非健康状态:


5.2 演示保护阈值

这里我们将其保护阈值设置为0.8(因为这里触发了保护阈值):


并重启消费者模块,之后我们就可以发现,消费者访问的时候出现了轮询的策略,Nacos会将请求均匀的分配个即使不健康的端口,这虽然会造成消费者的访问失败,但是这也正是保护策略的意图,否则大量访问冲击到这个健康的实例,会造成最后这一个健康的实例瘫痪。


5.3 Nacos反向探测支持的协议(只对永久实例生效)

Nacos 健康检查服务器端反向探测支持的(协议)类型有以下两个:

  • HTTP 探测。
  • TCP 探测(默认协议)

它的具体执行流程如下。

① TCP 探测

默认情况下,永久实例使用的是 TCP 探测,这点可以在 Nacos 控制台观察到,如下图所示


TCP 探测的执行逻辑是通过与注册的永久实例建立连接(channel),不断 ping 注册实例的端口,来判断实例是否健康。有响应就表示目前是健康状态,无响应则表示非健康状态。

② HTTP 探测(大公司可能使用,因为HTTP会占到80端口,且还需要使用ping命令。)

HTTP 探测需要在 Nacos 控制台手动配置,如下图所示:

Nacos服务器通过检查HTTP的接口是否返回200状态码,来判断实例是否健康。

比如上图我们所设置的接口是 /user/hh,那么我们就必须在后台有这个接口的实现,并且这个接口可以正常相应200状态码,我们不需要关心这个接口具体实现细节。

如果失败,那么就显示false,成功则显示true:

探测规则


反向探测时间周期是 2000 亳秒 + 随机数(5000 毫秒以内),如果检测异常会将此服务实例,标记为非健康实例,但不会把服务实例像临时实例那样进行删除。


六、健康监测机制

Nacos 中的健康检测机制是用来检查服务健康状态的,只有健康的节点才会被服务消费端调用,这样才能保证程序稳定、正常的运行。

Nacos 中提供了两种健康检测的机制:


  • 客户端主动上报(健康状态的)机制。
  • 服务器端反向探测(健康状态的)机制。

健康检查机制应用

也就是说 Nacos 中的两种服务实例分别对应了两种健康检查机制:


临时实例(也可以叫做非持久化实例):对应的是客户端主动上报机制。

永久实例(也可以叫做持久化实例):服务端反向探测机制。

七、配置自动刷新原理

Nacos 配置中心是支持配置项自动刷新的,而其实现的原理是通过长轮询+事件驱动的方式来实现的具体来说:


客户端向 Nacos 服务器发送一个带有监听器(Listener)的请求,以获取某个特定配置的值。

Nacos 服务器接收到请求后,会检查该配置是否发生了变化。如果没有变化,则该请求将被阻塞直到超时或配置发生变化。

当配置发生变化时,Nacos 服务器会立即响应,并将新的配置值返回给客户端。

客户端接收到新的配置值后,可以根据需要更新自身的配置。

长轮询:服务器端接收到客户端的请求之后,如果没有数据更新,则连接保持一段时间,直到有数据或者超时才会返回。


Nacos使用长轮询(Long Polling)而不是长连接(WebSocket等)的主要原因是为了更好地适应不同网络环境和防火墙的限制。长轮询是一种通过保持连接打开一段时间并等待服务器推送数据的技术,它具有一些优势和适用于多种场景


八、RestTemplate+LoadBalancer调用Nacos(不推荐)

此方案的实现有以下 3 个关键步骤:

添加依赖:nacos + loadbalancer

设置配置文件

编写调用代码

具体实现如下。

添加依赖

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
            <version>4.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>4.0.2</version>
        </dependency>

设置配置文件


spring:
  application:
    name: nacos-discovery-business
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
        register-enabled: false

编写调用代码

此步骤又分为以下两步:


给 RestTemplate 增加 LoadBalanced 支持

使用 RestTemplate 调用接口

8.1 RestTemplate添加LoadBalanced

在 Spring Boot 启动类上添加“@EnableDiscoveryClient”注解,并使用“@LoadBalanced”注解替换 IoC 容器中的 RestTemplate,具体实现代码如下:


package com.example.consumer;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
 
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
 
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
 
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
 
}


8.2 使用RestTemplate

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
 
@RestController
@RequestMapping("/business")
public class BusinessController2 {
    @Autowired
    private RestTemplate restTemplate;
    @RequestMapping("/getnamebyid")
    public String getNameById(Integer id){
        return restTemplate.getForObject("http://nacos-discovery-demo/user/getnamebyid?id="+id,
                String.class);
    }
}


由于这种方式需要将生产者的接口都写入到一起,不利于实现松耦合管理,并且由于是使用RestTemplate,没有Openfeign的超时重试机制,所以企业中主要使用Openfeign与nacos。


九、Nacos注册中心如何做到百万级别的服务注册?底层使用了什么技术?

Nacos采用了异步化的设计,通过使用 异步任务和内存队列 的方式,能够提高系统的并发处理能力。这对于处理大量的注册请求和变更通知非常重要。

可能有人问,Nacos的数据不是都存储在我们刚刚设置的数据库中吗?

其实并不是的,数据库中只是存储一些配置信息,以及用户的一些数据,而注册的服务是配置到系统磁盘中的。

但是,IO操作其实是最耗时间的,但是Nacos采取内存队列,先将 注册的服务存入内存队列中,然后再开启一个异步任务,去内存队列中一个个取需要存入磁盘中的服务实例。