从入门到精通:Spring Cloud Alibaba Nacos 全方位深度解析(附源码)
关键词:Nacos, Spring Cloud Alibaba, 微服务, 注册中心, 配置中心, 源码解析
写在前面
微服务架构已成为现代分布式系统的主流选择,而服务注册与发现、配置管理是微服务架构中的核心组件。在 Spring Cloud Netflix 逐渐进入维护模式后,Spring Cloud Alibaba Nacos 凭借其强大的功能和优秀的性能,迅速成为微服务架构的首选解决方案。
本文将从 基础使用、源码解析、面试题 三个维度,全方位深度解析 Nacos,帮助你彻底掌握这一微服务神器。无论你是初学者还是进阶开发者,都能在本文中找到有价值的内容。
目录
一、微服务架构与 Nacos 简介
1.1 什么是微服务
微服务是由 Martin Fowler(马丁·福勒)于 2014 年提出的架构概念。微服务架构将单一应用程序拆分成一组小的服务,每个服务运行在自己的进程中,服务之间通过轻量级的通信机制(通常是 HTTP API)进行交互。
微服务的核心特点:
- 服务独立部署和扩展
- 服务间松耦合
- 技术栈多样化
- 围绕业务能力组织团队
1.2 架构演变历程
互联网系统架构经历了以下演变过程:
单体应用架构
将所有功能集中在一个应用中,统一部署。
- 优点:架构简单,适合用户量少的项目
- 缺点:模块紧耦合,单点容错率低
垂直应用架构
将单体应用拆分为多个独立应用。
- 优点:实现流量分担,可针对性优化
- 缺点:系统间无法相互调用,功能冗余
分布式架构
抽取公共功能作为服务层,提高代码复用。
- 优点:代码复用性高
- 缺点:调用关系复杂,难以维护
SOA 架构
引入服务治理中心(ESB/Dubbo)解决调用关系问题。
- 优点:自动调节服务间调用关系
- 缺点:服务依赖复杂,运维困难
微服务架构
彻底拆分服务,强调独立部署、互不影响。
- 优点:原子化拆分,利于扩展
- 缺点:技术成本高(容错、分布式事务等)
1.3 Spring Cloud Alibaba 生态
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案,主要功能包括:
| 组件 | 功能 |
|---|---|
| Nacos | 服务注册发现与配置管理 |
| Sentinel | 流量控制、熔断降级 |
| RocketMQ | 分布式消息系统 |
| Dubbo | 高性能 RPC 框架 |
| Seata | 分布式事务解决方案 |
版本说明(课程使用版本):
- Spring Cloud: 2020.0.1
- Spring Cloud Alibaba: 2021.1
- Spring Boot: 2.4.2
- Nacos Server: 2.2.3
二、Nacos 基础实战
2.1 Nacos 简介与核心概念
Nacos(Naming Configuration Service)是一个易于使用的动态服务发现、配置管理和服务管理平台。
核心功能:
- 服务注册中心 - 替代 Eureka
- 配置中心 - 替代 Spring Cloud Config
支持的服务类型:
- Kubernetes Service
- gRPC & Dubbo RPC Service
- Spring Cloud RESTful Service
为什么需要注册中心?
以酒店前台为例:
- 没有前台:客人需要逐个房间寻找,效率低下
- 有前台:可入住房间登记在前台,客人快速查询入住
服务提供者(酒店房间)在注册中心(前台)登记,服务消费者(客人)通过注册中心快速发现服务。
2.2 Nacos 安装与启动
下载安装
官网地址:https://nacos.io/zh-cn/index.html
GitHub 下载:https://github.com/alibaba/nacos/releases
启动命令
Linux/Unix/Mac:
sh startup.sh -m standalone
Windows:
startup.cmd -m standalone
访问控制台
启动成功后访问:http://localhost:8848/nacos
默认账号密码:nacos/nacos
持久化配置
Nacos 默认使用嵌入式 Derby 数据库,生产环境建议切换为 MySQL:
- 修改
application.properties:
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8
db.user.0=root
db.password.0=root
-
执行
conf/nacos-mysql.sql初始化数据库 -
重启服务
2.3 服务注册与发现
创建父项目
<properties>
<spring-cloud-alibaba-version>2021.1</spring-cloud-alibaba-version>
<spring-cloud.version>2020.0.1</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
服务提供者
添加依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置文件(application.yml):
server:
port: 9001
spring:
application:
name: nacos-provider
cloud:
discovery:
server-addr: 127.0.0.1:8848
启动类:
@EnableDiscoveryClient
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
提供接口:
@RestController
public class DemoController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/hello")
public String hello() {
return "Hello Nacos Discovery " + serverPort;
}
}
服务消费者
配置文件:
server:
port: 9101
spring:
application:
name: nacos-consumer
cloud:
discovery:
server-addr: localhost:8848
service-url:
nacos-user-service: http://nacos-provider
RestTemplate 配置:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
调用服务:
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Value("${service-url.nacos-user-service}")
private String serverURL;
@GetMapping("/consumer/hello")
public String hello() {
return restTemplate.getForObject(serverURL + "/hello", String.class);
}
}
OpenFeign 服务调用
添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
创建 Feign 接口:
@FeignClient(name = "nacos-provider")
public interface ProviderService {
@GetMapping("/hello")
String hello();
}
启动类添加注解:
@EnableFeignClients(basePackages = "com.example.feign")
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
使用 Feign 调用:
@RestController
public class ConsumerController {
@Autowired
private ProviderService providerService;
@GetMapping("/consumer/feign")
public String helloByFeign() {
return providerService.hello();
}
}
2.4 配置中心使用
添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
配置文件
bootstrap.yml(高优先级):
server:
port: 3377
spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yaml
application.yml:
spring:
profiles:
active: dev # 开发环境
Data ID 命名规则
${prefix}-${spring.profiles.active}.${file-extension}
例如:nacos-config-client-dev.yaml
动态配置刷新
@RestController
@RefreshScope // 支持 Nacos 动态刷新
public class ConfigController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/config/info")
public String getConfigInfo() {
return configInfo;
}
}
多环境配置管理
命名空间(Namespace):用于环境隔离(dev/test/prod)
配置分组(Group):用于分类管理配置(DB_GROUP/MYBATIS_GROUP)
Data ID:具体的配置文件标识
三者关系:Namespace > Group > Data ID
2.5 集群搭建
集群结构
- 3 个 Nacos 注册中心节点
- 1 个 MySQL 数据库
集群配置
-
配置 MySQL 持久化(同单机版)
-
配置集群节点(cluster.conf):
192.168.1.111:8848
192.168.1.111:8868
192.168.1.111:8888
- Nginx 负载均衡配置:
upstream nacos {
server 192.168.1.111:8848;
server 192.168.1.111:8868;
server 192.168.1.111:8888;
}
server {
listen 80;
server_name 192.168.1.111;
location / {
proxy_pass http://nacos;
}
}
三、Nacos 源码深度解析
3.1 服务注册原理
客户端注册流程
入口:NacosServiceRegistryAutoConfiguration
核心方法:NacosServiceRegistry.register()
public void register(Registration registration) {
// 获取 NamingService
NamingService namingService = this.namingService();
String serviceId = registration.getServiceId();
String group = this.nacosDiscoveryProperties.getGroup();
// 封装实例信息
Instance instance = this.getNacosInstanceFromRegistration(registration);
// 执行注册
namingService.registerInstance(serviceId, group, instance);
}
实例信息封装:
private Instance getNacosInstanceFromRegistration(Registration registration) {
Instance instance = new Instance();
instance.setIp(registration.getHost());
instance.setPort(registration.getPort());
instance.setWeight(nacosDiscoveryProperties.getWeight());
instance.setClusterName(nacosDiscoveryProperties.getClusterName());
instance.setEphemeral(nacosDiscoveryProperties.isEphemeral());
return instance;
}
发送注册请求:
public void registerInstance(String serviceName, String groupName, Instance instance) {
// 临时实例开启心跳定时任务
if (instance.isEphemeral()) {
BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
beatReactor.addBeatInfo(groupedServiceName, beatInfo);
}
// 发送 HTTP 注册请求:/nacos/v1/ns/instance
serverProxy.registerService(groupedServiceName, groupName, instance);
}
服务端注册处理
接口:InstanceController.register()
处理流程:
- 获取 namespaceId、serviceName、instance 信息
- 创建客户端连接(createIpPortClientIfAbsent)
- 执行注册(clientOperationService.registerInstance)
- 发布注册事件(NotifyCenter.publishEvent)
- 存储到
publisherIndexes(ConcurrentHashMap)
// 注册服务存储结构
private final ConcurrentMap<Service, Set<String>> publisherIndexes = new ConcurrentHashMap<>();
private void addPublisherIndexes(Service service, String clientId) {
publisherIndexes.computeIfAbsent(service, key -> new ConcurrentHashSet<>());
publisherIndexes.get(service).add(clientId);
// 发布服务变更事件
NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, true));
}
3.2 心跳机制与健康检查
客户端心跳发送
临时实例启动定时任务发送心跳:
public void addBeatInfo(String serviceName, BeatInfo beatInfo) {
String key = buildKey(serviceName, beatInfo.getIp(), beatInfo.getPort());
dom2Beat.put(key, beatInfo);
// 开启定时任务,默认间隔 15 秒
executorService.schedule(new BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit.MILLISECONDS);
}
心跳任务:
@Override
public void run() {
// 发送心跳请求
JsonNode result = serverProxy.sendBeat(beatInfo, lightBeatEnabled);
// 如果服务不存在,重新注册
int code = result.get(CommonParams.CODE).asInt();
if (code == NamingResponseCode.RESOURCE_NOT_FOUND) {
Instance instance = new Instance();
// ... 设置实例信息
serverProxy.registerService(beatInfo.getServiceName(), groupName, instance);
}
// 继续下一次心跳
executorService.schedule(new BeatTask(beatInfo), nextTime, TimeUnit.MILLISECONDS);
}
服务端心跳处理
接口:InstanceController.beat()
核心逻辑:
public int handleBeat(String namespaceId, String serviceName, String ip, int port,
String cluster, RsInfo clientBeat, BeatInfoInstanceBuilder builder) {
// 获取客户端
String clientId = IpPortBasedClient.getClientId(ip + InternetAddressUtil.IP_PORT_SPLITER + port, true);
IpPortBasedClient client = (IpPortBasedClient) clientManager.getClient(clientId);
// 如果客户端不存在,基于心跳信息创建
if (null == client) {
Instance instance = builder.setBeatInfo(clientBeat).build();
registerInstance(namespaceId, serviceName, instance);
}
// 处理心跳信息
ClientBeatProcessorV2 beatProcessor = new ClientBeatProcessorV2(namespaceId, clientBeat, client);
HealthCheckReactor.scheduleNow(beatProcessor);
return NamingResponseCode.OK;
}
心跳处理器:
@Override
public void run() {
HealthCheckInstancePublishInfo instance = (HealthCheckInstancePublishInfo) client
.getInstancePublishInfo(service);
// 检查服务一致性
if (instance.getIp().equals(ip) && instance.getPort() == port) {
// 更新最后心跳时间
instance.setLastHeartBeatTime(System.currentTimeMillis());
// 如果服务不健康,更新为健康状态
if (!instance.isHealthy()) {
instance.setHealthy(true);
// 发布服务状态变更事件
NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service));
}
}
}
服务端健康检查
临时实例检查:每 5 秒执行一次
public void init() {
if (ephemeral) {
// 临时实例:客户端心跳超时检测
beatCheckTask = new ClientBeatCheckTaskV2(this);
HealthCheckReactor.scheduleCheck(beatCheckTask);
} else {
// 持久实例:服务端主动探测
healthCheckTaskV2 = new HealthCheckTaskV2(this);
HealthCheckReactor.scheduleCheck(healthCheckTaskV2);
}
}
健康检查逻辑:
private boolean isUnhealthy(Service service, HealthCheckInstancePublishInfo instance) {
// 获取超时时间,默认 15 秒
long beatTimeout = getTimeout(service, instance);
// 超过超时时间则认为不健康
return System.currentTimeMillis() - instance.getLastHeartBeatTime() > beatTimeout;
}
持久实例检查:通过 HTTP 请求主动探测
@Override
public void process(HealthCheckTaskV2 task, Service service, ClusterMetadata metadata) {
// 拼接探测地址
URL target = new URL(HTTP_PREFIX + instance.getIp() + ":" + ckPort + healthChecker.getPath());
// 发送 HTTP 健康检查请求
ASYNC_REST_TEMPLATE.get(target.toString(), header, Query.EMPTY, String.class,
new HttpHealthCheckCallback(instance, task, service));
}
3.3 服务订阅与发现
客户端订阅流程
入口:NacosDiscoveryClient.getInstances()
public List<ServiceInstance> getInstances(String serviceId) throws NacosException {
String group = this.discoveryProperties.getGroup();
// 获取服务实例列表
List<Instance> instances = this.namingService().selectInstances(serviceId, group, true);
return hostToServiceInstanceList(instances, serviceId);
}
获取服务信息:
public ServiceInfo getServiceInfo(final String serviceName, final String clusters) {
// 1. 从缓存获取
ServiceInfo serviceObj = getServiceInfo0(serviceName, clusters);
if (null == serviceObj) {
// 2. 缓存没有,从服务端获取
updateServiceNow(serviceName, clusters);
}
// 3. 开启定时更新任务
scheduleUpdateIfAbsent(serviceName, clusters);
return serviceInfoMap.get(serviceObj.getKey());
}
服务端处理订阅
接口:InstanceController.list()
@GetMapping("/list")
public Object list(HttpServletRequest request) throws Exception {
// 创建订阅者对象
Subscriber subscriber = new Subscriber(clientIP + ":" + udpPort, agent, app,
clientIP, namespaceId, serviceName, udpPort, clusters);
// 获取服务列表
return getInstanceOperator().listInstance(namespaceId, serviceName, subscriber, clusters, healthyOnly);
}
订阅处理:
@Override
public ServiceInfo listInstance(String namespaceId, String serviceName, Subscriber subscriber,
String cluster, boolean healthOnly) {
Service service = getService(namespaceId, serviceName, true);
// 如果是订阅请求,建立订阅关系
if (subscriber.getPort() > 0 && pushService.canEnablePush(subscriber.getAgent())) {
clientOperationService.subscribeService(service, subscriber, clientId);
}
// 获取服务信息
ServiceInfo serviceInfo = serviceStorage.getData(service);
return ServiceUtil.selectInstancesWithHealthyProtection(serviceInfo, serviceMetadata,
cluster, healthOnly, true, subscriber.getIp());
}
服务变更推送
UDP 推送:Nacos 1.x 使用 UDP 主动推送服务变更
@Override
public void onEvent(Event event) {
if (event instanceof ServiceEvent.ServiceChangedEvent) {
ServiceEvent.ServiceChangedEvent serviceChangedEvent = (ServiceEvent.ServiceChangedEvent) event;
Service service = serviceChangedEvent.getService();
// 延迟推送任务
delayTaskEngine.addTask(service, new PushDelayTask(service, PushConfig.getInstance().getPushTaskDelay()));
}
}
3.4 配置中心原理
客户端获取配置
入口:NacosConfigService.getConfig()
private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) {
// 1. 优先从本地缓存获取
String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);
if (content != null) {
return content;
}
try {
// 2. 从服务端获取
String[] ct = worker.getServerConfig(dataId, group, tenant, timeoutMs);
return ct[0];
} catch (NacosException ioe) {
// 3. 服务端失败,从本地快照获取
content = LocalConfigInfoProcessor.getSnapshot(agent.getName(), dataId, group, tenant);
return content;
}
}
服务端查询:ConfigController.getConfig()
长轮询机制
Nacos 使用长轮询(Long Polling)实现配置的实时更新:
客户端:
// 检查配置更新
List<String> changedGroupKeys = checkUpdateDataIds(cacheDatas, inInitializingCacheList);
for (String groupKey : changedGroupKeys) {
// 获取变更的配置内容
String content = getServerConfig(dataId, group, tenant, 3000L);
// 更新本地缓存
cache.setContent(content);
}
// 继续下一次轮询
executorService.execute(this);
长轮询请求:
List<String> checkUpdateConfigStr(String probeUpdateString, boolean isInitializingCacheList) {
List<String> headers = new ArrayList<>();
headers.add("Long-Pulling-Timeout");
headers.add("" + timeout); // 默认 30 秒
// 发送长轮询请求
HttpResult result = agent.httpPost(Constants.CONFIG_CONTROLLER_PATH + "/listener",
headers, params, agent.getEncode(), timeout);
if (HttpURLConnection.HTTP_OK == result.code) {
return parseUpdateDataIdResponse(result.content);
}
return Collections.emptyList();
}
服务端处理:ConfigServletInner.doPollingConfig()
public String doPollingConfig(HttpServletRequest request, HttpServletResponse response,
Map<String, String> clientMd5Map, int probeRequestSize) {
if (LongPollingService.isSupportLongPolling(request)) {
// 添加长轮询客户端
longPollingService.addLongPollingClient(request, response, clientMd5Map, probeRequestSize);
return HttpServletResponse.SC_OK + "";
}
// ... 兼容短轮询逻辑
}
长轮询客户端:
public void addLongPollingClient(HttpServletRequest req, HttpServletResponse rsp,
Map<String, String> clientMd5Map, int probeRequestSize) {
// 提前 500ms 返回,避免客户端超时
long timeout = Math.max(10000, Long.parseLong(str) - delayTime);
// 先检查是否有变更
List<String> changedGroups = MD5Util.compareMd5(req, rsp, clientMd5Map);
if (changedGroups.size() > 0) {
generateResponse(req, rsp, changedGroups);
return;
}
// 无变更,开启异步处理
final AsyncContext asyncContext = req.startAsync();
asyncContext.setTimeout(0L);
// 提交长轮询任务
ConfigExecutor.executeLongPolling(
new ClientLongPolling(asyncContext, clientMd5Map, ip, probeRequestSize, timeout, appName, tag));
}
配置变更通知:
@Override
public void onEvent(Event event) {
if (event instanceof LocalDataChangeEvent) {
LocalDataChangeEvent evt = (LocalDataChangeEvent) event;
// 执行数据变更任务
scheduler.execute(new DataChangeTask(evt.groupKey, evt.isBeta, evt.betaIps));
}
}
3.5 Nacos 2.x 架构升级
Nacos 1.x 问题
- 心跳数量多,TPS 高 - 大量心跳和元数据轮询
- 心跳感知变化慢 - 默认 15 秒超时,时效性差
- UDP 推送不可靠 - 客户端需要频繁对账查询
- HTTP 短连接问题 - 大量 TIME_WAIT 状态连接
- 30 秒长轮询 GC 问题 - 频繁的上下文切换和内存浪费
Nacos 2.x 改进
基于 gRPC 的长连接架构:
| 特性 | Nacos 1.x | Nacos 2.x |
|---|---|---|
| 协议 | HTTP 1.1 | gRPC (HTTP/2) |
| 连接 | 短连接 | 长连接 |
| 心跳 | 客户端定时发送 | 长连接 keepalive |
| 推送 | UDP | 双向流推送 |
| 性能 | 较低 | 提升 10 倍 |
优点:
- 降低 TPS:不再需要频繁心跳
- 快速感知:TCP 连接断开立即感知
- 可靠推送:基于 HTTP/2 的双向流
- 减少连接:长连接避免 TIME_WAIT
- 降低 GC:真实长连接解决配置模块 GC 问题
客户端源码核心:
// NamingGrpcClientProxy - gRPC 客户端代理
public class NamingGrpcClientProxy extends NamingClientProxy {
private final RpcClient rpcClient;
@Override
public void registerService(String serviceName, String groupName, Instance instance) {
// 构建 gRPC 请求
InstanceRequest request = new InstanceRequest(namespaceId, serviceName, groupName,
NamingRequestType.REGISTER_INSTANCE, instance);
// 发送 gRPC 请求
requestToServer(request, Response.class);
}
}
四、Nacos 面试题精选
Q1: Nacos 为什么选择 gRPC?
- HTTP 1.x 短板:无多路复用、Header 冗余、队头阻塞
- Nacos 1.x 影响:高 TPS、大量连接、UDP 不可靠
- gRPC 优势:
- HTTP/2 多路复用
- Header 压缩(HPACK)
- Protobuf 高效序列化
- 长连接双向流
Q2: Nacos 中的保护阈值是什么?
保护阈值(0-1)用于防止服务雪崩:
- 设置阈值为 0.5
- 当健康实例少于 50% 时
- 消费者会拉取所有实例(包括不健康)
- 保证至少部分请求能正常处理
Q3: Nacos 的负载均衡是如何工作的?
Nacos 提供服务端负载均衡:
- 消费者拉取服务列表时
- Nacos 可根据随机策略返回部分实例
- 减少网络传输和客户端内存占用
- Ribbon/LoadBalancer 在其基础上进行二次负载均衡
Q4: Nacos 的就近访问是什么?
基于 Cluster Name 的就近路由:
- 给实例设置 cluster-name(如:beijing/shanghai)
- 消费者优先调用同集群的服务实例
- 减少跨机房/跨地域的网络延迟
Q5: Nacos 保证 CP 还是 AP?
Nacos 支持CP 和 AP 切换:
- 临时实例(默认):AP 模式,使用 Distro 协议
- 持久实例:CP 模式,使用 Raft 协议
- 配置中心:数据存储在 MySQL,不涉及 CAP
# 切换为 CP 模式
curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'
Q6: Nacos 如何判断服务实例状态?
-
心跳检测(临时实例):
- 客户端每 15 秒发送心跳
- 服务端超过 15 秒未收到标记为不健康
- 超过 30 秒移除实例
-
健康检查(持久实例):
- 服务端主动发送 HTTP/TCP 探测
- 根据返回结果判断健康状态
-
负载均衡:
- 根据实例负载情况动态调整
Q7: Nacos 1.x 注册中心架构流程
┌─────────────┐ 1.服务注册 ┌─────────────┐
│ Provider │ ─────────────────> │ Nacos │
└─────────────┘ └──────┬──────┘
│ │
│ 5.心跳(每5秒) │ 6.健康检查(每5秒)
│ │
└────────────────────────────────> │
│
┌─────────────┐ 2.服务发现 ┌─────┴──────┐
│ Consumer │ ─────────────────> │ │
└─────────────┘ │ │
│ │ │
│ 3.定时拉取(每10秒) │ │
│ │ │
│ <──────────────────────── │ │
│ │ │
│ 4.UDP推送(服务变更) │ │
│ <──────────────────────── │ │
└────────────┘
Q8: Nacos 中的 Distro 协议
Distro 是 Nacos 自研的 AP 分布式协议:
设计思想:
- 每个节点平等:都可处理写请求,同步数据到其他节点
- 数据分片:每个节点负责部分数据
- 定时校验:发送校验值保持数据一致性
- 独立读请求:从本地直接响应
五、总结与展望
本文从基础使用、源码解析、面试题三个维度全面解析了 Spring Cloud Alibaba Nacos:
核心知识点回顾
-
服务注册与发现:
- 客户端通过
NacosServiceRegistry注册服务 - 服务端存储在
publisherIndexes(ConcurrentHashMap) - 支持临时实例(AP)和持久实例(CP)
- 客户端通过
-
心跳与健康检查:
- 临时实例:客户端定时发送心跳(15秒)
- 持久实例:服务端主动探测(HTTP/TCP)
- 超时机制:15秒标记不健康,30秒移除
-
配置中心:
- 本地缓存优先,服务端兜底
- 长轮询机制实现实时更新(30秒超时)
- Data ID 命名规则:
${prefix}-${profile}.${extension}
-
架构演进:
- Nacos 1.x:HTTP 短连接 + UDP 推送
- Nacos 2.x:gRPC 长连接 + 双向流推送
- 性能提升 10 倍
学习建议
- 动手实践:搭建 Nacos 集群,实现服务注册、配置管理
- 阅读源码:重点阅读
nacos-naming和nacos-config模块 - 关注面试题:理解 CAP 原理、心跳机制、长轮询等核心概念
- 跟进版本:Nacos 2.x 是趋势,建议优先学习
相关资源
- 官方文档:https://nacos.io/zh-cn/docs/what-is-nacos.html
- GitHub:https://github.com/alibaba/nacos
- Spring Cloud Alibaba:https://github.com/alibaba/spring-cloud-alibaba
如果本文对你有帮助,欢迎点赞、收藏、关注!如有疑问,欢迎在评论区留言讨论。
关键词:Nacos, Spring Cloud Alibaba, 微服务, 注册中心, 配置中心, 源码解析, Java, 分布式系统
本文基于 Nacos 2.2.3 + Spring Cloud Alibaba 2021.1 整理,持续更新中…
更多推荐


所有评论(0)