Nacos简介
官网地址
github文档地址
- Nacos 致力于帮助您发现、配置和管理微服务。
- Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
- Nacos 具有如下特性:
- 服务发现和服务健康监测:支持基于DNS和基于RPC的服务发现,支持对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求;
- 动态配置服务:动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置;
- 动态 DNS 服务:动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务;
- 服务及其元数据管理:支持从微服务平台建设的视角管理数据中心的所有服务及元数据。
Nacos中的基本概念
-
地域
-
可用区
- 同一地域内,电力和网络互相独立的物理区域。同一可用区内,实例的网络延迟较低。
-
接入点
-
命名空间
- 用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
-
配置
- 在系统开发过程中,开发者通常会将一些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。
- 目的是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物理运行环境进行适配。
- 配置管理一般包含在系统部署的过程中,由系统管理员或者运维人员完成。
- 配置变更是调整系统运行时的行为的有效手段。
-
配置管理
- 系统配置的编辑、存储、分发、变更管理、历史版本管理、变更审计等所有与配置相关的活动。
-
配置项
- 一个具体的可配置的参数与其值域
- 通常以 param-key=param-value 的形式存在。
- 例如我们常配置系统的日志输出级别(logLevel=INFO|WARN|ERROR) 就是一个配置项。
-
配置集
- 一组相关或者不相关的配置项的集合称为配置集。
- 在系统中,一个配置文件通常就是一个配置集,包含了系统各个方面的配置。
- 例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。
-
配置集 ID
- Nacos 中的某个配置集的 ID。
- 配置集 ID 是组织划分配置的维度之一。
- Data ID 通常用于组织划分系统的配置集。
- 一个系统或者应用可以包含多个配置集,每个配置集都可以被一个有意义的名称标识。
- Data ID 通常采用类 Java 包(如 com.taobao.tc.refund.log.level)的命名规则保证全局唯一性。此命名规则非强制。
-
配置分组
- Nacos 中的一组配置集,是组织配置的维度之一。
- 通过一个有意义的字符串(如 Buy 或 Trade )对配置集进行分组,从而区分 Data ID 相同的配置集。
- 当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。
- 配置分组的常见场景:不同的应用或组件使用了相同的配置类型,如 database_url 配置和 MQ_topic 配置。
-
配置快照
- Nacos 的客户端 SDK 会在本地生成配置的快照。
- 当客户端无法连接到 Nacos Server 时,可以使用配置快照显示系统的整体容灾能力。
- 配置快照类似于 Git 中的本地 commit,也类似于缓存,会在适当的时机更新,但是并没有缓存过期(expiration)的概念。
-
服务
-
服务名
- 服务提供的标识,通过该标识可以唯一确定其指代的服务。
-
服务注册中心
-
服务发现
- 在计算机网络上,(通常使用服务名)对服务下的实例的地址和元数据进行探测,并以预先定义的接口提供给客户端进行查询。
-
元信息
- Nacos数据(如配置和服务)描述信息,如服务版本、权重、容灾策略、负载均衡策略、鉴权配置、各种自定义标签 (label),从作用范围来看,分为服务级别的元信息、集群的元信息及实例的元信息。
-
应用
-
服务分组
-
虚拟集群
- 同一个服务下的所有服务实例组成一个默认集群, 集群可以被进一步按需求划分,划分的单位可以是虚拟集群。
-
实例
- 提供一个或多个服务的具有可访问网络地址(IP:Port)的进程。
-
权重
- 实例级别的配置。权重为浮点数。权重越大,分配给该实例的流量越大。
-
健康检查
- 以指定方式检查服务下挂载的实例 (Instance) 的健康度,从而确认该实例 (Instance) 是否能提供服务。根据检查结果,实例 (Instance) 会被判断为健康或不健康。对服务发起解析请求时,不健康的实例 (Instance) 不会返回给客户端。
-
健康保护阈值
- 为了防止因过多实例 (Instance) 不健康导致流量全部流向健康实例 (Instance) ,继而造成流量压力把健康实例 (Instance) 压垮并形成雪崩效应,应将健康保护阈值定义为一个 0 到 1 之间的浮点数。
- 当域名健康实例数 (Instance) 占总服务实例数 (Instance) 的比例小于该值时,无论实例 (Instance) 是否健康,都会将这个实例 (Instance) 返回给客户端。
- 这样做虽然损失了一部分流量,但是保证了集群中剩余健康实例 (Instance) 能正常工作。
Nacos基本架构及概念
-
服务 (Service)
- 服务是指一个或一组软件功能(例如特定信息的检索或一组操作的执行),其目的是不同的客户端可以为不同的目的重用(例如通过跨进程的网络调用)。
- Nacos 支持主流的服务生态,如 Kubernetes Service、gRPC|Dubbo RPC Service 或者 Spring Cloud RESTful Service。
-
服务注册中心 (Service Registry)
- 服务注册中心,它是服务,其实例及元数据的数据库。
- 服务实例在启动时注册到服务注册表,并在关闭时注销。
- 服务和路由器的客户端查询服务注册表以查找服务的可用实例。
- 服务注册中心可能会调用服务实例的健康检查 API 来验证它是否能够处理请求。
-
服务元数据 (Service Metadata)
- 服务元数据是指包括服务端点(endpoints)、服务标签、服务版本号、服务实例权重、路由规则、安全策略等描述服务的数据。
-
服务提供方 (Service Provider)
-
服务消费方 (Service Consumer)
-
配置 (Configuration)
- 在系统开发过程中通常会将一些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。
- 目的是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物理运行环境进行适配。
- 配置管理一般包含在系统部署的过程中,由系统管理员或者运维人员完成这个步骤。
- 配置变更是调整系统运行时的行为的有效手段之一。
-
配置管理 (Configuration Management)
- 在数据中心中,系统中所有配置的编辑、存储、分发、变更管理、历史版本管理、变更审计等所有与配置相关的活动统称为配置管理。
-
名字服务 (Naming Service)
- 提供分布式系统中所有对象(Object)、实体(Entity)的“名字”到关联的元数据之间的映射管理服务
- 例如 ServiceName -> Endpoints Info, Distributed Lock Name -> Lock Owner/Status Info,
- DNS Domain Name -> IP List,
-
配置服务 (Configuration Service)
- 在服务或者应用运行过程中,提供动态配置或者元数据以及配置管理的服务提供者。
逻辑架构及其组件介绍
- 服务管理:
- 实现服务CRUD,域名CRUD,服务健康状态检查,服务权重管理等功能
- 配置管理:
- 实现配置管CRUD,版本管理,灰度管理,监听管理,推送轨迹,聚合数据等功能
- 元数据管理:
- 插件机制:
- 事件机制:
- 日志模块:
- 管理日志分类,日志级别,日志可移植性(尤其避免冲突),日志格式,异常码+帮助文档
- 回调机制:
- sdk通知数据,通过统一的模式回调用户处理。接口和数据结构需要具备可扩展性
- 寻址模式:
- 解决ip,域名,nameserver、广播等多种寻址模式,需要可扩展
- 推送通道:
- 解决server与存储、server间、server与sdk间推送性能问题
- 容量管理:
- 管理每个租户,分组下的容量,防止存储被写爆,影响服务可用性
- 流量管理:
- 按照租户,分组等多个维度对请求频率,长链接个数,报文大小,请求流控进行控制
- 缓存机制:
- 容灾目录,本地缓存,server缓存机制。容灾目录使用需要工具
- 启动模式:
- 按照单机模式,配置模式,服务模式,dns模式,或者all模式,启动不同的程序+UI
- 一致性协议:
- 解决不同数据,不同一致性要求情况下,不同一致性机制存储模块:解决数据持久化、非持久化存储,解决数据分片问题
- Nameserver:
- 解决namespace到clusterid的路由问题,解决用户环境与nacos物理环境映射问题
- CMDB:
- 解决元数据存储,与三方cmdb系统对接问题,解决应用,人,资源关系
- Metrics:
- 暴露标准metrics数据,方便与三方监控系统打通
- Trace:
- 暴露标准trace,方便与SLA系统打通,日志白平化,推送轨迹等能力,并且可以和计量计费系统打通
- 接入管理:
- 用户管理:
- 权限管理:
- 审计系统:
- 通知系统:
- 核心数据变更,或者操作,方便通过SMS系统打通,通知到对应人数据变更
- OpenAPI:
- 暴露标准Rest风格HTTP接口,简单易用,方便多语言集成
- Console:
- SDK:
- Agent:
- CLI:
领域模型
- Nacos 数据模型 Key 由三元组唯一确定
- Namespace默认是空串
- 公共命名空间(public)
- 分组默认是 DEFAULT_GROUP。
原理
-
nacos 配置中心采用
- 客户端 long pull 的方式
- Nacos 客户端会循环请求服务端变更的数据,并且超时时间设置为30s,当配置发生变化时,请求的响应会立即返回,否则会一直等到 29.5s+ 之后再返回响应
- 客户端的请求到达服务端后,服务端将该请求加入到一个叫 allSubs 的队列中,等待配置发生变更时 DataChangeTask主动去触发,并将变更后的数据写入响应对象。
- 与此同时服务端也将该请求封装成一个调度任务去执行,等待调度的期间就是等DataChangeTask 主动触发的,如果延迟时间到了 DataChangeTask 还未触发的话,则调度任务开始执行数据变更的检查,然后将检查的结果写入响应对象(基于文件的MD5)
-
nacos注册中心采用了
- pull (客户端的轮询)
- push (服务端主动push)
- 客户端启动时会将当前服务的信息包含ip、端口号、服务名、集群名等信息封装为一个Instance对象然后创建一个定时任务,每隔一段时间向Nacos服务器发送PUT请求并携带相关信息。
- nacos服务器端在接收到心跳请求后,会去检查当前服务列表中有没有该实例,如果没有的话将当前服务实例重新注册,注册完成后立即开启一个异步任务,更新客户端实例的最后心跳时间,如果当前实例是非健康状态则将其改为健康状态。
- 心跳定时任务创建完成后,通过POST请求将当前服务实例信息注册进nacos服务器。
- nacos服务器端在接收到注册实例请求后,会将请求携带的数据封装为一个Instance对象,然后为这个服务实例创建一个服务Service,一个Service下可能有多个服务实例,服务在Nacos保存到一个ConcurrentHashMap中Map(namespace,Map(group::serviceName, Service)); 。
- nacos将实例添加到对应服务列表中会根据AP和CP不同的模式,采用不同协议。
- CP模式就是基于Raft协议(通过leader节点将实例数据更新到内存和磁盘文件中,并且通过CountDownLatch实现了一个简单的raft写入数据的逻辑,必须集群半数以上节点写入成功才会给客户端返回成功)
- AP模式基于Distro协议(向任务阻塞队列添加一个本地服务实例改变任务,去更新本地服务列表,然后在遍历集群中所有节点,分别创建数据同步任务放进阻塞队列异步进行集群数据同步,不保证集群节点数据同步完成即可返回)
- nacos在将服务实例更新到服务注册表中时,为了防止并发读写冲突,采用的是写时复制的思想,将原注册表数据拷贝一份,添加完成之后再替换回真正的注册表。
- nacos在更新完成之后,通过发布服务变化事件,将服务变动通知给客户端,采用的是UDP通信,客户端接收到UDP消息后会返回一个ACK信号,如果一定时间内服务端没有收到ACK信号,还会尝试重发,当超出重发时间后就不在重发。
- 客户端通过定时任务定时从服务端拉取服务数据保存在本地缓存。
服务端在发生心跳检测、服务列表变更或者健康状态改变时会触发推送事件,在推送事件中会基于UDP通信将服务列表推送到客户端,虽然通过UDP通信不能保证消息的可靠抵达,由于Nacos客户端会开启定时任务,每隔一段时间更新客户端缓存的服务列表,通过定时轮询更新服务列表做兜底,所以不用担心数据不会更新的情况,这样既保证了实时性,又保证了数据更新的可靠性。
#false为永久实例,true表⽰临时实例开启,注册为临时实例,默认是true
spring.cloud.nacos.discovery.ephemeral=true
- 为什么nacos有两种心跳机制?
- 对于临时实例,健康检查失败,则直接删除。这种特性适合于需要应对流量突增的场景,服务可以弹性扩容,当流量过去后,服务停掉即可自动注销。
- 对于持久化实例,健康检查失败,会设置为不健康状态。它的优点就是可以实时的监控到实例的健康状态,便于后续的告警和扩容等一系列处理。
- 自我保护
- nacos也有自我保护机制(当前健康实例数/当前服务总实例数),值为0-1之间的浮点类型。
- 正常情况下nacos 只回健康的实例。
- 但在高并发场景,如果只返回健康实例的话,流量洪峰到来可能直接打垮剩下的健康实例,产生雪崩效应。
- 保护阈值存在的意义在于当服务A健康实例数/总实例数 < 保护阈值时,Nacos会把该服务所有的实例信息(健康的+不健康的)全部提供给消费者
- 消费者可能访问到不健康的实例,请求失败,但这样远比造成雪崩要好。牺牲了请求,保证了整个系统的可用。
总结
- 服务注册到注册中心后,服务的消费者就可以向注册中心订阅某个服务,并提交一个监听器,当注册中心中服务发生变更时,监听器会收到通知,这时消费者更新本地的服务实例列表,以保证所有的服务均是可用的。
- Nacos注册可以概括为以下六步
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
Nacos安装
- nacos下载地址
- 配置JAVA_HOME
- 解压安装包,直接运行bin目录下的startup.cmd;
- 运行成功后,访问http://localhost:8848/nacos可以查看Nacos的主页,默认账号密码都是nacos。
Nacos 配置持久化至 MySQL
- 进入项目的 middleware/nacos/conf/application.properties 文件修改 Nacos 配置的数据连接,需要修改配置如下:
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://localhost:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123456
- 在mysql数据库创建 nacos (自定义名称)数据库,然后运行sql脚本 nacos-mysql.sql,脚本位置在:
Java项目注册到Nacos
- 我们通过改造consul-user-service和consul-ribbon-service来演示下服务注册与发现的功能,主要是将应用原来的Consul注册中心支持改为Nacos注册中心支持。
- 创建nacos-user-service模块和nacos-ribbon-service模块;
- 如果要使用Spring Cloud Alibaba 的组件都需要在pom.xml中添加如下的配置;
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 修改相关依赖,把原来的Consul注册发现的依赖改为Nacos的:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- 修改配置文件application.yml,将Consul的注册发现配置改为Nacos的:
server:
port: 8206
spring:
application:
name: nacos-user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址
management:
endpoints:
web:
exposure:
include: '*'
- 运行两个nacos-user-service和一个nacos-ribbon-service,在Nacos页面上可以看到如下信息
负载均衡功能
- 由于我们运行了两个nacos-user-service,而nacos-ribbon-service默认会去调用它的接口,我们调用nacos-ribbon-service的接口来演示下负载均衡功能。
- 多次调用接口:http://localhost:8308/user/1 ,可以发现两个nacos-user-service的控制台交替打印如下信息。
2022-09-24 22:28:06.458 INFO 12092 --- [nio-8207-exec-2] c.macro.cloud.controller.UserController : 根据id获取用户信息,用户名称为:macro
使用Nacos作为配置中心
- 创建nacos-config-client模块
- 在pom.xml中添加相关依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- 添加配置文件application.yml,启用的是dev环境的配置:
spring:
profiles:
active: dev
- 添加配置文件bootstrap.yml,主要是对Nacos的作为配置中心的功能进行配置:
server:
port: 9101
spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: localhost:8848 #Nacos地址
config:
server-addr: localhost:8848 #Nacos地址
file-extension: yaml #这里我们获取的yaml格式的配置
- 创建ConfigClientController,从Nacos配置中心中获取配置信息:
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo() {
return configInfo;
}
}
在Nacos中添加配置
- 我们先来讲下Nacos中的dataid的组成格式及与SpringBoot配置文件中的属性对应关系:
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
- 比如说我们现在要获取应用名称为nacos-config-client的应用在dev环境下的yaml配置,dataid如下:
nacos-config-client-dev.yaml
config:
info: "config info for dev"
- 启动nacos-config-client,调用接口查看配置信息:http://localhost:9101/configInfo
config info for dev
Nacos的动态刷新配置
- 我们只要修改下Nacos中的配置信息,再次调用查看配置的接口,就会发现配置已经刷新,Nacos和Consul一样都支持动态刷新配置。当我们在Nacos页面上修改配置并发布后,应用会刷新配置并打印如下信息
2022-09-24 22:50:49.460 INFO 12372 --- [-localhost_8848] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$ec395f8e] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2022-09-24 22:50:49.608 INFO 12372 --- [-localhost_8848] c.a.c.n.c.NacosPropertySourceBuilder : Loading nacos data, dataId: 'nacos-config-client-dev.yaml', group: 'DEFAULT_GROUP'
2022-09-24 22:50:49.609 INFO 12372 --- [-localhost_8848] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource {name='NACOS', propertySources=[NacosPropertySource {name='nacos-config-client-dev.yaml'}, NacosPropertySource {name='nacos-config-client.yaml'}]}
2022-09-24 22:50:49.610 INFO 12372 --- [-localhost_8848] o.s.boot.SpringApplication : The following profiles are active: dev
2022-09-24 22:50:49.620 INFO 12372 --- [-localhost_8848] o.s.boot.SpringApplication : Started application in 0.328 seconds (JVM running for 172.085)
2022-09-24 22:50:49.638 INFO 12372 --- [-localhost_8848] o.s.c.e.event.RefreshEventListener : Refresh keys changed: [config.info]
Nacos集群部署
https://blog.csdn.net/jeff06143132/article/details/123565017
https://blog.csdn.net/qq_51277752/article/details/125744997
https://www.51cto.com/article/649179.html
https://zhuanlan.zhihu.com/p/105265584