Sentinel 规则持久化到 Nacos 实践(网关篇 + 普通应用篇)

Sentinel 规则持久化到 Nacos 实践(网关篇 + 普通应用篇)

本文基于 Sentinel 1.8.9 社区版 dashboard 源码改造,实现网关流控规则与 API 分组规则的 Nacos 持久化,并给出普通 Spring MVC 应用的接入方案。文中涉及的所有 IP、账号、密码均已脱敏,请替换为你自己的环境信息。


1. 背景

社区版 Sentinel dashboard 的规则存储是纯内存

复制代码
dashboard UI 改规则 ──HTTP(command API)──→ 客户端 JVM 内存

存在两个丢失点:

  1. 客户端重启 → 内存规则丢失;
  2. dashboard UI 改的规则不落 Nacos → 即使客户端配了 datasource-nacos,UI 改的那份也只在内存,重启后回退到 Nacos 旧规则。

本次改造实现 push 模式 :dashboard UI 修改规则后全量持久化到 Nacos 配置中心 ,客户端通过 sentinel-datasource-nacos 监听变更实时生效,任意一方重启规则均不丢。

复制代码
dashboard UI 改规则 ──publishConfig──→ Nacos 配置中心 ──gRPC 监听──→ 客户端(sentinel-datasource-nacos)
                     (持久化,重启不丢)                    (变更秒级生效 / 重启拉全量)

改造范围 :先实现网关类规则(网关流控规则 gw-flow + API 分组定义 gw-api),再给出普通应用的流控/熔断规则扩展方案。


2. 版本与环境事实

Nacos Server 3.0.3
dashboard Sentinel 1.8.9 源码本地编译,端口 8083
网关应用 Spring Boot 3.5.0 / Spring Cloud 2025.0.0 / spring-cloud-alibaba 2025.0.0.0 ,传递 nacos-client 3.0.3
dashboard nacos-client 本次新增 3.0.3(与 Server/客户端三方对齐)
group 选型 DEFAULT_GROUP
namespace(test) <NAMESPACE_ID>(注意:客户端连的是命名空间 ID,不是名称)
Nacos 地址(test) <NACOS_SERVER_ADDR>(gRPC 端口自动 +1000,需放通)

请将 <NACOS_SERVER_ADDR> 替换为你的 Nacos 地址,格式如 10.0.0.1:8848<NAMESPACE_ID> 替换为实际命名空间 ID。


3. Nacos 侧配置

在目标 namespace 下预创建 2 个配置(不预创建时客户端首次启动拉取会报 config not exist):

dataId group 初始内容
yc-gateway-gw-flow-rules DEFAULT_GROUP []
yc-gateway-gw-api DEFAULT_GROUP []

dataId 命名约定:{app}-gw-flow-rules / {app}-gw-api,app 即客户端应用名(如 yc-gateway)。

gw-flow 规则 JSON 示例 (数组,字段与 core GatewayFlowRule 一致):

json 复制代码
[
  {
    "resource": "yc-business-route",
    "resourceMode": 0,
    "grade": 1,
    "count": 100,
    "intervalSec": 1,
    "controlBehavior": 0,
    "burst": 0
  }
]

gw-api JSON 示例 (字段与 core ApiDefinition 一致):

json 复制代码
[
  {
    "apiName": "message-remind-api",
    "predicateItems": [
      { "pattern": "/api/messageRemind/", "matchStrategy": 1 }
    ]
  }
]

matchStrategy:0=精确 1=前缀 2=正则。dashboard 页面上配好规则后内容会自动覆盖。


4. dashboard 改造(sentinel 源码)

4.1 改动文件清单

文件 类型 说明
sentinel-dashboard/pom.xml 修改 新增 com.alibaba.nacos:nacos-client:3.0.3
sentinel-dashboard/src/main/resources/application.properties 修改 新增 nacos.* 连接配置(支持环境变量覆盖)
dashboard/rule/nacos/NacosConfigSupport.java 新增 ConfigService 懒加载单例(gRPC 长连接);dataId 拼接约定
dashboard/rule/nacos/GatewayFlowRuleNacosProvider.java 新增 读 Nacos:核心规则 JSON → dashboard 实体
dashboard/rule/nacos/GatewayFlowRuleNacosPublisher.java 新增 写 Nacos:dashboard 实体 → 核心规则 JSON 全量覆盖
dashboard/rule/nacos/GatewayApiNacosProvider.java 新增 读 Nacos(API 分组,含接口类型手工解析)
dashboard/rule/nacos/GatewayApiNacosPublisher.java 新增 写 Nacos(API 分组)
dashboard/controller/gateway/GatewayFlowRuleController.java 修改 读写从"直调客户端"改为 Nacos
dashboard/controller/gateway/GatewayApiController.java 修改 同上

4.2 关键设计点

  1. 存储格式 = 客户端反序列化格式

    Nacos 中存核心规则对象GatewayFlowRule / ApiDefinition)的 JSON 数组;dashboard 读写均经 entity.toGatewayFlowRule() / fromGatewayFlowRule(...) 转换,剔除 id/app/ip/port/gmtCreate/gmtModified 等 dashboard 专属字段。严禁直接序列化 dashboard 实体(嵌套 rule 结构会导致客户端解析失败)。

  2. gw-api 接口类型反序列化坑

    ApiDefinition.predicateItems 是接口类型 Set<ApiPredicateItem>,fastjson(1.2.83_noneautotype,autoType 已禁用)无法直接反序列化------dashboard 侧 GatewayApiNacosProvider 手工解析为 ApiPathPredicateItem(与客户端 UpdateGatewayApiDefinitionGroupCommandHandler#parseJson 同款);客户端 Nacos 数据源侧由 spring-cloud-alibaba-sentinel-gateway 自带的 ApiPredicateItemDeserializer(Jackson 自定义反序列器,2025.0.0.0 已验证存在)处理,因此客户端正常。

  3. publish 失败显式报错

    Nacos 成为规则真源后,写 Nacos 失败若仍返回成功,规则会在下次刷新时"消失"(UI 与 Nacos 不一致);因此增/删/改后 publish 失败直接向前端返回 publish rules to nacos fail

  4. 内存仓库仍保留

    InMemGatewayFlowRuleStore 仅用于:list.json 刷新时给规则分配展示 id、apiName 重复校验、增删改后的全量规则收集。id 仅 dashboard 会话内有效,每次进入页面重新分配。

  5. 全量覆盖语义

    每次增/删/改把该应用全部规则写回 dataId(官方 push 模式标准做法);多人同时改规则存在互相覆盖风险(规则量小可接受,见 §8)。

  6. 前端零改动

    Controller 接口签名不变(/gateway/flow/*.json/gateway/api/*.json)。

  7. ConfigService 线程安全

    NacosConfigSupport.getConfigService() 采用 DCL 双重检查锁(volatile + synchronized)保证单例,gRPC 长连接创建成本高,全局复用一个实例;group 不进 Properties(Nacos group 是 API 调用时传参,不在连接级别预设)。

4.3 application.properties 新增配置

properties 复制代码
# ========== Nacos 规则持久化(push 模式改造) ==========
nacos.server-addr=${NACOS_SERVER_ADDR:<NACOS_SERVER_ADDR>}
# namespace 必须传命名空间 ID(不是名称),当前为 test 环境,生产通过 NACOS_NAMESPACE 注入
nacos.namespace=${NACOS_NAMESPACE:<NAMESPACE_ID>}
nacos.group=${NACOS_GROUP:DEFAULT_GROUP}
nacos.username=${NACOS_USERNAME:nacos}
nacos.password=${NACOS_PASSWORD:<NACOS_PASSWORD>}

生产部署时通过环境变量覆盖:

环境变量 默认值 说明
NACOS_SERVER_ADDR <NACOS_SERVER_ADDR> Nacos 地址
NACOS_NAMESPACE test 环境命名空间 ID 必须传 ID
NACOS_GROUP DEFAULT_GROUP 一般不动
NACOS_USERNAME nacos Nacos 鉴权用户
NACOS_PASSWORD <NACOS_PASSWORD> 生产必填,否则 publish 鉴权失败

请替换 <NACOS_SERVER_ADDR><NAMESPACE_ID><NACOS_PASSWORD> 为你自己的值。

4.4 打包与部署

bash 复制代码
# 必须用 JDK 17 构建(maven-compiler-plugin 3.12 的 --release 参数与 JDK 8 不兼容)
export JAVA_HOME=/path/to/jdk-17
mvn -pl sentinel-dashboard -am clean package -DskipTests
# 产物:sentinel-dashboard/target/sentinel-dashboard.jar(fat jar)

部署方式不变(java -jar 或 Dockerfile),需补充:

  • 注入 NACOS_PASSWORD 等环境变量;
  • dashboard 所在 Pod → Nacos gRPC 端口(主端口+1000) 网络放通;
  • 重启 dashboard 后规则自动从 Nacos 恢复。

5. 网关侧配置

依赖已就位(sentinel-datasource-nacos),无需改代码,仅修改 application-nacos-test.ymlspring.cloud.sentinel

yaml 复制代码
spring:
  cloud:
    sentinel:
      eager: true
      transport:
        dashboard: <SENTINEL_DASHBOARD_ADDR>   # 替换为 dashboard 地址
      datasource:
        gw-flow:
          nacos:
            server-addr: <NACOS_SERVER_ADDR>
            namespace: <NAMESPACE_ID>
            group-id: DEFAULT_GROUP
            data-id: yc-gateway-gw-flow-rules
            username: nacos
            password: ${NACOS_PASSWORD}
            rule-type: gw-flow          # 注意:在 nacos 内部
        gw-api:
          nacos:
            server-addr: <NACOS_SERVER_ADDR>
            namespace: <NAMESPACE_ID>
            group-id: DEFAULT_GROUP
            data-id: yc-gateway-gw-api
            username: nacos
            password: ${NACOS_PASSWORD}
            rule-type: gw-api-group     # 注意:枚举值为 gw-api-group
      scg:
        enabled: true
      webflux:
        enabled: false   # 必须关闭,避免重复埋点

要点:

  • rule-type 必须写在 nacos内部 ,且取值为 SCA RuleType 固定枚举:网关流控 gw-flow 、API 分组 gw-api-group (不是 gw-api)。
  • 属性名是 group-iddata-id (非 groupdataId)。
  • NACOS_PASSWORD 建议通过环境变量注入。
  • 客户端懒加载/监听由 spring-cloud-alibaba 自动完成。

6. 验证步骤

  1. dashboard 启动日志确认:Nacos config service initialized, serverAddr=..., namespace=..., group=DEFAULT_GROUP
  2. 网关启动日志确认 Nacos 数据源加载([SentinelDataSourceHandler] / NacosDataSource 注册),无 config-not-exist 报错;
  3. dashboard UI(网关流控规则页)新增一条规则 → Nacos 控制台查看 yc-gateway-gw-flow-rules 配置内容已更新
  4. 网关日志出现规则更新([GatewayRuleManager] / [GatewayApiDefinitionManager] ... updated);
  5. 重启 dashboard → UI 上规则仍在;重启网关 → 规则仍在;
  6. 压测验证限流阈值生效(可选)。

7. 普通应用(非网关)接入 Sentinel 改造步骤

7.1 客户端接入(每个应用)

① 引依赖 (版本由父 pom 的 spring-cloud-alibaba-dependencies 统一管理):

xml 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

② 配置数据源application-nacos-test.yml):

yaml 复制代码
spring:
  cloud:
    sentinel:
      eager: true
      transport:
        dashboard: <SENTINEL_DASHBOARD_ADDR>
      datasource:
        flow:
          nacos:
            server-addr: <NACOS_SERVER_ADDR>
            namespace: ${NACOS_NAMESPACE:<NAMESPACE_ID>}
            group-id: DEFAULT_GROUP
            data-id: yc-business-flow-rules
            username: nacos
            password: ${NACOS_PASSWORD}
            rule-type: flow
        degrade:
          nacos:
            server-addr: <NACOS_SERVER_ADDR>
            namespace: ${NACOS_NAMESPACE:<NAMESPACE_ID>}
            group-id: DEFAULT_GROUP
            data-id: yc-business-degrade-rules
            username: nacos
            password: ${NACOS_PASSWORD}
            rule-type: degrade

③ Nacos 预创建配置 :在对应 namespace 下创建 yc-business-flow-rulesyc-business-degrade-rules(group=DEFAULT_GROUP,初始内容 [])。

④(可选)代码级资源定义 :Web 接口自动埋点(资源名=URL),无需代码;非 HTTP 入口可使用 @SentinelResource 注解。

7.2 dashboard 持久化改造(一次性)

前提:已完成 §4 的网关改造(NacosConfigSupport 及公共设施已就位)。

NacosConfigSupport 增加普通规则 dataId 约定

java 复制代码
public static final String FLOW_DATA_ID_SUFFIX = "flow-rules";
public static final String DEGRADE_DATA_ID_SUFFIX = "degrade-rules";

public static String flowDataId(String app) {
    return app + "-" + FLOW_DATA_ID_SUFFIX;
}

public static String degradeDataId(String app) {
    return app + "-" + DEGRADE_DATA_ID_SUFFIX;
}

② 新增 Provider/Publisher:复制网关版改 3 处(核心规则类型、dataId 方法、实体转换)。

③ 改 Controller :将 FlowControllerV1DegradeController 中的 sentinelApiClient 调用替换为 Nacos Provider/Publisher,并同步返回 publish 结果。

④ 重新打包部署 dashboard,前端零改动。

7.3 规则类型总表

规则类型 rule-type(客户端) dashboard Controller dataId 约定 实体转换
流控 flow FlowControllerV1 {app}-flow-rules FlowRuleEntity.fromFlowRule / toRule
熔断降级 degrade DegradeController {app}-degrade-rules DegradeRuleEntity.fromDegradeRule / toRule
授权 authority AuthorityRuleController {app}-authority-rules 同款转换
系统保护 system SystemController {app}-system-rules 同款转换
热点参数 param-flow ParamFlowRuleController {app}-param-flow-rules 同款转换(注意 7.4)

建议只做 flow + degrade 两类(覆盖 80%+ 场景)。

7.4 param-flow 的接口反序列化坑

ParamFlowRule.paramItemList 是接口类型 List<ParamFlowItem>,dashboard 侧需手工解析;客户端侧 spring-cloud-alibaba 没有现成的反序列化器,需自定义 Converter 或改用其他方案。

7.5 存量规则迁移与上线顺序

  1. 改造上线前,从旧 dashboard UI 导出现网存量规则 → 整理成对应 dataId 的核心规则 JSON 数组 → 预写入 Nacos;
  2. 上线顺序:先发改造后的 dashboard,再改各应用 yml 并重启
  3. 每接入一个应用,按 §6 验证清单全链路走一遍。

8. 注意事项与已知限制

  1. 三元组必须一致:dataId / group / namespace 在 dashboard 与客户端两端完全一致。
  2. namespace 传 ID 不传名称
  3. 全量覆盖并发风险:push 模式下"最后写入者胜",规则变更建议固定负责人操作。
  4. dashboard 多实例:建议单实例部署,多实例写同一 dataId 无一致性问题,但 UI 规则 id 各自分配。
  5. 鉴权 :dashboard nacos.password 生产必须注入,否则 publish 时 Nacos 401。
  6. 网络:dashboard → Nacos 主端口 + gRPC 端口;客户端 → Nacos 同样端口。
  7. dashboard 重启后的规则 id 变化:id 仅用于前端定位,重启后重新编号,不影响功能。
  8. 规则内容校验:Nacos 上手工改 JSON 时若字段非法,客户端解析后由 core 校验拒绝加载,建议优先在 UI 上改。
  9. 规则同步行为:Nacos 是唯一真源,UI 改规则或 Nacos 控制台改规则都会同步到客户端;dashboard 页面停留期间若 Nacos 被手工修改,后续编辑可能覆盖手工修改(last-writer-wins)。
  10. ConfigService 创建失败无降级:Nacos 不可达时 dashboard 页面报错,不会回退到旧的内存模式。
  11. group 属性不进 Properties:group 通过 API 调用时传递。
  12. Nacos 配置预创建 :建议预创建空数组 [],避免首次启动 warn 日志。

9. 总结

通过将 Sentinel Dashboard 的规则存储从内存迁移到 Nacos,实现了规则持久化和动态同步,解决了客户端和 Dashboard 重启后规则丢失的问题。本文给出了网关规则的完整改造方案,并提供了普通应用接入的扩展指南。改造后,规则管理更加可靠,适合生产环境使用。

注意:文中所有 IP、账号、密码均为示例占位,实际部署时请替换为你的环境信息。

相关推荐
莫得感情 o1 天前
Redis 09 · 高可用:Sentinel 如何发现故障并完成切主
redis·缓存·sentinel
凌云若寒2 天前
CODESOFT试用流程
linux·运维·网络·数据库·sentinel
多敲代码防脱发9 天前
Alibaba Sentinel(熔断、限流)(国内下载Sentinel)
java·开发语言·sentinel
2601_9621819611 天前
【Spring Cloud Alibaba】Sentinel 服务熔断与流量控制
sentinel
LayZhangStrive12 天前
后端开发中间件 - Nacos下载并快速使用教程
中间件·nacos
lv__pf13 天前
Sentinel【TL微服务10、11】
java·微服务·sentinel
凤山老林14 天前
高可靠 API 网关架构:Spring Cloud Gateway 集成 Sentinel 实现智能限流、动态路由与安全管控
安全·spring cloud·架构·sentinel
就叫_这个吧15 天前
java springcloud熔断降级组件sentinel基础应用及nacos持久化处理
java·spring cloud·nacos·sentinel
aikopen15 天前
高可用 API 网关限流与微服务过载保护实战:从 Sentinel 动态阈值到 DB 连接池舱壁
数据库·微服务·sentinel