Nacos 整体架构与核心概念
Nacos(Dynamic Naming and Configuration Service)是阿里开源的注册中心 + 配置中心一体化组件,国内微服务事实标准。本文先建立整体认知:数据模型、架构分层、一致性设计。
Nacos 是什么
一个组件同时提供两类能力:
| 能力 | 解决的问题 | 替代品 |
|---|---|---|
| 服务发现(注册中心) | 服务实例在哪、是否健康 | Eureka、Consul |
| 配置中心 | 配置统一管理、动态下发 | Config Server、Apollo |
数据模型:五级层次
Namespace(命名空间:隔离环境)
└── Group(分组:逻辑分类)
└── Service(服务:逻辑服务名)
├── Cluster(集群:同机房/同分组实例)
│ └── Instance(实例:具体地址)
└── 配置(DataId = group + dataId)| 层级 | 说明 | 示例 |
|---|---|---|
| Namespace | 环境隔离,不同 Namespace 完全隔离 | dev / prod / 多租户 |
| Group | 同一 Namespace 内的逻辑分组 | DEFAULT_GROUP / 业务组 |
| Service | 服务名,客户端注册的标识 | order-service |
| Cluster | 实例的物理分组(机房/可用区) | 杭州 / 上海 |
| Instance | 一个具体实例(ip:port + 元数据) | 10.0.0.5:8080 |
命名空间的隔离效果
Namespace=dev Namespace=prod
└── order-service └── order-service
└── 实例 A、B └── 实例 C、Ddev 与 prod 的服务互相不可见,配置也互相隔离。多环境、多租户都靠 Namespace 实现。
完整服务标识
服务全名 = Namespace + Group + Service
配置全名 = Namespace + Group + DataId客户端注册/订阅时三者必须一致,否则"查不到"。
整体架构
┌─────────────────────── 客户端 ───────────────────────┐
│ Spring Cloud 应用(NacosDiscoveryClient / ConfigService)│
│ ├─ NamingService(注册/订阅/心跳) │
│ └─ ConfigService(拉取/监听/长轮询) │
└──────────────────────────┬────────────────────────────┘
│ gRPC / HTTP
┌──────────────────────────▼────────────────────────────┐
│ Nacos Server │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Naming Module│ │ Config Module│ │ Admin Module│ │
│ │ (注册/发现) │ │ (配置管理) │ │ (控制台/权限) │ │
│ └──────┬──────┘ └──────┬──────┘ └─────────────┘ │
│ └────────────────┴────────────────┐ │
│ ┌───────────────────────────────────────▼──────────┐ │
│ │ Consistency Module(一致性层) │ │
│ │ AP:Distro 协议(临时实例) CP:JRaft(持久实例/配置)│ │
│ └───────────────────────────────────────┬──────────┘ │
│ ┌───────────────────────────────────────▼──────────┐ │
│ │ 存储:内嵌 Derby / 外置 MySQL(生产必备) │ │
│ └──────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────┘模块划分
| 模块 | 职责 |
|---|---|
| Naming Module | 服务注册、发现、健康检查 |
| Config Module | 配置发布、监听、长轮询 |
| Consistency Module | 数据一致性(Distro / JRaft) |
| Admin Module | 控制台、用户权限、操作审计 |
| 存储层 | 内嵌 Derby(单机)/ MySQL(集群) |
一致性设计:CP vs AP
Nacos 最核心的设计:同一套系统,不同数据用不同一致性模型。
CAP 背景
- CP(强一致):写成功后所有节点立即可读,牺牲可用性(分区时拒绝写)
- AP(最终一致):任何节点可写,数据异步同步,牺牲一致性(短暂读到旧数据)
Nacos 的混合策略
| 数据 | 一致性模型 | 协议 | 原因 |
|---|---|---|---|
| 临时实例(注册表) | AP | Distro | 注册数据可短暂不一致,但必须高可用、低延迟 |
| 持久实例 / 配置 | CP | JRaft | 配置必须一致,不能出现"不同机器不同配置" |
临时实例 vs 持久实例
| 对比 | 临时实例(ephemeral=true) | 持久实例 |
|---|---|---|
| 存储 | 内存(AP) | 持久化到数据库(CP) |
| 心跳 | 必须心跳续约,超时自动摘除 | 无需心跳,人工管理 |
| 一致性 | Distro 最终一致 | JRaft 强一致 |
| 默认 | 客户端默认注册方式 | Spring Cloud 用持久实例场景较少 |
协议演进
| 版本 | 通信协议 | 说明 |
|---|---|---|
| Nacos 1.x | HTTP 短轮询(注册)+ UDP 推送(发现) | 推送不可靠,客户端兜底轮询 |
| Nacos 2.x | gRPC 长连接 | 双向流,注册/订阅/推送全走长连接,性能与实时性大幅提升 |
gRPC 长连接的意义:一次建连,后续所有操作复用;服务端可主动推送变更(Push),客户端不用反复轮询。
数据流:一次注册与发现
注册(临时实例)
客户端注册
├─ 1. gRPC 连接某 Nacos 节点
├─ 2. 发送 Instance 数据
├─ 3. 节点写入内存注册表
├─ 4. Distro 异步同步到其他节点(最终一致)
└─ 5. 客户端启动心跳(默认 5s 一次)发现
客户端订阅
├─ 1. gRPC 订阅 Service
├─ 2. 节点返回当前实例列表(含缓存)
├─ 3. 服务端实例变化 → Push 到客户端
└─ 4. 客户端更新本地缓存生产拓扑
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Nacos 1 │ │ Nacos 2 │ │ Nacos 3 │ ← 集群(≥3 节点)
└────┬─────┘ └────┬─────┘ └────┬─────┘
└─────────────┼─────────────┘
▼
MySQL(外置,主从)- 集群 ≥3 节点,节点间互相感知
- 生产必须外置 MySQL 持久化(内嵌 Derby 仅单机演示)
- 客户端通过域名/负载均衡访问任意节点
常见问题
- Namespace 和 Group 的区别? Namespace 是环境/租户级隔离,Group 是同一 Namespace 内的逻辑分组;查不到数据先检查两者是否一致。
- 临时实例和持久实例怎么选? 服务实例默认临时(自动心跳);持久实例适合人工管理的固定节点。
- 为什么配置要 CP? 配置错乱会导致线上事故,必须强一致;注册数据短暂不一致影响小,所以要 AP。
- Nacos 1.x 和 2.x 能混用吗? 服务端 2.x 兼容 1.x 客户端(双协议支持),但推荐统一升级到 2.x。