Nacos
一、介绍
1、简介
【全称】 Dynamic Naming and Configuration Service
【官网】 https://nacos.io/zh-cn/index.html
一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理。
//什么是nacos? 这个组件能做什么? 能够解决什么问题?
自述:nacos是一个微服务管理组件,它本质上也是一个微服务,具备服务管理和配置管理功能,在实际开发中分布式架构比较常用,分布式架构存在服务集群和微服务之间相互调用,而nacos主要对分布式服务管理:
//服务管理方面:
管理服务提供者的地址信息(服务提供者配置nacos,服务一启动就被nacos识别并管理),监控服务提供者的健康状态(被动(临时实例):心跳检测 / 主动(非临时实例):主动询问),具备负载均衡策略ribbon(配置集群,集群就近优先原则,不配置则轮流访问),协调服务有效运行。和nacos同类型的组件有eureka,相比不如nacos强大。nacos解决了eureka不能够主动向服务推送变更消息,且只能被动检测服务状态的缺陷。
(略:nacos弥补了eureka不能持久化服务提供者地址信息到本地的缺陷)
//配置管理方面:
微服务集群中存在相同的配置信息,nacos能够将配置文件从微服务中的抽离出来,存放在nacos统一管理,不仅能够热更新配置信息,还能很大程度上解耦合,方便维护。
2、安装
从官网下载压缩文件后,解压即安装。
3、启动
3.1、单机模式
cmd 进入到bin目录下
start.cmd -m standalone
默认端口:8848
登录名:nacos
密码:nacos
3.2、集群
① 修改配置文件
进入nacos的conf目录,修改配置文件cluster.conf.example,重命名为cluster.conf
修改如下:
127.0.0.1:8845
127.0.0.1:8846
127.0.0.1:8847
② 连接数据库
【1】初始化数据库==执行conf目录下的mysql文件
【2】修改application.properties文件,添加数据库配置
# 使用的数据库类型
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=root
③ 修改端口
进入每个的application.properties文件,修改端口如下:
server.port=8845
server.port=8846
server.port=8847
④ 启动
cmd 进入到bin目录下start.cmd 或 双击start.cmd
此时端口为配置的端口
登录名:nacos
密码:nacos
⑤ 配置nginx
upstream nacos-cluster {
server 127.0.0.1:8845;
server 127.0.0.1:8846;
server 127.0.0.1:8847;
}
server {
listen 80;
server_name localhost;
location /nacos {
proxy_pass http://nacos-cluster;
}
}
⑥ 项目中配置
spring:
cloud:
nacos:
server-addr: localhost:80 # Nacos地址
4、相关概念
DataId:服务名//指定nacos配置服务中微服务的配置文件的文件名
Group:组名 //便于区分不同程序的服务
Namespace:名称空间,起隔离作用 //不写会报错,如果为""表示使用默认命名空间public
cluster-name:集群名称,可配置就近原则//提供者配置集群名称则就近原则,不配置则轮流访问
二、注册中心-Nacos
1、面临问题
1、在远程调用的时候,如何得知提供者的ip地址和端口。
//所有微服务配置了服务名称和nacos地址,当微服务启动就被nacos识别和管理,服务消费者远程调用时根据服务名称从nacos中获取服务名称对应的所有提供者的地址信息。
2、有多个提供者时该如何选择。
//所有微服务在配置nacos信息是可以配置集群,当访问微服务集群时,服务消费者会根据自己的集群名称去nacos中就近原则轮流访问相同集群下的服务提供者。不指定集群名称则轮流访问所有的提供者服务
3、如何让得知某个提供者是否健康,是不是已经宕机。
//nacos具有主动询问和被动心跳检测两种方式检测服务提供者的健康状态,当提供者异常时,会及时向消费者推送变更消息。
2、解决方案-nacos
![image-20220303201549619](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2FE%3A%2Fjava%2FAPI%2F%25E5%25BE%25AE%25E6%259C%258D%25E5%258A%25A1%2F3%25E3%2580%2581nacos%2FNacos.assets%2Fimage-20220303201549619.png%3FlastModify%3D1712579740&pos_id=mkaCgzzG)
3、使用步骤
3.1、父工程导入alibaba依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
3.2、导入依赖
<!--nacos注册中心客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
3.3、配置服务器地址
spring:
cloud:
nacos:
server-addr: localhost:8848 # 服务端地址
discovery: # 作为注册中心的相关配置
cluster-name: SH //所属集群名称
namespace: SH //所属名称空间
group: default # 所属组名
3.4、就近原则配置
userservice:
ribbon:
# 负载均衡规则 - 就近原则
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
4、与Eureka的区别
4.1、服务发现模式不同
Nacos: 服务端发现模式//主动
Eureka: 客户端发现模式//被动
4.2、提供者地址获取方式不同
Nacos: 服务端向健康临时实例和非临时实例广播地址//nacos主动向消费者服务推送提供者状态变更消息
Eureka: 客户端自己向服务端拉取地址//消费者服务定时从eureka中拉取提供者信息
![3.png](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2FE%3A%2Fjava%2FAPI%2F%25E5%25BE%25AE%25E6%259C%258D%25E5%258A%25A1%2F3%25E3%2580%2581nacos%2FNacos.assets%2F3.png%3FlastModify%3D1712579740&pos_id=Jo1HmSG4)
4.3、心跳检测机制不同
Nacos: 客户端5s发送心跳状态。服务端20s剔除临时实例,非临时实例永不剔除。
Eureka: 客户端30s发送心跳状态。服务端60s进行剔除。默认有保护机制。
4.4、ACP侧重不同
Nacos: CP.//一致性
Eureka: AP.//可用性
三、配置中心-Nacos
1、面临问题
1、同一个微服务下多个实例需要修改配置文件时十分繁琐
//随着微服务部署的实例越来越多,如果业务需要做调整,修改每个微服务配置就显得程序很冗余,而将这些配置抽取到nacos中,每个微服务根据配置文件名获取nacos中配置文件信息,这样只需在nacos中存放一份,就可以让多个微服务共享该配置文件信息,实现nacos统一管理。
//注意事项:要将微服务获取nacos配置文件的信息单独存放在bootstrap.yml文件中,保证在application.yml核心配置文件加载之前加载,先拉取远程配置文件再读取本地配置文件创建spring容器。
2、当配置文件信息发生变更时,微服务如何实时读取
//当配置文件被抽取到nacos中,在微服务内部的类上打注解@RefreshScope或者@ConfigurationProperties(prefix = "pattern")注入的方式可以从nacos中拿取配置信息,nacos只需对配置文件内容做修改并发布,微服务不需要重启就能直接热更新配置信息
![1.png](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2FE%3A%2Fjava%2FAPI%2F%25E5%25BE%25AE%25E6%259C%258D%25E5%258A%25A1%2F3%25E3%2580%2581nacos%2FNacos.assets%2F1.png%3FlastModify%3D1712579740&pos_id=8QYqmPhc)
2、解决方案-nacos
1、简介
1.分离的多环境配置,可以更灵活的管理权限,安全性更高。
2.应用程序的打包更为纯粹,以实现一次打包,多处运行的特点。
3.配置动态刷新(可以在读取配置的类上面添加注解@RefreshScope来实现动态刷新)
4.配置回滚(可以再历史版本里面查看到配置文件修改的记录,可以选择对应的版本回滚)。
Nacos的配置管理,基础层面都通过DataId和Group来定位配置内容,除此之外还增加了很多其他的管理功能。
2、分布式配置中心实现原理
本地应用读取云端分布式配置中心文件(第一次读取时建立长连接)
本地应用读取到配置文件后,本地jvm和硬盘都会缓存一份。
本地应用于分布式配置中心服务器端一直保持长连接
当我们的配置文件发生变化(根据版本号|MID判断)。将变化结果通知本地应用及时刷新配置文件。
3、使用步骤
3.1、服务端配置
![image-20220303203206992](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2FE%3A%2Fjava%2FAPI%2F%25E5%25BE%25AE%25E6%259C%258D%25E5%258A%25A1%2F3%25E3%2580%2581nacos%2FNacos.assets%2Fimage-20220303203206992.png%3FlastModify%3D1712579740&pos_id=EL0SIg58)
3.2、导入依赖
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
3.3、配置服务器地址(bootstrap.yml)
spring:
application:
name: userservice # 服务名称
profiles:
active: dev #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
config: # 作为配置中心的相关配置
file-extension: yaml # 文件后缀名 必须与服务端配置相同
cluster-name: SH # 所属集群名称
namespace: SH # 所属名称空间
group: default # 所属组名
![2.png](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=file%3A%2F%2FE%3A%2Fjava%2FAPI%2F%25E5%25BE%25AE%25E6%259C%258D%25E5%258A%25A1%2F3%25E3%2580%2581nacos%2FNacos.assets%2F2.png%3FlastModify%3D1712579740&pos_id=GfIYazN3)
3.4、配置文件加载顺序(优先级)
外部的优于内部的,指定的大于默认的。
//微服务内部配置<nacos指定配置的<nacos共享配置
3.5、热更新配置
① 在@Value注入的变量所在类上添加注解@RefreshScope
@RefreshScope
public class UserController {
@Value("${pattern.dateformat}")
private String dateformat;
}
② 使用@ConfigurationProperties注解代替@Value注解
@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dateformat;
}