type
status
date
slug
summary
tags
category
icon
password
做的项目中涉及到了nacos,作为刚刚步入职场,第一次认识到了nacos在项目中的使用。
首先先要明白nacos是什么。
Nacos(Naming and Configuration Service)是一个开源的动态服务发现、配置管理和服务管理平台。它主要用于微服务架构中,帮助开发者更方便地实现服务的注册与发现、配置管理以及服务管理。(其实看名字就知道用途了 naming and configuration!)
以下是一些基本概念:
Nacos的基本概念和功能是什么?
- Nacos主要提供服务注册与发现、动态配置管理和服务管理三大核心功能。
基于这三个核心的概念的拓展:
1.服务发现
- 传统方式的痛点:在微服务架构中,服务数量众多,且服务实例的 IP 地址和端口经常动态变化(例如,由于弹性伸缩、容器化部署等原因)。传统方式下,我们需要手动维护一个服务地址列表(例如,在配置文件中),这既繁琐又容易出错。
- Nacos 的解决方案:Nacos 提供了服务注册与发现的功能。
- 服务注册:每个服务实例在启动时,将自己的网络地址(IP 地址和端口)注册到 Nacos Server。
- 服务发现:当一个服务(消费者)需要调用另一个服务(提供者)时,它会向 Nacos Server 查询提供者的地址列表。Nacos Server 会返回可用的服务实例地址。
- 健康检查:Nacos 会定期检查已注册的服务实例的健康状况。如果某个实例不健康(例如,无法响应请求),Nacos 会将其从地址列表中移除,确保消费者不会调用到不可用的服务。
其实就是说:
- Nacos 客户端负责与 Nacos Server 通信,完成服务注册、发现和健康检查。
- Nacos Server 维护服务注册表,提供查询接口。
2.配置管理
- 传统方式的痛点:在分布式系统中,配置信息(例如,数据库连接、第三方 API 密钥、功能开关等)分散在各个服务的配置文件中。当配置需要更改时,我们需要逐个修改每个服务的配置文件,然后重启服务,这非常低效且容易出错。
- Nacos 的解决方案:Nacos 提供了集中式的配置管理功能。
- 配置存储:所有服务的配置信息都存储在 Nacos Server 中。
- 配置推送:当配置发生变化时,Nacos Server 会主动将最新的配置推送到相关的服务实例。服务实例无需重启即可应用新的配置。
- 版本控制:Nacos 支持配置的版本控制,可以方便地回滚到之前的配置版本。
- 多环境支持:Nacos 支持多环境(例如,开发、测试、生产)的配置隔离
其实就是说:
- Nacos 客户端监听配置变化,并自动更新本地配置。
- Nacos Server 负责存储、管理和推送配置。
3.服务管理
- 服务元数据:Nacos 允许为服务注册自定义元数据(例如,版本号、环境标签等)。这些元数据可用于服务治理、流量控制等场景。
- 流量管理:Nacos 集成了流量管理功能,可以实现灰度发布、流量路由等高级功能。
Nacos与Eureka、Consul等其他服务注册与发现组件的区别是什么?
- Nacos不仅支持服务注册与发现,还集成了动态配置管理功能,而Eureka和Consul主要专注于服务注册与发现。
- Nacos支持多种服务注册方式(如DNS、HTTP),而Eureka主要基于RESTful API。
- Nacos提供了更丰富的服务治理能力,如流量管理、权限控制等。
Nacos的主要用途:
- 服务注册与发现:微服务实例可以自动注册到Nacos,其他服务可以通过Nacos发现和调用这些实例。
- 动态配置管理:应用的配置可以集中管理在Nacos中,支持实时更新和推送,确保配置的一致性和实时性。
- 服务管理:提供服务实例的健康检查、流量管理、权限控制等功能,帮助开发者更好地管理和监控微服务。

总的来说,nacos的作用:注册中心+配置中心的组合 -> Nacos = Eureka+Config+Bus
一些问题:
- 服务实例下线问题: 服务实例下线后,Nacos 如何处理?
- 解决方案: 使用健康检查机制,确保下线的服务实例被及时移除。
- 配置更新延迟问题: 配置更新后,应用程序如何及时感知?
- 解决方案: 使用 Nacos 的配置监听机制,确保配置更新后立即通知应用程序。
- 集群脑裂问题: 集群中出现脑裂如何处理?
- 解决方案: 使用 Raft 协议确保集群数据一致性,避免脑裂问题。
一些bootstrap和application.yml的区别:
- 加载时机:
bootstrap.yml
在应用程序启动的早期阶段加载,甚至在application.yml
之前。application.yml
在应用程序启动的后期阶段加载。
- 用途:
bootstrap.yml
主要用于配置Spring Cloud相关的组件,如配置服务器、服务发现等。application.yml
主要用于配置应用程序的常规配置参数。
- 配置服务器:
bootstrap.yml
通常用于配置Spring Cloud Config Server的连接信息。application.yml
从配置服务器获取配置后,可以覆盖或补充bootstrap.yml
中的配置。
那在实际项目中的作用也是,包括要注册base business等模块的服务,以此来保证可以发现和调用这些实例;
一些配置类的修改,以此来配合ERMS系统的接口(比如erms的地址可以根据项目来修改)只要简单在nacos配置里面改一下就好了—》动态配置管理;
其他内容
- 命名空间 (Namespace):用于隔离不同的环境(例如,开发、测试、生产)。
- 配置的DataId和Group: DataId通常是应用名+profile名,Group用于区分不同的项目或者模块。
- 服务实例的权重:可以为不同的服务实例设置权重,实现流量的负载均衡
nacos的服务注册
如果用的springCloud:
Spring Cloud Alibaba 提供了自动配置类 NacosDiscoveryAutoConfiguration,这个配置类会在满足以下条件时自动生效:
- 存在 Nacos Discovery 的依赖
- 配置文件中包含了必要的 Nacos 配置(如 server-addr)
那么就要在bootstrap.yml(先于application.yml加载)
- 在使用 Spring Cloud Config 或相关依赖时(例如
spring-cloud-starter-alibaba-nacos-discovery
),默认会启用 bootstrap 机制,此时 bootstrap.yml 总是优先于 application.yml 加载。(Spring 2.4之前)
配置nacos的:
spring:
application:
name: RPM-SERVER # 服务注册到 Nacos 的名称
cloud:
nacos:
server-addr: ${cluster-nacos-connect-string} # Nacos 服务器地址
example:
metadata:
- 含义:通过 project: ${cluster-project-code} 为服务附加元数据,有助于区分不同的业务项目。
namespace:
- 含义:使用 ${profile} 指定命名空间,可以将不同环境(如 dev、test、prod)的服务进行逻辑隔离。
group:
- 含义:使用 ${nacos-group} 指定服务分组,有助于业务逻辑或版本的划分。分组机制让我们可以对服务进行集群管理或灰度发布
所以总的来说就是
先要有pom.xml
这个dependency之后
在bootstrap.yml(优先级高于application.yml)
添加上nacos相关的配置
>然后对应启动类添加上
@SpringBootApplication
注解就能实现服务的注册和发现
ref:
临时实例和永久实例
临时:业务服务,服务下线之后不需要注册中心中查看
永久:需要运维的服务,比如MySQL,redis

2.x版本
通信协议用的gRPC
原因:http会频繁创建和销毁链接,浪费资源

会把服务实例信息存储到客户端缓存中,redo操作,本质上redo就是一个补偿机制,定时任务,3s执行。
就是重新连接,怕服务实例挂了。
心跳机制
告诉服务端挂了
1.x的实现

各存在一个定时任务:
在Nacos服务端也会开启一个定时任务,默认也是5s执行一次,去检查这些服务实例最后一次心跳的时间,也就是客户端最后一次发送Http请求的时间
- 当最后一次心跳时间超过15s,但没有超过30s,会把这服务实例标记成不健康
- 当最后一次心跳超过30s,直接把服务从服务注册表中剔除
2.x版本
长连接+主动检查
- 连接本身的心跳机制,断开就直接剔除服务实例
- Nacos主动检查机制,服务端会对20s没有发送数据的连接进行检查,出现异常时也会主动断开连接,剔除服务实例
健康检查
心跳机制是服务实例向服务端发送请求
健康检查是服务端主动向服务实例发送请求

健康检查机制在1.x和2.x的实现机制是一样的
Nacos服务端在会去创建一个健康检查任务,这个任务每次执行时间间隔会在2000~7000毫秒之间
当任务触发的时候,会根据设置的健康检查的方式执行不同的逻辑,目前主要有以下三种方式:
- TCP
- HTTP
- MySQL
TCP的方式就是根据服务实例的ip和端口去判断是否能连接成功,如果连接成功,就认为健康,反之就任务不健康
HTTP的方式就是向服务实例的ip和端口发送一个Http请求,请求路径是需要设置的,如果能正常请求,说明实例健康,反之就不健康
MySQL的方式是一种特殊的检查方式,他可以执行下面这条Sql来判断数据库是不是主库
一般就用TCP
服务发现
nacos提供两种发现的方式:主动查阅和服务订阅
一般是后者,主动push到服务端
2.x服务订阅的实现

服务查询1.x是通过Http请求;2.x通过gRPC请求
服务订阅1.x是通过UDP来推送的;2.x就基于gRPC长连接来实现的
1.x和2.x客户端都有服务实例的缓存,也有定时对比机制,只不过1.x会自动开启;2.x提供了一个开个,可以手动选择是否开启,默认不开启
数据一致性
服务的责任机制?

哪个服务负责哪个实例
CAP和BASE

最多只能满足两个
为什么不能同时满足三个?
因为对于一个分布式,网络是一定需要分区的。—》分区就是说系统的服务部署在不同的网络区域

比如一套系统可能在北京和上海都有部署,不同的网络分区可能存在无法相互访问的情况。
就因为可能出现网络分区导致的通信失败。
比如说,现在出现了网络分区的问题,上图中的A网络区域和B网络区域无法相互访问
此时假设往上图中的A网络区域发送请求,将服务中的一个值 i 属性设置成 1
如果保证可用性,此时由于A和B网络不通,此时只有A中的服务修改成功,B无法修改成功,此时数据AB区域数据就不一致性,也就没有保证数据一致性
如果保证一致性,此时由于A和B网络不通,所以此时A也不能修改成功,必须修改失败,否则就会导致AB数据不一致
虽然A没修改成功,保证了数据一致性,AB还是之前相同的数据,但是此时整个系统已经没有写可用性了,无法成功写数据了
如何解决:?
首先我们可以先保证系统的可用性,也就是先让系统能够写数据,将A区域服务中的i修改成1
之后当AB区域之间网络恢复之后,将A区域的i值复制给B区域,这样就能够保证AB区域间的数据最终是一致的了
这不就皆大欢喜了么
这种思路其实就是BASE理论的核心要点,优先保证可用性,数据最终达成一致性。
BASE理论主要是包括以下三点:
- 基本可用(Basically Available):系统出现故障还是能够对外提供服务,不至于直接无法用了
- 软状态(Soft State):允许各个节点的数据不一致
- 最终一致性,(Eventually Consistent):虽然允许各个节点的数据不一致,但是在一定时间之后,各个节点的数据最终需要一致的
NACOS的AP
用的是阿里的Distro协议,每个节点都是平等的,服务都能接受客户端的读写

当某个服务端节点接收到注册临时服务实例的请求,不仅仅会将这个服务实例存到自身的服务注册表,同时也会向其它所有服务节点发送请求,将这个服务数据同步到其它所有节点

所以此时从任意一个节点都是可以获取到所有的服务实例数据的。
即使数据同步的过程发生异常,服务实例也成功注册到一个Nacos服务中,对外部而言,整个Nacos集群是可用的,也就达到了AP的效果
同时为了满足BASE理论,Nacos也有下面两种机制保证最终节点间数据最终是一致的:
- 失败重试机制
- 定时对比机制
失败重试机制是指当数据同步给其它节点失败时,会每隔3s重试一次,直到成功
定时对比机制就是指,每个Nacos服务节点会定时向所有的其它服务节点发送一些认证的请求
这个请求会告诉每个服务节点自己负责的服务实例的对应的版本号,这个版本号随着服务实例的变动就会变动
Nacos的CP
基于Raft算法
在Raft算法,每个节点主要有三个状态
- Leader,负责所有的读写请求,一个集群只有一个
- Follower,从节点,主要是负责复制Leader的数据,保证数据的一致性
- Candidate,候选节点,最终会变成Leader或者Follower

当有写请求时,如果请求的节点不是Leader节点时,会将请求转给Leader节点,由Leader节点处理写请求
比如,有个客户端连到的上图中的
Nacos服务2
节点,之后向Nacos服务2
注册服务Nacos服务2
接收到请求之后,会判断自己是不是Leader节点,发现自己不是此时
Nacos服务2
就会向Leader节点发送请求,Leader节点接收到请求之后,会处理服务注册的过程如何保证CP?
- 首先,Leader在处理写请求时,不会直接数据应用到自己的系统,而是先向所有的Follower发送请求,让他们先处理这个请求
- 当超过半数的Follower成功处理了这个写请求之后,Leader才会写数据,并返回给客户端请求处理成功
- 如果超过一定时间未收到超过半数处理成功Follower的信号,此时Leader认为这次写数据是失败的,就不会处理写请求,直接返回给客户端请求失败
所以,一旦发生故障,导致接收不到半数的Follower写成功的响应,整个集群就直接写失败,这就很符合CP的概念了。
数据模型

- 命名空间(Namespace):多租户隔离用的,默认是
public
- 分组(Group):这个其实可以用来做环境隔离,服务注册时可以指定服务的分组,比如是测试环境或者是开发环境,默认是
DEFAULT_GROUP
- 服务名(ServiceName):这个就不用多说了
通过上面三者就可以确定同一个服务了
在服务注册和订阅的时候,必须要指定上述三部分信息,如果不指定,Nacos就会提供默认的信息