Nacos:以“服务”为中心的现代应用架构的服务基础设施
1、Nacos功能
Nacos主要功能在微服务中主要体现:配置中心、注册中心
1.1、Nacos优点
简单易用、特性丰富、超高性能、超大容量、高可用(这里几个特点下面会提到)
有些友友肯定对于配置中心和注册中心是有点分不清的,下面会一步步让你分清这两个的区别
1.2、安装并启动
(1)Nacos安装和运行需要依赖JDK环境,因此在安装之前,需要先在服务器安装JDK1.8+的环境
(2)安装并启动
这里直接编译压缩包进行安装(下面是linux上进行安装的)
下载压缩包:直接来github上下载就行 Releases · alibaba/nacos (github.com)
解压压缩包:unzip nacos-server-版本.zip 或者 tar -xvf nacos-server-版本.tar.zip
进入Nacos运行目录:cd nacos/bin;
启动Nacos服务:
Linux:sh startup.sh -m standalone 启动 Nacos 单击模式
windows:startup.cmd -m standalone 启动Nacos单击模式
下面展示一下:windows上得启动方式(方便演示)
下载好的,直接解压一份出来就可以了,我解压后改了个名字叫nacos文件夹
注:这里在你没有配置端口的时候,默认是8848端口
1.3、开启控制台授权登录
建议使用VS Code打开,快捷查找ctrl + F
nacos.core.auth.enabled=true
nacos.core.auth.server.identity.key=nacos
nacos.core.auth.server.identity.value=nacos
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
配置好以后,重启一下服务 访问之后会出现这个,点击确定就行
2、配置中心
2.1、创建配置服务
注:配置内容就是我们统一配置管理的信息
2.2、Spring Boot项目使用配置中心
(1)添加nacos-config依赖
(2)在项目配置文件设置nacos相关信息
(3)使用@Value注解
除了以上的依赖还需要一个spring web依赖,方便我们进行演示操作
不用东西可以直接删除,以下是不需要的东西
application.properties文件的配置
# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
# Nacos认证信息
#登录 nacos 用户名
spring.cloud.nacos.config.username=nacos
#登录密码 nacos
spring.cloud.nacos.config.password=nacos
#访问路径 不变的
spring.cloud.nacos.config.contextPath=/nacos
# 设置配置中心服务端地址
spring.cloud.nacos.config.server-addr=localhost:8848
# Nacos 配置中心的namespace。需要注意,如果使用 public 的 namcespace ,请不要填写这个值,直接留空即可
# spring.cloud.nacos.config.namespace=
#第一个nacos 表示的协议 : 配置名称
spring.config.import=nacos:nacos-config-example
注:这里的配置是不存在mysize的,mysize配置参数是写在nacos的配置中心的
2.3、特点
下面写一个类,访问,拿到nacos中配置参数
@RestController
@RequestMapping("/test")
public class TestController {
@Value("${mysize}")
private String mysize;
@RequestMapping("/get")
public String get(){
return "nacos-config : "+ mysize;
}
}
启动项目之后,按照路径进行访问
特点1:集中管理配置信息: 配置中心将不同服务的配置信息集中放在一起进行管理,实现了配置信息的集中存储,java代码也就不用写那么多了(这里拿到的就是配置中心存放的进行统一管理信息)
特点2:动态更新配置:配置中心的配置信息可以通过操作界面或者API进行动态更新,无需重启服务就可以应用最新的配置信息
如果这里我们修改配置信息,会进行热更新吗?就以现在代码,当然是不行的
这里需要加入一个注解,能意识到Nacos配置中心在更改
在原有代码的基础上添加一个注解@RefreshScope
@RestController
@RefreshScope
@RequestMapping("/test")
public class TestController {
@Value("${mysize}")
private String mysize;
@RequestMapping("/get")
public String get(){
return "nacos-config : "+ mysize;
}
}
就会进行实时更新,记得重启
注:修改内容后发布会有一个比对,这里绿色表示新添加的内容,红色表示删除内容,此时直接刷新就可以看见访问内容改变
特点3:配置信息共享:将配置集中在配置中心中,不同的服务实例可以共享一套配置信息,在上面配置文件的时候,这里有一个分组和Data ID,多个服务都可以使用同一个Data ID来实现配置共享
特点4:配置信息安全:配置中心可以配对信息,提供安全管理,权限控制等管理功能
特点5:信息追溯:支持配置版本管理、历史记录等管理功能
下面演示特点5,我们前面在Nacos中修改过一次配置信息,Nacos里面是记录了历史版本的
注:配置列表本身是存在在nacos自己给的一个存储文件中 嵌入式数据库Derby,一旦删除配置数据就会丢失,下面解释
3、Nacos注册中心
3.1、配置数据源
Nacos单击模式启动默认使用的是内置的嵌入式数据库Derby作为数据存储的,但是Derby不适合承载生产环境大规模部署,因为它有以下限制:
(1)数据存储容量最大只有2GB
(2)不支持集群模式下数据的高可用复制
(3)性能和并发能力有限
在生产环境中使用单击模式时,可以使用外置数据库作为数据存储,这里展示的是MySQL
数据源切换为MySQL
Nacos 0.7版本增加支持MySQL数据源能力:
(1)安装数据库,版本要求:5.6.5+;
(2)初始化MySQL数据库,数据库初始化文件:
注:下载好的Nacos包中是自带mysql的sql语句的
直接打开MySQL创建一个叫做nacos的数据库,把这个sql文件内容插入到前面创建的nacos数据库中(我这里使用的workbench进行操作),当前已经创建好了nacos数据库并导入表信息
(3)修改Nacos安装目录中中conf/application.properties文件,增加支持MySQL数据库配置,添加MySQL数据源的URL、用户名和密码,配置如下(将以下配置的注释去掉,并进行修改):
spring.datasource.platform=mysql
db.num=1
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=226688
datasource:表示数据源使用的是MySQL
num:表示数据库个数(这里我只有一个数据库所以就写了1)
url:数据库访问路径记住着连接的是我们刚刚导入那个nacos数据库,名字处理好
user.0:就是第一个数据库用户名(我的数据库用户名是root,请输入你的用户名)
password.0:就是第一个数据库密码(我的数据库密码是226688,请输入你的用户名)
3.2、注册中心
注册中心的交互过程:
服务提供者(生产者):对外提供服务的微服务应用,它会把自身的服务地址注册到注册中心,以供消费者发现者和调用
服务调用者(消费者):调用其他微服务的应用程序,它会向注册中心订阅自己需要的服务,并基于服务提供者注册的信息发起远程调用
3.2.1、生产者实现
(1)添加nacos-discovery依赖
(2)配置nacos服务器端信息
(3)编写调用接口
这里我从新创建一个项目来针对注册中心解释的
注:删除父类的src
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>provider</name>
<description>provider</description>
<!--标签 配置 父类-->
<parent>
<groupId>com.example</groupId>
<artifactId>nacos-discovery-csdn</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<!--因为我们这里继承父类 配置就可以省去了 这里的就可以删除了-->
<!-- <properties>-->
<!-- <java.version>17</java.version>-->
<!-- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>-->
<!-- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>-->
<!-- <spring-boot.version>3.0.2</spring-boot.version>-->
<!-- </properties>-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!--这里的依赖配置管理 父类已经配置过了,所以这里的就可以删除了-->
<!-- <dependencyManagement>-->
<!-- <dependencies>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-dependencies</artifactId>-->
<!-- <version>${spring-boot.version}</version>-->
<!-- <type>pom</type>-->
<!-- <scope>import</scope>-->
<!-- </dependency>-->
<!-- </dependencies>-->
<!-- </dependencyManagement>-->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.example.provider.ProviderApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
提供者的配置:
spring:
application:
name: provider #服务名称 一会在Nacos注册中心会看见的
cloud:
nacos: #nacos 服务
discovery: #进行注册配置
server-addr: localhost:8848 #配置nacos的访问地址
username: nacos #配置登录用户
password: nacos #配置用户密码
server:
port: 0 #端口随机分配 提供者 不需要具体的端口
提供者写一个代码: 在provider项目中创建一个controller层同时在该层建立一个UserController类
@RestController
@RequestMapping("/user")
public class UserController {
//为了获取端口号 注入webServer相关注解
@Autowired
private WebServerApplicationContext serverApplicationContext;
@RequestMapping("/getname")
public String getName(@RequestParam("id") Integer id){
return "provider : "+id+" | port "+serverApplicationContext.getWebServer().getPort();
}
}
3.2.2、消费者实现
消费者,需要调用生产者的HTTP接口,需要引入OpenFeign进行HTTP调用,其次为了实现负载均衡,所以开始添加了LoadBalancer
(1)添加依赖(注册中心,OpenFeign、LoadBalancer)
(2)配置nacos服务信息
(3)在项目中开启OPenFeign
(4)编写OPenFeign调用代码
(5)编写代码通过OpenFeign调用生产者
这里我们们直接使用父工程的,父工程已经导入了,我这里就直接创建项目依赖父工程管理就行
注:大体和提供者一样,配置父工程,删除自己的相关配置和依赖管理
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer</name>
<description>consumer</description>
<!--首先继承父工程-->
<parent>
<groupId>com.example</groupId>
<artifactId>nacos-discovery-csdn</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<!--删除自己配置 直接使用父工程的配置-->
<!-- <properties>-->
<!-- <java.version>17</java.version>-->
<!-- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>-->
<!-- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>-->
<!-- <spring-boot.version>3.0.2</spring-boot.version>-->
<!-- </properties>-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!--删除自己的依赖管理 父工程提我们管理了-->
<!-- <dependencyManagement>-->
<!-- <dependencies>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-dependencies</artifactId>-->
<!-- <version>${spring-boot.version}</version>-->
<!-- <type>pom</type>-->
<!-- <scope>import</scope>-->
<!-- </dependency>-->
<!-- </dependencies>-->
<!-- </dependencyManagement>-->
下面我们来写下配置文件:
spring:
application:
name: provider #服务名称 一会在Nacos注册中心会看见的
cloud:
nacos: #nacos 服务
discovery: #进行注册配置
server-addr: localhost:8848 #配置nacos的访问地址
username: nacos #配置登录用户
password: nacos #配置用户密码
register-enabled: false #表示注册显示 消费者 不需要显示
server:
port: 8080
注:下面开始编写消费者代码的时候,需要涉及远程调用所以consumer的启动类上需要添加一个@EnableFeignClients
启动提供者和消费者(注意:确保nacos服务是启动的)
3.3、注册中心参数
分组:注册服务所在的组名,默认是DEFAULT——GROUP,例如:研发小组,测试小组等
这里演示一下该操作;提供者的服务进行一下克隆,这里只需要在已经启动的提供者服务右击选择cope configuration ( 点击modify options选择 program arguments配置以下内容)
服务路由类型:常见有以下两种:
none:默认路由,基于权重的轮询负载均衡路由策略
label:标签路由,相同标签的实例会被聚合为一个集群,不同标签则实现流量隔离(不常用)
临时实例-永久实例
永久实例(Persistent Instance):是指注册到Nacos的服务实例,其注册信息会一直保留在Nacos服务器上,知道主动注销或者被删除。这意味即使服务实例下线或不可用,它的注册信息仍然会保留在Nacos上,直到显示取消注册。永久实例适用于需要长期存在服务
临时实例(Ephemeral Instance):是指注册到Nacos的服务实例,其注册信息在实例下线或不可用时会自动被删除。如果服务实例下线,、断开连接或者主动注销,Nacos会自动从注册表中删除这些实例的信息。临时实例适用于临时性的服务实例
以上两种实例主要针对健康检测机制有不同显示
健康检查机制应用
Nacos中提供两种健康检测的机制:
客户端主动上报(健康状态的)机制:客户端有问题了,及时向服务器求救
服务器端反向探测(健康状态的)机制:服务器定期扫描检测服务是否健康
临时实例(非持久化实例):对应的是客户端主动上报机制
临时实例每隔5秒级会主动上报一次自己的健康状况,发送的数据包叫做心跳包,发送心跳包的机制叫做心跳机制,如果心跳包的间隔时间超过了15秒,那么Nacos服务器端就会将此服务实例标记为非健康实例,如果心跳包超过了30s,那么Nacos服务端将会把此服务实例从服务列表删除
永久实例(持久化实例):对应的是服务端反向探测机制
服务端会定期检测,永久实例是否还存活这,如果不健康了,就会发出警告
演示:(这里只需要给provider服务 配置文件进行一个参数配置 ephemeral: false
注:以为2.0以后nacos实例下线的提示给去掉了,所以这里就是在演示实例下线后的提醒,如果有兴趣的友友,可以下载1.4.1版本的nacos去看看
spring:
application:
name: provider
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
ephemeral: false
server:
port: 0
保护阀值:健康节点要求的最小百分比。用于在服务出现不健康实例时,阻止流量过度向少量健康实例集中,保护服务的整体可用性,保护阀值应设置为一个0到1之间浮点数,默认值为0。当集群中的健康实例占比小于设置的保护阀值时,就会触发阀值保护功能,触发保护阀值后,Nacos会将全部实例返回给调用者,虽然可能会损失一部分流量,但是保证集群中的剩余的健康实例能正常工作(临时实例是演示不了阀值的,永久实例才能体现保护阀值,永久实例下线后不会丢失,可以计算占比)
那永久实例怎么删除呢,有点麻烦,永久实例存在这个文件里,直接把protocol文件删除就行
4、底层原理
Nacos执行流程图:
4.1、配置自动刷新原理
Nacos配置中心是支持配置项目自动刷新的,实现原理是通过长轮询+事件驱动方式来实现的
(1)客户端向Nacos服务器发送一个带有监听器(Listener)的请求,以获取某个特定配置的值
(2)Nacos服务器接收请求后,会检查该配置是否发生变化,如果没有变化,该请求将阻塞,知道超时或者配置发生变化
(3)当配置发生变化时,Nacos服务器会立即响应,并将新的配置值返回给客户端
(4)客户端接收到新的配置值后,可以根据需要更新自身的配置
以上叙述性其实就是长轮询
长轮询:客户端--(发送监听请求)->Nacos服务接收---(数据变化或者超时)-->数据返回客户端---->客户端收到消息,立马再发一个带有监听的请求(重复以上流程)
4.2、注册中心的底层实现
Nacos注册中心的底层实现主要依赖于两个关键组件:服务注册(Service Register)和服务发现(Service Discovery)
依仗这四个点:服务注册、心跳机制、服务发现、负载均衡
服务注册:当服务启动时,它会向Nacos服务器发送一个注册请求,包含自己的元数据信息。Nacos服务器接收到注册请求后,在内存中维护一个注册表,将服务实例的元数据保护起来,用户后续的服务发现
心跳机制:注册成功后,服务会定期发送心跳请求,以检测自己的健康状况和可以性,Nacos服务器就可以及时监控到服务实例的状态
服务发现:当服务消费者需要访问某个服务时,它会向Nacos服务器发送一个服务请求,包含所需服务的名称,Nacos服务器根服务名称查找注册表,返回服务的实例列表给消费者
负载均衡:Nacos提供了负载均衡的支持。消费者可以选择合适的负载均衡策略选择其中一个或者多个服务实例进行调用