Appearance
Nacos简介
Nacos是由阿里巴巴团队使用 Java 语言开发的开源项目。一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
Nacos是Dynamic Naming and Configuration Service的首字母简称。Nacos就是注册中心+配置中心的组合(Nacos=Eureka+Config+Bus)。
Nacos安装
下载
Nacos安装包 Nacos官网支持多种安装方式(压缩包解压即用、
docker镜像运行、k8s部署)bin目录下有
startup.cmd和startup.sh两个启动脚本,分别适用于Windows和Linux系统。启动后默认地址是
http://localhost:8848/nacos,默认用户名密码都是nacos。
Nacos集群搭建
搭建一个生产可用的Nacos集群,主要包含以下几个核心步骤:
环境准备:至少准备3个或以上的奇数个节点。这是由底层的一致性算法(Raft协议)所决定的,奇数个节点能有效避免选举时出现平票僵局。
配置数据库:Nacos集群需要将元数据(如配置信息、用户权限)持久化到外部的共享数据库(如MySQL)。你需要创建一个数据库,并执行Nacos提供的SQL脚本来初始化表结构。
修改节点配置:在每个Nacos节点的 application.properties 文件中配置上一步骤的数据库连接信息。同时,在 cluster.conf 文件中列出集群内所有节点的IP地址和端口(默认为8848)。
启动与接入:逐台或同时启动所有Nacos节点。微服务应用在配置注册中心地址时,可以使用负载均衡器(如Nginx)作为统一的接入点。
集群核心工作原理
Nacos集群的设计巧妙之处在于其无中心化和数据一致性的保障。
无中心化与VIP:在生产环境中,通常不会让微服务直接连接某个特定的Nacos节点。相反,会使用一个虚拟IP(VIP) 或负载均衡器(如Nginx)作为统一的接入点,从而屏蔽后端节点的物理IP,实现客户端与集群细节的解耦。
数据一致性协议(Raft):Nacos集群采用 Raft一致性算法 来保证所有节点间数据的强一致性。该算法通过选举机制产生一个 Leader 节点,负责接收所有客户端的写请求(如服务注册、配置发布)。随后,Leader将数据变更同步给其他的 Follower 节点,只有大多数节点(过半)确认成功后,这次写操作才会被确认。这样可以确保即使单个节点故障,数据也不会丢失。
配置同步机制:对于配置中心的数据,变更时会先写入共享数据库,然后由Leader节点通知其他节点从数据库 dump 最新数据到本地文件缓存,以提高读取性能。
节点间的心跳监测:它们之间的健康感知和数据一致性是通过更底层的 Raft协议的心跳机制 来实现的。Leader节点会定期向所有Follower节点发送心跳消息(一种不包含数据内容的特殊AppendEntries RPC)这主要有两个目的:1、维持领导权:告知Follower自己仍然存活,防止触发新的选举。2、携带日志同步信息:在大多数情况下,心跳会附带日志信息,用于数据同步。如果一个Follower节点在超过选举超时时间(Election Timeout)后仍未收到Leader的心跳,它就会认为Leader已经宕机,并主动发起选举,尝试使自己成为新的Leader,以维持集群的可用性。
集群无中心化的坑
由于无中心化,微服务是配置的Nginx作为统一的接入点。Nginx作为负载均衡器默认是无状态的轮询,它本身无法区分哪个Nacos节点是Leader。
Nacos集群节点自身内置了一套强大的“请求转发”机制。Nacos集群的每个节点都非常清楚自己在Raft组中的角色(Leader或Follower)。当客户端的一个写请求(例如,服务注册、配置发布)通过Nginx被随机分配到一个Follower节点时,Follower节点不会处理这个请求,而是会立即向客户端返回一个特定的 HTTP 状态码(如 307 Temporary Redirect) 或一个包含错误码和信息的JSON响应。这个响应的核心内容是:“我不是Leader,当前的Leader地址是
http://leader-node-ip:8848”。当客户端收到这样的重定向响应后,客户端不会向用户抛出错误,而是自动地、透明地重新发起请求,这次直接请求Follower告诉它的那个Leader地址。
注意:
由于这种特性,Follower节点给出的Leader地址是内网的,无法被访问到外网。所以会导致集群无法正常访问。
Nacos设计时已经考虑到了这种网络隔离的场景。解决方案的核心是:让每个Nacos节点明确知道“客户端通过哪个公共地址来访问我”。这样,当Follower需要返回重定向信息时,它就不会返回自己的内网地址,而是返回这个配置好的公共地址。
需要在每个Nacos节点的配置文件中conf/application.properties,添加或修改以下参数:
properties
# Nacos的IP地址(客户端能访问到的IP,即Nginx的IP或域名)
nacos.inetutils.ip-address=your.nginx.public.ip
# Nacos的端口(客户端能访问到的端口,即Nginx监听的端口,通常是80/443/8848)
nacos.inetutils.port=8848
# 另一个更直接、更推荐的配置项是(高版本Nacos):
# 指定Nacos节点对外暴露的地址,格式为 ip:port
nacos.member.list=your.nginx.public.ip:8848Nacos的CAP模型
首先,需要理解CAP理论,它指出在一个分布式系统中,以下三者不可兼得:
- C(Consistency)一致性:所有节点在同一时间看到的数据是完全相同的。
- A(Availability)可用性:每个请求都能得到响应(不保证是最新数据)。
- P(Partition Tolerance)分区容错性:系统在网络分区情况下仍然能够正常工作。
🟢 AP模式(可用性 + 分区容错性)
特点:
✅ 高可用:所有请求都能得到响应,不会因为节点间通信问题而拒绝服务
✅ 低延迟:读写操作很快,因为不需要等待所有节点同步
⚠️ 最终一致性:不保证强一致性,数据在不同节点间可能存在短暂不一致,但最终会一致
理念、场景、Nacos体现:
- 核心理念:保证服务永远可用,即使这意味着不同节点可能暂时看到不同的数据。
- 典型应用场景:服务注册与发现、社交媒体的点赞数、评论数、电商网站的购物车。
- 在Nacos中的体现:当Nacos以AP模式运行时(默认的服务注册发现模式),服务实例可以向任意节点注册,节点间异步同步服务注册信息,即使部分节点宕机或网络分区,服务发现功能仍然可用。
🔵 CP模式(一致性 + 分区容错性)
特点:
✅ 强一致性:所有节点看到的数据完全相同
✅ 数据安全:不会出现数据冲突或丢失
⚠️ 可能牺牲可用性:在节点间通信失败时,为了保证一致性,系统可能拒绝写操作或部分读操作
理念、场景、Nacos体现:
- 核心理念:保证数据绝对一致,即使这意味着在某些情况下服务不可用。
- 典型应用场景:银行交易系统、配置信息管理、分布式锁服务。
- 在Nacos中的体现:当Nacos以CP模式运行时(默认的配置管理模式),使用Raft协议保证配置数据的一致性,写操作必须由Leader节点处理并同步到多数节点,在网络分区时,少数派分区可能无法提供写服务。
总结
- AP = 宁可暂时数据不一致,也要保证服务可用
- CP = 宁可暂时服务不可用,也要保证数据一致
选择建议:
- 对于服务注册发现,优先选择AP模式(Nacos默认)
- 对于配置管理,优先选择CP模式(Nacos默认)
根据业务场景的容忍度来决策:能接受短暂数据不一致选AP,要求数据绝对准确选CP
在Nacos中可以通过以下方式指定模式:
bash
# 创建使用AP模式的命名空间(默认)
curl -X POST 'http://localhost:8848/nacos/v1/ns/operator/switch?entry=serverMode&value=AP'
# 创建使用CP模式的命名空间
curl -X POST 'http://localhost:8848/nacos/v1/ns/operator/switch?entry=serverMode&value=CP'Nacos同时也支持在服务注册时指定:
java
// Spring Cloud Alibaba 示例
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public NamingService namingService() {
// 指定命名空间,对应不同的模式
Properties properties = new Properties();
properties.setProperty("serverAddr", "localhost:8848");
properties.setProperty("namespace", "您创建的命名空间ID");
return NamingFactory.createNamingService(properties);
}
}如何配置Nacos
在Spring Cloud项目里配置Nacos,主要是在 bootstrap.yml 文件中进行。这是因为应用启动时需要先连接到Nacos配置中心拉取外部配置,而 bootstrap.yml 的加载优先级高于 application.yml。
一个完整的 bootstrap.yml 配置文件通常如下所示:
yaml
server:
port: 8000
spring:
application:
name: your-service-name # 务必设置,它是构成Data ID的一部分
cloud:
nacos:
discovery:
server-addr: localhost:8848 # Nacos注册中心地址
config:
server-addr: localhost:8848 # Nacos配置中心地址
file-extension: yaml # 指定配置格式
namespace: your_namespace_id # 命名空间ID(添加后自动生成的一串uuid),用于环境隔离,不配置会连上默认的public空间
group: YOUR_GROUP_NAME # 配置分组,默认为DEFAULT_GROUP
profiles:
active: dev # 指定当前激活的环境Nacos通过 Data ID 来查找对应命名空间和分组下的配置,其默认生成规则是:${spring.application.name}-${spring.profiles.active}.${file-extension}
并且我们可以通过 Spring Cloud 原生注解 @RefreshScope 实现配置自动更新
实战配置Nacos
项目bootstrap.yml 配置:
yaml
server:
port: 80
spring:
application:
name: OMS
cloud:
nacos:
discovery:
server-addr: localhost:8848 # Nacos注册中心地址
config:
server-addr: localhost:8848 # Nacos配置中心地址
file-extension: yaml # 指定配置格式
namespace: 16fd2706-8baf-433b-82eb-8c7fada847da # XX项目的命名空间ID
group: OMS_GROUP # OMS分组,与WMS、TMS分组隔离
profiles:
active: prod # 指定当前激活的环境Nacos在对应命名空间和分组下创建一个配置文件,文件名为:OMS-prod.yaml,文件内容:
yaml
your:
config:
item: "Nacos配置中心"项目java代码读取配置:
java
import org.springframework.cloud.context.config.annotation.RefreshScope;
@RestController
@RefreshScope // 支持Nacos的动态刷新功能
public class MyController {
// 从Nacos中获取配置项
@Value("${your.config.item}")
private String configItem;
// ... 你的业务代码
}