← 返回 NACOS 列表

Nacos 配置中心原理

Nacos 配置中心原理

一、Nacos 概述

Nacos(Dynamic Naming and Configuration Service)是阿里巴巴开源的服务发现与配置管理平台,提供服务注册与发现动态配置管理两大核心能力。

  • 注册中心:服务实例注册、健康检查、服务发现
  • 配置中心:配置集中管理、动态下发、变更通知

二、Nacos 配置中心原理

2.1 核心概念 [1.x/2.x/3.x 通用]

以下核心概念在 Nacos 所有版本中保持一致:

概念 说明
Data ID 配置的唯一标识,通常格式为 {prefix}-{profile}.{format},如 application-dev.yaml
Group 配置分组,默认 DEFAULT_GROUP,用于隔离同一 Data ID 的不同环境配置
Namespace 命名空间,用于多环境或多租户隔离,默认 public
配置项 一个具体的配置 key-value 对
配置快照 客户端本地缓存的配置副本,用于容灾

2.2 客户端获取配置的模式(按版本)

Nacos 获取配置的机制在不同版本中差异显著,从纯 Pull(1.x)演进到Push + Pull 混合(2.x/3.x)


[1.x 机制] 纯 Pull — HTTP 长轮询

Nacos 1.x 仅通过 HTTP 长轮询(Long Polling) 实现配置监听,没有服务端主动推送能力。

核心流程:

客户端 ──(1) 发起长轮询请求(HTTP)──▶ 服务端
                                           │
                                           ├── 有变更?──立即返回变更的 Key 列表
                                           │
                                           └── 无变更?保持连接(最长 30s)
                                                │
                                                ├── 30s 内有其他客户端变更配置?
                                                │   → 服务端触发 ConfigChangeEvent
                                                │   → 遍历挂起的请求,返回变更
                                                │
                                                └── 30s 超时 → 返回空响应
                                                      ↓
                                                客户端再次发起新一轮长轮询

时序细节:

  1. 发起长轮询

    • HTTP GET 请求,路径 /v1/cs/configs/listener
    • 携带所有监听配置的 MD5,多个配置合并到同一个请求体中(非每个配置单独一个连接
    • 仅当配置数超过 3000 个时,客户端会按每批 3000 个进行分片,每片启动一个独立的长轮询线程
    • 超时时间 LongPollingTimeout=30000(30 秒)
  2. 服务端挂起请求

    • 创建 ClientLongPolling 延迟任务
    • 比对 MD5 列表与最新配置
    • 有变更 → 立即返回
    • 无变更 → 放入调度队列等待
  3. 客户端处理响应

    • 收到变更 Key → 调用 /v1/cs/configs 重新拉取完整配置
    • 收到空响应 → 立即发起新一轮长轮询(无间隔)
    • 更新本地快照和内存配置
    • 触发 Spring Environment 刷新、@RefreshScope 回调

⚠️ 1.x 局限: 配置生效最长需等待 30s(一个长轮询周期),无法实现即时推送。


[2.x/3.x 机制] Push + Pull 混合 — gRPC 双向流 + 长轮询降级

Nacos 2.x 引入 gRPC 双向流 作为主要通信方式,实现服务端真正主动推送;HTTP 长轮询保留作为降级方案。3.x 继承该架构。

gRPC Push 机制(主要通道):

客户端                        Nacos Server
  │                               │
  │  (1) 建立 gRPC 双向流长连接     │
  │══════════════════════════════▶│
  │◀══════════════════════════════│
  │                               │
  │  (2) 注册配置监听              │
  │──── ConfigWatchRequest ─────▶│
  │                               │
  │  (3) 配置有变更时              │
  │                               │
  │◀─── ConfigChangePush ────────│  ← 服务端主动推送
  │                               │
  │  (4) 收到推送 → 拉取最新配置   │
  │──── ConfigQuery ────────────▶│
  │◀──── 完整配置内容 ────────────│

gRPC 推送的优势(相比 1.x 长轮询):

维度 1.x HTTP 长轮询 2.x/3.x gRPC 推送
推送延迟 最长 30s(需等待轮询周期) 毫秒级(服务端主动推送)
连接模型 每次轮询一个 HTTP 连接 多路复用单一长连接
连接数 所有配置合并到一个长轮询请求中,仅超大批量(>3000)时分片,连接数 = ⌈配置数/3000⌉ 固定,所有操作复用同一 gRPC 连接
网络开销 请求头重复传输 HTTP/2 头部压缩,开销小

HTTP 长轮询降级(备用通道):

当 gRPC 连接建立失败或断开时,2.x/3.x 客户端会自动降级到 1.x 的 HTTP 长轮询机制,确保客户端在不支持 gRPC 的网络环境中仍然可用。


2.3 客户端与服务端通讯协议演进 [全版本对比]

版本 配置中心协议 注册中心协议 端口变化
Nacos 1.x HTTP 长轮询(Pull) HTTP 心跳 仅 8848
Nacos 2.x gRPC 双向流(Push)+ HTTP 降级 gRPC 长连接 + HTTP 降级 8848 + 9848 + 7848
Nacos 3.x gRPC 双向流(增强) gRPC 长连接 同 2.x

2.4 配置快照与容灾 [1.x/2.x/3.x 通用]

该机制在所有版本中一致:

  • 客户端启动时成功拉取配置后,在本地磁盘保存一份配置快照
  • 快照位置:${user.home}/nacos/config/snapshot-{namespace}/{dataId}
  • 服务端不可用时,客户端从本地快照加载配置,保证应用可启动

2.5 配置变更回调链路(按版本)

[1.x 机制] HTTP 长轮询回调链路

管理员修改配置 → Nacos Server 持久化到 MySQL/Derby
     ↓
Server 触发 ConfigChangeEvent
     ↓
遍历挂起的 HTTP 长轮询 → 返回变更 Key 列表
     ↓
客户端收到列表 → 再次 HTTP GET 拉取完整配置
     ↓
客户端更新本地缓存 + 本地快照
     ↓
Spring: 发布 RefreshEvent(Environment 变更)
     ↓
@RefreshScope 的 Bean 重新创建
     ↓
配置生效

[2.x/3.x 机制] gRPC Push 回调链路

管理员修改配置 → Nacos Server 持久化到 MySQL/Derby
     ↓
Server 通过 gRPC 双向流直接推送(ConfigChangePush)
     ↓
客户端 gRPC 连接收到推送 → 发起 ConfigQuery 拉取完整配置
     ↓
客户端更新本地缓存 + 本地快照
     ↓
Spring: 发布 RefreshEvent(Environment 变更)
     ↓
@RefreshScope 的 Bean 重新创建
     ↓
配置生效

核心差异: 1.x 需要等待 30s 内长轮询的"被唤醒";2.x/3.x 是服务端通过 gRPC 通道直接推送,延迟从秒级降至毫秒级。

4.2 配置中心的完整交互(按版本)

[1.x 机制] HTTP 长轮询循环

┌───── Client 1.x ────┐         ┌──── Nacos Server 1.x ──┐
│                       │         │                         │
│  (1) HTTP GET 长轮询  │────────▶│  /v1/cs/configs/listener  │
│      MD5 监听列表     │         │  挂起请求(最长 30s)      │
│                       │         │                         │
│                       │◀────────│  (2a) 有变更 → 变更 Key  │
│                       │         │  (2b) 无变更 → 空响应    │
│                       │         │                         │
│  (3) 有变更时           │         │                         │
│  HTTP GET 拉取完整配置  │────────▶│  /v1/cs/configs          │
│                       │◀────────│  返回完整配置内容          │
│                       │         │                         │
│  (4) 更新本地缓存       │         │                         │
│  + 快照 + 回调         │         │                         │
│                       │         │                         │
│  ←── 回到步骤(1) 循环 ──▶       │                         │
└───────────────────────┘         └─────────────────────────┘

关键特征: 每个循环周期是一个独立的 HTTP 请求,长轮询超时后立即发起下一个。

[2.x/3.x 机制] gRPC 推送 + HTTP 降级

┌───── Client 2.x/3.x ─┐         ┌── Nacos Server 2.x/3.x ─┐
│                        │         │                          │
│  (1) 建立 gRPC 长连接   │────────▶│  端口 9848                │
│      双向流            │◀────────│                          │
│                        │         │                          │
│  (2) 注册配置监听       │────────▶│  ConfigWatchRequest       │
│                        │         │  注册到监听列表            │
│                        │         │                          │
│  (3) 初次拉取配置       │◀────────│  返回完整配置              │
│                        │         │                          │
│  (4) 配置有变更时       │         │                          │
│                        │◀────────│  gRPC Push(主动推送)     │
│                        │         │  ConfigChangePush         │
│                        │         │                          │
│  (5) 拉取最新配置       │────────▶│  ConfigQuery              │
│                        │◀────────│  返回完整配置内容          │
│                        │         │                          │
│  (6) 更新本地缓存       │         │                          │
│  + 快照 + 回调         │         │                          │
│                        │         │                          │
│  ←── 等待下一次 Push ──▶         │                          │
│  (无变更时无网络开销)    │         │                          │
└────────────────────────┘         └──────────────────────────┘

关键特征: 连接建立后,无变更时零额外网络开销,变更时服务端主动推送,延迟 < 1s。

4.4 通讯端口说明(按版本)

端口 协议 用途 引入版本 说明
8848 HTTP 管理控制台、HTTP API 1.x 起 所有版本均存在
9848 gRPC 客户端 gRPC 请求端口(8848 + 1000) 2.x 开始 1.x 无此端口
9849 gRPC 集群节点间 gRPC 通信(8848 + 1001) 2.x 开始 1.x 无此端口
7848 HTTP 集群 JRAFT 选举通信 2.x 开始 1.x 使用 Raft 在 8848

版本差异小结:

端口数量 Nacos 1.x Nacos 2.x Nacos 3.x
对外端口 1 个(8848) 2 个(8848 + 9848) 同 2.x
集群内部端口 0 个 1 个(7848) 同 2.x

配置中心常见问题

Q1:客户端配置变更后多久能生效?**

1.x 机制:最长 30s(一次长轮询周期内),取决于长轮询何时超时或变更触发。

2.x/3.x 机制:毫秒级(gRPC 服务端主动推送),延迟通常 < 1s。

**

Q4:配置长轮询会不会造成连接泄漏?**

1.x 场景:不会,Nacos 客户端内部使用连接池管理 HTTP 连接,长轮询超时后会立即发起下一次请求,每个请求有独立超时和清理机制。且所有配置合并到一个长轮询请求中,不会随配置数增多而线性增加连接数。但 1.x 没有连接复用,配置/心跳/查询各走独立通道。

2.x/3.x 场景:更无此问题,所有操作复用单一 gRPC 长连接。

**