Nacos
开篇:微服务的"通讯录"和"配置中心"
想象一个大公司,每个部门都有自己的电话。新员工入职时把电话登记到公司通讯录上,离职时从通讯录上删掉。任何人想找某个部门,查一下通讯录就知道该打哪个号码了。
这就是注册中心干的事——微服务的通讯录。
再想象一下:公司规定了各种制度(如报销标准、审批流程),如果每个部门自己保存一份,修改起来得挨个通知,费时费力。不如搞一个统一的"制度公告板",改了之后所有人都能实时看到。
这就是配置中心干的事——统一管理配置,动态生效。
Nacos(Dynamic Naming and Configuration Service) 是阿里开源的一站式解决方案,同时扮演了注册中心和配置中心两个角色。它和 Spring Cloud Alibaba 深度集成,是目前国内微服务架构的首选组件。
一、服务注册与发现
注册流程
当一个微服务(比如订单服务)启动时,发生了什么?
- 服务注册:启动时通过 Nacos 客户端向 Server 发送注册请求,包含服务名、IP、端口、集群名、元数据等信息
- 心跳保活:客户端每 5 秒发送一次心跳,告诉 Nacos "我还活着"
- 健康检测:Nacos Server 每 5 秒检查一次心跳。15 秒没收到心跳,标记为不健康并广播通知;30 秒没收到,直接移除实例
发现流程
消费者(比如网关服务)需要调用订单服务时:
- 首次查询:消费者向 Nacos 发起查询,获取目标服务的全量实例列表,缓存到本地
- 本地缓存调用:后续调用直接读本地缓存,根据负载均衡策略选择一个实例
- 定时拉取:每 10 秒从 Nacos 拉取最新列表,覆盖旧缓存
- 变更推送:当服务实例发生变化(上线/下线/健康状态变更),Nacos 通过 UDP 或 gRPC 主动推送到订阅的客户端,实现秒级更新
快速接入
1. 添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>2. 启动类添加注解
@SpringBootApplication
@EnableDiscoveryClient
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}3. 配置 application.yml
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 192.168.1.100:8848这样订单服务启动时就会自动注册到 Nacos。其他服务通过 order-service 这个名字就能找到它。
Distro 协议(AP 模式的数据同步)
Nacos 在 AP 模式下使用自研的 Distro 协议做数据同步,核心设计:
- 每个 Nacos 节点负责一部分写请求
- 新增数据同步给其他节点
- 定时发送数据校验值给其他节点,保持一致
- 每个节点独立处理读请求,从本地响应
- 新节点加入时全量拉取数据
这种设计保证了高可用——即使部分节点挂了,其余节点仍能正常提供服务。
二、配置中心
为什么需要配置中心?
在微服务架构中,几十个服务各自有一堆配置文件。改一个线程池大小就要改代码、提交、走发布流程。如果能有个统一的地方管配置,改了马上生效,该多好?
这就是 Nacos 配置中心要解决的问题。
核心概念:Namespace / Group / DataId
Nacos 用三层结构来组织配置:
Namespace(命名空间,如 dev/test/prod)
└── Group(分组,如 DEFAULT_GROUP)
└── DataId(配置文件标识,如 order-service.yml)- Namespace:用来做环境隔离,开发、测试、生产各一个
- Group:同一环境下的逻辑分组
- DataId:具体的配置文件,格式通常是
${spring.application.name}.${file-extension}
快速接入
1. 添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>2. 配置 bootstrap.yml
spring:
application:
name: order-service
profiles:
active: dev
cloud:
nacos:
config:
server-addr: 192.168.1.100:8848
file-extension: yml注意:配置中心的配置要写在 bootstrap.yml 中,因为它在 application.yml 之前加载。加载顺序:bootstrap.yml > application.yml > application-dev.yml
3. 使用 @RefreshScope 实现动态刷新
@RestController
@RefreshScope
public class ConfigController {
@Value("${order.timeout:3000}")
private int orderTimeout;
@GetMapping("/config")
public String getConfig() {
return "timeout=" + orderTimeout;
}
}在 Nacos 控制台修改 order.timeout 的值后,不用重启服务,接口返回的值就会自动更新。
配置变更感知:长轮询机制(1.x)
配置中心的核心问题是:配置改了,客户端怎么知道?
Nacos 1.x 使用长轮询(Long Polling) 机制,巧妙地平衡了实时性和性能:
长轮询的好处:
- 不像短轮询那样频繁请求服务端
- 不像长连接那样需要维护大量 TCP 连接
- 配置变更时能接近实时地感知到
Nacos 2.x:为什么引入 gRPC?
Nacos 1.x 的 HTTP 短连接模型在大规模集群下暴露了几个问题:
- 连接开销大:每次请求都创建销毁 TCP 连接,高 TPS 下大量 WAIT_TIME 连接
- 心跳风暴:服务规模大时(尤其是 Dubbo 接口级注册),心跳包数量巨大,系统资源空耗
- GC 压力:HTTP 长轮询模拟长连接,每 30 秒一次上下文切换造成内存浪费
- 感知延迟:心跳超时默认 15 秒才移除不健康实例,时效性差
Nacos 2.x 引入 gRPC 长连接,解决了这些问题:
- 真正的长连接,避免频繁创建销毁 TCP 连接
- TCP 连接断开能被快速感知,提升反应速度
- 客户端不再需要定时心跳,只需维持 keepalive
- 减少了大量重复的 TPS,服务端压力大幅降低
- 内存消耗显著下降,GC 问题解决
缺点是 gRPC 基于 HTTP/2 Stream,可观测性不如直接用 HTTP 那么直观。
三、Nacos vs Eureka vs Zookeeper
| 维度 | Nacos | Eureka | Consul | Zookeeper |
|---|---|---|---|---|
| CAP 模型 | CP + AP 双模式 | AP | CP | CP |
| 健康检查 | TCP/HTTP/心跳 | 心跳 | TCP/HTTP/gRPC | Keep Alive |
| 一致性算法 | JRaft + Distro | Gossip | Raft | ZAB |
| 雪崩保护 | 有 | 有 | 无 | 无 |
| 配置中心 | 内置 | 无 | KV 存储(弱) | 无(需自己实现) |
| 图形界面 | 有 | 有 | 有 | 无 |
| 维护状态 | 活跃 | 已停更 | 活跃 | 活跃 |
| 跨注册中心同步 | 支持 | 不支持 | 支持 | 不支持 |
| Dubbo 集成 | 支持 | 不支持 | 支持 | 支持 |
Nacos 为什么能同时支持 AP 和 CP?
因为 Nacos 有两个使用场景,需求不同:
- 注册中心:可用性更重要。注册中心一旦不可用,所有服务调用都会受影响。偶尔返回旧数据(某个已下线的服务还在列表里)可以接受,重试一下就好
- 配置中心:一致性更重要。不同机器收到不同的配置,这个不能接受。晚一点推送可以忍,但推送的内容必须一致
所以 Nacos 实现了两套协议:
- Distro 协议(AP):面向临时实例(注册中心场景),保证高可用
- JRaft 协议(CP):面向持久化数据(配置中心场景),保证强一致
可以通过配置切换模式。默认是 AP 模式。
选型建议
- 新项目首选 Nacos:注册+配置一站式,生态活跃,功能最全
- Eureka 不要再选了:SpringBoot 3.0 后不再维护
- 对一致性有极端要求:可以考虑 ZooKeeper 或 Consul
- 已经在用 ZK:如果团队熟悉 ZK 且满足需求,继续用也可以
四、常见面试题精选
Q1:Nacos 的服务注册和发现流程是怎样的?
注册:服务启动时通过 Nacos 客户端发送注册请求(服务名/IP/端口),注册后每 5 秒发心跳。Nacos Server 15 秒没收到心跳标记不健康,30 秒移除。
发现:消费者首次调用时查询服务列表并缓存到本地,每 10 秒定时拉取更新。同时 Nacos 在实例变更时通过 UDP/gRPC 主动推送,实现秒级更新。
Q2:Nacos 是 AP 的还是 CP 的?
都支持。默认是 AP 模式(Distro 协议),适合注册中心场景。可以切换到 CP 模式(JRaft 协议),适合需要强一致的场景。之所以同时支持,是因为注册中心和配置中心对一致性/可用性的要求不同。
Q3:Nacos 2.x 为什么引入 gRPC?
1.x 的 HTTP 短连接在大规模集群下有连接开销大、心跳风暴、GC 压力大、感知延迟长等问题。2.x 引入 gRPC 长连接,解决了这些问题,性能和稳定性大幅提升。
Q4:Nacos 配置变更客户端怎么感知?
1.x 用长轮询:客户端发起 30 秒超时的请求,Nacos 服务端如果没有变更就挂起,有变更或超时才返回。这样既避免了频繁轮询,又能接近实时地感知变更。2.x 用 gRPC 长连接,服务端直接推送。
小结
Nacos 是微服务架构中的基础设施,理解它需要把握以下要点:
- 注册中心的本质:服务上线注册、心跳保活、下线摘除、消费者订阅变更
- 配置中心的本质:集中管理 + 动态生效,用长轮询/gRPC 实现变更感知
- AP + CP 双模式:Distro 协议保可用性,JRaft 保一致性,按场景选择
- 2.x 的核心升级:gRPC 长连接取代 HTTP 短连接,解决大规模集群下的性能问题
- 选型首选 Nacos:注册+配置一站式,生态活跃,是当前国内微服务的事实标准