Files
2026-07-13 12:37:52 +08:00

266 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
Copyright 1999-2026 Alibaba Group Holding Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# Nacos 插件化规范
## 目的
Nacos 使用插件机制和 SPI 扩展,将横切基础能力和可替换的领域能力从固定核心中拆出。
插件可以提供鉴权、资源可见性、数据源方言、加解密、链路追踪、流量控制、环境适配、
AI pipeline、AI 存储、AI 资源导入或 Java 客户端侧请求适配等能力。
插件机制的目标,是在保持 Nacos 核心模型稳定的同时,让不同部署环境可以选择符合自身
身份系统、数据库、观测体系或扩展场景的实现。
## 插件身份
每个插件由以下字段唯一标识:
- `pluginType`:扩展类别,例如 `auth``visibility`
- `pluginName`:该类别下的实现名称,例如 `nacos`
- `pluginId`:运行时标识,格式为 `{pluginType}:{pluginName}`
`pluginId` 用于管理 API、集群状态同步、插件状态持久化和面向用户的诊断信息。
## 插件类型
当前插件类型注册表由 `PluginType` 定义。
| 类型 | 目的 | 契约 |
|------|------|------|
| `auth` | 认证与授权实现。 | [鉴权插件规范](../auth/auth-plugin-spec.md) |
| `visibility` | 资源可见性与查询可见性建议。 | [可见性插件规范](../auth/visibility-plugin-spec.md) |
| `datasource-dialect` | 数据库方言与持久化适配。 | [数据源方言插件规范](datasource-dialect-plugin-spec.md) |
| `config-change` | 配置变更扩展。 | [配置变更插件规范](config-change-plugin-spec.md) |
| `encryption` | 加解密扩展。 | [配置加密插件规范](config-encryption-plugin-spec.md) |
| `trace` | 链路追踪与观测扩展。 | [Trace 插件规范](trace-plugin-spec.md) |
| `environment` | 环境适配扩展。 | [环境插件规范](environment-plugin-spec.md) |
| `control` | 流量与控制扩展。 | [Control 插件规范](control-plugin-spec.md) |
| `ai-pipeline` | AI 注册中心 pipeline 扩展。 | [AI 发布 Pipeline 插件规范](ai-pipeline-plugin-spec.md) |
| `ai-storage` | AI 注册中心存储扩展。 | [AI 存储插件规范](ai-storage-plugin-spec.md) |
| `ai-resource-import` | AI 注册中心外部资源导入扩展。 | [AI 资源导入插件规范](ai-resource-import-plugin-spec.md) |
各插件类别的领域契约由对应规范定义。本文档定义所有插件类别共享的运行时契约。
[寻址扩展](addressing-plugin-spec.md)为了和公开插件文档保持连续性,也放在插件
规范中记录;但当前服务端代码通过 `MemberLookup` 处理寻址,并未将其注册到
`PluginType`
## 运行位置
Nacos 有两类插件式扩展面:
| 运行位置 | 加载模型 | 状态归属 | 示例 |
|----------|----------|----------|------|
| 服务端插件 | 领域 SPI 加 `PluginProvider`,在支持时可由服务端插件 API 列出和管理。 | Nacos 服务端进程;对可管理插件,还包括服务端插件状态。 | `auth``visibility``datasource-dialect``control``trace`。 |
| Java 客户端扩展 | 在客户端进程内通过 Java SPI 或 SDK API 加载。 | 客户端 classpath、客户端配置和 SDK 实例生命周期。 | `ServerListProvider``ClientAuthService``IConfigFilter`、客户端侧配置加密。 |
客户端扩展不由 `/v3/admin/core/plugin/*` 管理,也不具备服务端
`PluginStateCheckerHolder` 决策,除非对应服务端插件同时参与请求处理。它们仍必须遵守
Nacos 资源身份、鉴权和 payload 语义,因为它们会影响 SDK 发出的请求。
## 执行形态
插件类别并不都以同一种形态执行。每个插件类型都必须明确自身执行形态。
| 形态 | 含义 | 示例 |
|------|------|------|
| 互斥选择 | 在进程或请求范围内选择一个实现,其他已加载实现不参与该次判断。 | `auth``datasource-dialect` |
| 配置选择的单服务 | 可以加载多个实现,但领域根据配置或请求上下文选择一个服务。 | `visibility``ai-resource-import` |
| 有序链式执行 | 多个匹配插件按稳定顺序执行。每个节点可以贡献结果,失败是否中断由领域定义。 | `ai-pipeline``config-change` |
| 订阅或广播 | 多个订阅者观察同一个事件或 trace 点,不拥有主决策权。 | `trace`、事件型扩展 |
对于链式插件,领域 SPI 必须定义:
- 如何根据资源或 pointcut 选择候选插件。
- 哪个字段控制顺序,例如 `getPreferOrder()``getOrder()`
- 执行方式是串行还是并行。
- 某个插件失败时,是中断链路还是只记录失败结果。
- 如何持久化和暴露部分执行结果。
核心插件管理器记录插件的加载状态和启用状态,本身不定义执行形态。领域管理器负责稳定地
应用对应执行形态。
## SPI 层次
Nacos 插件包含两个相关的 SPI 层次:
1. 领域 SPI,例如 `AuthPluginService``VisibilityService`,定义所属领域需要的行为。
2. 核心插件 SPI,即 `PluginProvider`,将插件实例暴露给核心插件管理器,用于列表查询、
状态管理、配置管理和运行时观测。
需要动态配置的插件应实现 `PluginConfigSpec`。支持启停状态判断的插件类别,应通过
`PluginStateCheckerHolder` 获取状态,而不是维护一套独立状态来源。
## 加载与生命周期
插件实现通过 Nacos SPI 加载。部署时可以从 classpath 或服务端插件目录提供插件。
插件实现必须能在不修改 Nacos 服务端代码的情况下被加载。
核心 `PluginManager` 会在服务端应用就绪后发现 `PluginProvider` 实现。领域管理器也可以
通过 SPI 加载自身领域服务,但是否可参与请求处理,仍必须遵守核心插件管理器维护的启停
状态。
插件启动必须具备确定性:
- 一个插件类型和插件名称组合只能对应一个运行时插件实例。
- 同一插件类型下重复的插件名称不适合稳定运行。
- 插件实现不得改变 Nacos 共享资源标识、响应封装或错误约定的含义。
## 状态与配置
插件状态分为两个层次:
- 已加载:实现存在于运行时。
- 已启用:实现可以参与请求处理。
大多数插件类型在加载后默认启用。互斥插件类型会选择一个默认实现:
| 类型 | 默认选择规则 |
|------|--------------|
| `auth` | 由 `nacos.core.auth.system.type` 指定,默认 `nacos`。 |
| `datasource-dialect` | 由 SQL platform 配置指定,默认 `derby`。 |
当服务端依赖某些插件维持基本运行能力时,这些插件不能被禁用。当前关键插件集合包括内置
数据源方言,以及服务端需要的默认 AI 存储插件。
实现 `PluginConfigSpec` 的插件应暴露配置定义、当前配置和配置应用行为。除非请求明确
声明为仅本机生效,否则集群级状态或配置变更必须通过插件状态操作链路进行同步。
### 配置定义
插件配置项由 `ConfigItemDefinition` 描述。`key` 表示插件实现内部的 canonical item
key,不携带 `nacos.plugin.{pluginType}.{pluginName}.` 前缀。静态配置推荐使用以下
normalized full key
```text
nacos.plugin.{pluginType}.{pluginName}.{itemKey}
```
配置定义可以声明以下元数据:
| 字段 | 含义 |
|------|------|
| `aliases` | 历史静态配置 key,用于兼容读取和迁移提示。 |
| `sensitive` | 是否为敏感值。查询 API 返回前必须脱敏。 |
| `effectMode` | 生效模式,`RUNTIME` 表示可运行时生效,`RESTART` 表示需要重启。 |
`aliases` 用于静态配置兼容读取,也可以作为迁移兼容的 API 输入。完成归一化后,alias
不应写入运行时持久化文件或 local-only 内存表。如果输入同时包含同一配置项的多个
alias,则按定义中的声明顺序取第一个生效,并由服务端记录其余 alias 被忽略的日志。
### 配置来源与值元数据
插件配置的 effective value 由统一解析流程计算。配置来源优先级为:
```text
LOCAL_ONLY > RUNTIME_PERSISTED > STATIC > DEFAULT
```
| 来源 | 含义 |
|------|------|
| `DEFAULT` | 来自 `ConfigItemDefinition.defaultValue`。 |
| `STATIC` | 来自 `application.properties`、环境变量、JVM 参数或 Spring 参数等静态配置。 |
| `RUNTIME_PERSISTED` | 来自集群级运行时 override,当前可由 `plugin-configs.json` 记录终态内容。 |
| `LOCAL_ONLY` | 当前节点的本机 override,只用于诊断或应急处理,不同步到集群。 |
插件详情返回模型可以追加以 canonical item key 为索引的 `configValueMetas` map。每个
`PluginConfigValueMeta` 用于描述对应配置项的当前值来源和是否存在多来源覆盖。
`overridden` 忽略 `DEFAULT`,只有同一 key 同时存在多个非默认来源时才应为 `true`
运行时持久化配置和 local-only 配置只保存 `pluginId + itemKey` 对应的值,不保存
normalized full key、alias key、source 或版本信息。
每个内部 source resolver 都必须通过 `getConfig(PluginInfo)` 返回使用 canonical
item key 的完整 map。读取能力与写入能力相互独立:`DEFAULT` 从 definition 读取默认值,
`STATIC` 根据标准 key 和 alias 从环境读取,两个运行时 source 读取各自内部 map。
`isUpdatable` 只在替换 source map 时检查。每次更新完整替换该 source 的 map;传入空
map 表示清空该插件在该 source 下的全部 override,不额外提供 remove 或 restore 操作。
### 配置更新兼容性
插件详情 API 应保持 additive 兼容:已有 `config``configDefinitions` 字段继续
保留,其中 `config` 可以表示当前 effective config,新增的 `configValueMetas` map 按
canonical item key 提供 source 和 overridden 等元信息。
`PUT /v3/admin/core/plugin/config` 和对应 Console API 保持现有完整 override map
更新语义。`localOnly=true` 表示只更新当前节点 local-only override;否则更新集群级
runtime persisted override。key 归一化和 `effectMode` 校验由服务端内部完成,不作为
新的 API 参数暴露。`effectMode=RESTART` 的字段不应通过运行时更新立即生效。
服务端应比较目标 source 更新前后的完整 map,因此新增、修改或移除 `RESTART` 配置项
都必须拒绝。提交的完整 map 中省略某个 key,只有在该配置项支持运行时生效时才表示
移除对应 override。
canonical item key、normalized full key 和兼容 alias key 应在校验及存储前统一归一化为
item key。请求包含未定义 key,或者 alias 歧义命中多个配置项时,应返回参数校验错误。
对于声明为 `sensitive=true` 的配置项,提交值只要包含统一的 `******` marker,就按
脱敏展示值处理。如果当前目标 source 已经包含该 key,服务端应保留该 source 中的原始
值;如果目标 source 不包含该 key,则忽略这项输入,继续保持该 source 不存在此 key。
该判断同时覆盖 `******``a******z``ab******yz`,且不得把 `STATIC` 等其他
source 的 effective value 复制成 runtime override。服务端应记录 WARN 日志,但只记录
`pluginId`、item key 和目标 source,不得打印配置值。
### 初始化与运行时应用
启动和运行时更新复用同一套 source resolver 与 effective config 计算逻辑:
1. 启动时先将 `plugin-configs.json` 中的全部内容装载到 runtime persisted source
再开始应用插件配置。
2. 随后对每个已加载的可配置插件执行 resolve 和 apply,即使该插件没有持久化
override 也要处理。启动属于初始化阶段,可以同时应用 `RUNTIME``RESTART`
字段。
3. 运行时请求完整替换一个 `RUNTIME_PERSISTED``LOCAL_ONLY` source map,随后
重新解析全部来源;每次接受的请求都调用插件实现,包括使用相同完整 map 发起的
手动重试。
同一插件的更新应串行执行。runtime persisted 更新先持久化归一化后的完整 source
map,再替换 resolver source、解析并校验 effective config,最后应用到插件。持久化
失败时不得修改 resolver source 或插件,也不执行回滚。source 更新成功但 apply 失败
时,已接受的 source map 保持持久化和可解析状态,服务端不自动发起回滚或补偿更新;
API 应明确返回“配置已更新但 apply 失败”的服务端错误,日志记录 plugin ID 和 source
且不记录配置值。再次提交相同完整 map 可以手动重试 apply。`LOCAL_ONLY` 更新执行相同
的 replace、resolve、apply 流程,但不持久化、不同步;apply 失败后新的本机 source map
同样保留。
## 管理 API
核心插件管理 API 如下:
| 方法 | 路径 | 目的 |
|------|------|------|
| `GET` | `/v3/admin/core/plugin/list` | 查询已加载插件,可按类型过滤。 |
| `GET` | `/v3/admin/core/plugin/detail` | 查询单个插件详情,返回 effective config 和可选值元数据。 |
| `PUT` | `/v3/admin/core/plugin/status` | 启用或禁用插件。 |
| `PUT` | `/v3/admin/core/plugin/config` | 更新插件配置。 |
这些端点属于 Admin API,并要求符合 [HTTP 鉴权规范](../http-api/authorization-spec.md)
中的控制台域鉴权。插件管理 API 必须使用标准 v3
[响应与错误模型](../http-api/response-error-spec.md)。
## 设计要求
插件实现必须遵守以下规则:
- 使用已有 Nacos [资源标识](../design/resource-model-spec.md)和领域模型,不为同一
资源发明不兼容的新模型。
- 插件提供的 HTTP API 必须保持 v3 [HTTP API](../http-api/api-spec.md) 响应、错误和
鉴权约定。
- 仅通过 `PluginConfigSpec` 暴露插件自身拥有的配置。
- 除调用方明确要求本机操作用于诊断或应急处理外,集群级状态变更必须保持同步。
- 安全敏感的默认值和部署要求必须在插件实现规范中说明。
插件机制是扩展边界,不是绕过 Nacos 资源、API 或安全规则的通道。