目录

一、Nacos 核心定位与整体架构

1. 核心定位

2. 整体架构

二、Nacos 服务注册发现实战与底层源码解析

1. Spring Cloud Alibaba 整合实战

第一步:引入依赖

第二步:应用配置

第三步:启动类与服务调用

2. 核心概念:临时实例 vs 持久实例

3. 服务注册完整流程源码级拆解

客户端核心源码

服务端核心源码

4. 健康检查与剔除机制

5. 服务发现与本地缓存

三、Nacos 配置中心实战与底层源码解析

1. 配置中心三级模型

2. Spring Cloud 整合实战

第一步:引入依赖

第二步:bootstrap 配置

第三步:动态刷新代码示例

3. 配置加载完整流程

4. 长轮询动态推送原理

客户端核心逻辑

服务端核心逻辑

四、Nacos 集群架构与一致性原理

1. 集群部署架构

2. 双一致性协议设计

3. Distro 协议(AP 模式)

4. Raft 协议(CP 模式)

五、实战踩坑与最佳实践

1. 服务注册发现常见踩坑

2. 配置中心常见踩坑

3. 生产最佳实践

六、面试速记总结


基于 Spring Cloud Alibaba 2.2.x + Nacos 2.x 实操学习

一、Nacos 核心定位与整体架构

1. 核心定位

Nacos(Dynamic Naming and Configuration Service)是阿里开源的一站式微服务基础设施,同时承担服务注册发现动态配置管理两大核心能力,替代了传统 Spring Cloud 技术栈中 Eureka + Spring Cloud Config + Spring Cloud Bus 的组合,是 Spring Cloud Alibaba 生态的核心组件。 它的核心优势在于:

  • 双能力合一:服务治理与配置管理共用一套集群,降低运维成本
  • 双一致性模式:支持 AP 高可用模式与 CP 强一致模式灵活切换
  • 生产级验证:经过阿里双十一场景验证,支持十万级服务实例规模
  • 开箱即用:提供可视化控制台,支持权限控制、配置版本、灰度发布等运维能力

2. 整体架构

架构分层说明:

  • 接入层:客户端通过 HTTP/gRPC 协议与服务端交互,支持多语言 SDK
  • 核心功能层:命名服务负责服务注册发现、健康检查;配置服务负责配置存储、推送、版本管理
  • 一致性协议层:根据场景选择不同协议,保证分布式下的数据一致性
  • 存储层:默认内置 Derby 数据库,生产环境推荐外接 MySQL 实现持久化

二、Nacos 服务注册发现实战与底层源码解析

1. Spring Cloud Alibaba 整合实战

第一步:引入依赖
<!-- Spring Cloud Alibaba 版本统一管理 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.9.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- Nacos 服务注册发现启动器 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
第二步:应用配置
spring:
  application:
    name: order-service  # 服务名,注册到Nacos的唯一标识
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848  # Nacos服务端地址
        namespace: dev_123456        # 命名空间,用于环境隔离
        group: business-order        # 分组,用于业务模块隔离
        ephemeral: true              # 是否为临时实例,默认true
        weight: 1                    # 实例权重,用于流量分配
        metadata:                    # 自定义元数据,可用于灰度、路由
          version: v1.0
          env: dev
第三步:启动类与服务调用
@SpringBootApplication
@EnableDiscoveryClient  // 开启服务注册发现能力,Spring Cloud 高版本可省略
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }

    // 注入RestTemplate,结合Ribbon实现负载均衡调用
    // 先不使用OpenFeign
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

2. 核心概念:临时实例 vs 持久实例

Nacos 将服务实例分为两类,对应不同的一致性与健康检查策略:

类型 默认值 健康检查方式 宕机处理 一致性模式 适用场景
临时实例 客户端主动心跳上报 15s 无心跳标记不健康,30s 自动剔除 AP 模式(Distro 协议) 常规微服务实例,弹性扩缩容
持久实例 服务端主动探活检查 仅标记不健康,不会自动剔除 CP 模式(Raft 协议) 数据库、缓存、中间件等固定服务

3. 服务注册完整流程源码级拆解

客户端核心源码

注册入口在 NacosNamingService,核心逻辑是组装实例参数后发送 HTTP 请求到服务端,注册成功后立即启动心跳任务。

// com.alibaba.nacos.client.naming.NacosNamingService
@Override
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    // 1. 校验参数,组装服务全名
    String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
    // 2. 临时实例必须开启心跳
    if (instance.isEphemeral()) {
        BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
        // 添加心跳任务,默认5秒执行一次
        beatReactor.addBeatInfo(groupedServiceName, beatInfo);
    }
    // 3. 发送HTTP POST请求,调用服务端注册接口
    serverProxy.registerService(groupedServiceName, groupName, instance);
}
服务端核心源码

服务端通过 InstanceController 接收注册请求,最终写入 ServiceManager 的内存注册表中。

// com.alibaba.nacos.naming.core.ServiceManager
public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {
    // 1. 服务不存在则创建空服务
    emptyService(namespaceId, serviceName, instance.isEphemeral());
    Service service = getService(namespaceId, serviceName);
    
    synchronized (service) {
        // 2. 将实例添加到对应服务的实例列表中
        addInstance(namespaceId, serviceName, instance.isEphemeral(), instance);
    }
    
    // 3. 临时实例触发异步集群同步
    if (instance.isEphemeral()) {
        distroProtocol.sync(new DistroKey(serviceName, instance.getIp() + "#" + instance.getPort(),
                KeyBuilder.INSTANCE_LIST_KEY_PREFIX), DataOperation.CHANGE,
                DistroConfig.getInstance().getSyncDelayMillis());
    }
}

注册表底层结构:采用双层 ConcurrentHashMap 实现,线程安全且查询性能极高。

Map<namespaceId, Map<groupedServiceName, Service>> serviceMap

- 第一层:按命名空间隔离

- 第二层:按服务名隔离 - Service 对象内部维护集群列表、实例列表、健康检查器等核心数据

4. 健康检查与剔除机制

  • 客户端心跳:临时实例启动后台 BeatTask 线程,默认每 5 秒向服务端发送一次心跳包,更新最后心跳时间。
  • 服务端剔除:服务端后台定时任务每 5 秒扫描所有实例,15 秒未收到心跳的实例标记为不健康,30 秒未收到心跳的临时实例直接从注册表移除。
  • 持久实例探活:服务端主动发起 TCP/HTTP 探活,失败仅标记不健康,不会自动删除,需要人工下线。

5. 服务发现与本地缓存

客户端获取服务列表采用「定时全量拉取 + 事件订阅 + 本地缓存」的三级机制:

  1. 客户端启动时主动拉取一次全量服务列表,存入本地内存
  2. 后台定时任务默认每 10 秒拉取一次,更新本地缓存
  3. 支持 UDP 推送,服务端实例变更时主动通知客户端
  4. 本地同时生成快照文件缓存到磁盘,即使 Nacos 全挂、客户端重启,也能读取缓存保证服务调用可用

生产意义:这是 Nacos 高可用设计的关键,注册中心故障不会影响已有服务的正常调用,仅影响新服务注册和实例变更。

三、Nacos 配置中心实战与底层源码解析

1. 配置中心三级模型

Nacos 配置管理采用 Namespace + Group + DataId 的三级结构,实现多层级隔离:

  • Namespace 命名空间:最顶层隔离,用于区分开发、测试、生产等环境,不同命名空间下配置完全不可见
  • Group 分组:中间层隔离,用于区分不同业务线、不同项目,默认值为 DEFAULT_GROUP
  • DataId 数据 ID:具体的配置文件,通常对应一个应用的配置,格式支持 yaml、properties 等

2. Spring Cloud 整合实战

第一步:引入依赖
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
第二步:bootstrap 配置

配置中心的配置必须在 Spring 上下文刷新前加载,因此要写在 bootstrap.yml 中,优先级高于 application.yml。

spring:
  application:
    name: user-service
  profiles:
    active: dev
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        namespace: dev_123456
        group: business-user
        file-extension: yaml  # 配置文件后缀,对应dataId拼接规则
        # 共享配置:多个应用共用的公共配置
        shared-configs:
          - data-id: common-db.yaml
            group: common-group
            refresh: true  # 是否支持动态刷新
        # 扩展配置:额外引入的第三方配置
        extension-configs:
          - data-id: redis-config.yaml
            group: middleware-group
            refresh: true

DataId 完整拼接规则:${spring.application.name}-${spring.profiles.active}.${file-extension}

当 user-service 应用启动时,Nacos 客户端默认会去 Nacos 服务端查找名为 user-service-dev.yaml 的配置文件,并将其作为该应用独有的主配置拉取下来。

这个规则解决了多环境隔离多服务区分的问题:

  • 区分服务(${spring.application.name}user-service 和 order-service 即使都激活 dev 环境,也会分别拉取 user-service-dev.yaml 和 order-service-dev.yaml,互不干扰。

  • 区分环境(${spring.profiles.active}:同一个 user-service,在 dev 环境拉取 user-service-dev.yaml,在 prod 环境拉取 user-service-prod.yaml。这样就不需要改代码,只需启动时指定 -Dspring.profiles.active=prod,就能自动切换数据库连接、日志级别等配置。

  • 区分格式(${file-extension}:支持 yaml 或 properties,客户端根据后缀自动解析。

主配置,和之前的 shared-configs / extension-configs 关系:

配置类型 对应的 DataId 示例 作用范围 优先级(值覆盖)
主配置(上面公式) user-service-dev.yaml 当前服务 + 当前环境 专属的业务配置 最高(最后加载)
extension-configs redis-config.yaml 当前服务引入的中间件专项配置 中等
shared-configs common-db.yaml 所有服务通用的底层配置 最低(最先加载)
第三步:动态刷新代码示例
@RestController
@RequestMapping("/config")
@RefreshScope // 开启该类配置的动态刷新,变更后自动重建Bean
public class ConfigTestController {

    @Value("${user.config.nickname:default}")
    private String nickname;

    @Value("${user.config.max-count:100}")
    private Integer maxCount;

    @GetMapping("/test")
    public String getConfig() {
        return "昵称:" + nickname + ",最大次数:" + maxCount;
    }
}

@RefreshScope 原理解析: 加了该注解的 Bean 会被放入专门的 RefreshScope 缓存中。配置变更时,Spring 会清空这个缓存,下次访问该 Bean 时会重新创建实例,新实例会注入最新的配置值,从而实现动态刷新。

3. 配置加载完整流程

4. 长轮询动态推送原理

Nacos 配置中心没有用 WebSocket 等长连接技术,而是采用长轮询 + MD5 比对的方案,兼顾实时性与性能。

客户端核心逻辑

ClientWorker 类内部维护 LongPollingRunnable 线程,循环执行以下逻辑:

  1. 客户端携带本地所有配置的 MD5 值,向服务端发起 HTTP 请求,超时时间设置为 30 秒
  2. 服务端比对 MD5,如果有配置变更,立即返回变更的 DataId 列表
  3. 如果 30 秒内没有配置变更,服务端在超时前返回空响应
  4. 客户端收到响应后,立即发起下一次长轮询请求
  5. 客户端拿到变更的 DataId 后,单独拉取最新配置,更新本地环境
// com.alibaba.nacos.client.config.impl.ClientWorker.LongPollingRunnable
@Override
public void run() {
    // 1. 检查本地配置MD5,组装校验参数
    List<String> changedGroupKeys = checkUpdateDataIds(cacheDatum, inInitializingCacheList);
    // 2. 有变更则拉取最新配置
    for (String groupKey : changedGroupKeys) {
        String[] key = GroupKey.parseKey(groupKey);
        String dataId = key[0];
        String group = key[1];
        getServerConfig(dataId, group, 3000L);
    }
    // 3. 递归提交下一次长轮询任务
    executorService.execute(this);
}
服务端核心逻辑

服务端 LongPollingService 接收长轮询请求,将请求挂起,不立即返回:

  • 监听配置变更事件,如果对应配置发生修改,立即唤醒挂起的请求,返回变更信息
  • 如果到超时时间都没有变更,返回空结果,由客户端重连

设计优势:相比普通轮询,大幅减少无效请求;相比 WebSocket,实现简单,兼容所有网络环境,且服务端压力更低。

四、Nacos 集群架构与一致性原理

1. 集群部署架构

生产环境推荐 3 节点及以上的奇数节点集群,通过 SLB/VIP 做统一入口,客户端连接 VIP 即可。

  • 节点数量:至少 3 台,奇数台,保证 Raft 协议可以正常选举
  • 存储选型:生产环境必须切换为 MySQL 存储,默认内置 Derby 仅适合单机测试
  • 跨机房部署:建议节点分布在不同机房、不同机架,提高容灾能力

2. 双一致性协议设计

Nacos 最大的设计特点是针对不同场景采用不同的一致性协议,实现 AP 与 CP 的融合:

功能模块 对应实例类型 一致性协议 一致性级别 设计目标
服务注册发现 临时实例 Distro 协议 最终一致(AP) 优先保证高可用,容忍短暂不一致
服务注册发现 持久实例 Raft 协议 强一致(CP) 优先保证数据准确,故障时不可写入
配置中心 全部配置 Raft 协议 强一致(CP) 配置数据绝对不能出错,保证全节点一致

3. Distro 协议(AP 模式)

Distro 是 Nacos 自研的分布式一致性协议,专门针对临时服务注册场景设计:

  • 去中心化:所有节点地位平等,客户端可以连接任意节点读写
  • 数据分片:每个节点负责一部分服务的数据,通过哈希算法分配
  • 异步同步:写请求路由到负责节点写入成功后立即返回,后台异步同步到其他节点
  • 最终一致:数据存在短暂延迟,通常秒级内达到全节点一致
  • 故障容错:任意节点宕机不影响其他节点,集群整体可用,仅该节点负责的分片数据暂时不可写

4. Raft 协议(CP 模式)

Raft 是工业界通用的强一致性共识算法,配置中心和持久实例都依赖它:

  • 三个角色:Leader(主节点,处理所有写请求)、Follower(从节点,同步数据、处理读请求)、Candidate(选举候选状态)
  • 选主机制:Leader 故障后,剩余节点发起选举,获得过半票数的节点成为新 Leader
  • 日志复制:写请求由 Leader 接收,生成日志同步给 Follower,过半节点写入成功后提交返回
  • 脑裂防护:必须过半节点同意才能写入,网络分区时少数派集群无法写入,保证数据不出现双写冲突

五、实战踩坑与最佳实践

1. 服务注册发现常见踩坑

  1. 环境隔离误区:不要用 Group 区分环境,Namespace 才是官方设计的环境隔离单位。不同环境(dev/test/prod)必须建独立的 Namespace,避免配置和服务串环境。
  2. 服务无故下线:优先检查网络是否有防火墙中断心跳、实例内存溢出导致心跳线程停止、客户端版本与服务端不兼容。
  3. 实例权重滥用:权重为 0 的实例不会被消费方调用,常用于灰度发布、优雅停机;不要随意设置过大权重,导致单实例流量过高。
  4. Nacos 宕机影响:客户端有本地内存缓存和磁盘快照,Nacos 集群全挂不会影响已有服务的正常调用,仅无法注册新服务和感知实例变更。

2. 配置中心常见踩坑

  1. 配置不刷新:检查类是否加了 @RefreshScope;检查长轮询请求是否被网关 / 防火墙中断;确认配置的 refresh 属性是否为 true。
  2. 配置优先级错乱:配置覆盖优先级由高到低排序:应用自身 profile 专属配置 > 应用主配置 > 扩展配置 > 全局共享配置;同名属性遵循 “高优覆盖低优” 原则,同类型配置内声明越靠后,优先级越高。
  3. 敏感信息明文:数据库密码、密钥等敏感配置不要明文存储,使用 Nacos 配置加密插件或集成配置中心加密方案。
  4. 配置误发布:生产环境开启配置发布审批、灰度发布、版本回滚能力,避免误修改导致全量故障。

3. 生产最佳实践

  • 命名空间按环境划分,Group 按业务线划分,DataId 按应用 + 环境命名,形成规范的命名体系
  • 核心服务使用持久实例,普通微服务使用临时实例,合理平衡可用性与一致性
  • 配置中心按应用粒度拆分,公共配置抽离为共享配置,避免重复维护
  • 集群至少 3 节点,外接 MySQL 持久化,开启监控告警,关注集群健康状态、连接数、配置推送延迟
  • 客户端设置合理的超时和重试参数,避免服务端抖动影响业务

六、面试速记总结

  1. 核心定位:Nacos 是集服务注册发现、动态配置管理于一体的微服务基础设施,支持 AP/CP 双模式。
  2. 服务注册:客户端启动发送注册请求,服务端写入内存注册表,临时实例用心跳保活,30 秒无心跳自动剔除。
  3. 配置中心:三级模型 Namespace+Group+DataId;长轮询 + MD5 比对实现配置动态推送;@RefreshScope 实现 Bean 动态刷新。
  4. 一致性协议:临时实例用 Distro AP 协议,保证高可用;持久实例和配置用 Raft CP 协议,保证强一致。
  5. 高可用设计:客户端本地缓存服务列表和配置快照,注册中心故障不影响已有服务调用。
  6. 与 Eureka 对比:Eureka 仅支持 AP 服务注册,无配置中心能力;Nacos 功能更全,支持 CP 模式,性能和容量更高,阿里生态适配更好。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐