网关 Sentinel 限流实战:API 分组、规则加载与全量匹配踩坑记

CHEN 网关 Sentinel 限流实战:API 分组、规则加载与全量匹配踩坑记

小结 :本文沉淀 CHEN 网关接入 Sentinel 网关流控的完整实战经验。核心内容:① matchStrategy 在 Dashboard UI 上的语义标注(精确/前缀/正则)与客户端适配器真实行为(精确/ANT 模式/正则)严重错位 ,这是"配置看起来对、限流就是不生效"的第一大坑;② gw-api 数据源的 JSON 反序列化由 SCA 自定义反序列化器处理,格式错误时静默失败、每 5 秒重试报错、规则不生效 ;③ 网关自有接口走自转发架构,命中全量分组时限流配额双重消耗。文中给出经过字节码级验证的语义表、生产可用配置与排查 SOP。

姊妹篇:《Spring Cloud Gateway 整合 Sentinel 踩坑记:为什么网关限流抛出的是 ParamFlowException.md》(网关流控规则统一转换为 ParamFlowRule、异常处理返回 429 的部分见该篇,本文不重复展开)。

一、依赖版本(本次踩坑的关键背景)

组件 版本 说明
Java 17 编译与运行时
Spring Boot 3.5.0 父 POM
Spring Cloud 2025.0.0 对应 Spring Cloud Gateway 4.3.x
Spring Cloud Alibaba 2025.0.0.0 统一管理 SCA 全家桶版本
Sentinel 核心/适配器 1.8.9 显式声明 sentinel-gateway-adapter.version=1.8.9;含 sentinel-spring-cloud-gateway-adapter、sentinel-api-gateway-adapter-common
spring-cloud-alibaba-sentinel-gateway 2025.0.0.0 SCA 网关自动装配(本文多个坑的来源)
spring-cloud-alibaba-sentinel-datasource 2025.0.0.0 规则数据源(Nacos push 模式)
Sentinel Dashboard 1.8.9(企业版) 部署于 10.xx.xx.161:10000
Nacos 集群版(k8s 内 nacos-cluster:8848) 规则配置 push 模式持久化

版本组合要点 :SCA 2025.0.0.0 + Sentinel 适配器 1.8.9 是本次所有坑的版本土壤。升级 SCA 或 Sentinel 适配器版本后,本文第 4.1 节的 matchStrategy 语义表必须重新验证。

二、规则生效链路(排障必备心智模型)

复制代码
Nacos 配置中心
 ├─ dataId: chen-gateway-gw-api      (API 分组定义,rule-type: gw-api-group)
 │    → JsonConverter + ApiPredicateItemDeserializer 反序列化
 │    → GatewayApiDefinitionManager(内存中的 API 定义 + 匹配器)
 │
 ├─ dataId: chen-gateway-gw-flow-rules (网关流控规则,rule-type: gw-flow)
 │    → JsonConverter 反序列化为 GatewayFlowRule
 │    → GatewayRuleManager 转换:
 │        - 不带 paramItem → FlowRule(普通 QPS 限流)
 │        - 带 paramItem   → ParamFlowRule(热点参数限流,按 Header/query 参数计数)
 │        ⚠️ resourceMode=1(API 分组模式)的规则转换时会校验同名 API 分组是否存在,
 │           分组不存在则规则被丢弃
 │
 └─ 请求进入 SentinelGatewayFilter(GlobalFilter)
      → pickMatchingApiDefinitions:按 API 分组定义逐个匹配请求路径
      → 命中的分组各建一个 Entry(资源名 = apiName)
      → 未命中任何分组也按 Route ID 建 Entry(资源名 = 路由 ID)
      → ParamFlowRule 检查(超阈值抛 ParamFlowException)
      → GlobalExceptionHandler 捕获 BlockException → HTTP 429 + 业务码 429

链路上任何一环断裂都不会拦截,且大多静默无感知。排障时按"定义加载 → 路径匹配 → 规则转换 → 参数提取"顺序二分定位。

三、生产可用配置(正确答案先行)

3.1 数据源 yml(application-nacos-test.yml)

yaml 复制代码
spring:
  cloud:
    sentinel:
      eager: true
      transport:
        dashboard: 10.xx.xx.161:10000
      # rule-type 必须写在 nacos 块内(binder 绑定目标无此属性,放外面被忽略 → postRegister NPE)
      datasource:
        gw-flow:
          nacos:
            server-addr: ${spring.cloud.nacos.server-addr}
            namespace: ${spring.cloud.nacos.config.namespace}
            group-id: DEFAULT_GROUP
            data-id: chen-gateway-gw-flow-rules
            rule-type: gw-flow
        gw-api:
          nacos:
            server-addr: ${spring.cloud.nacos.server-addr}
            namespace: ${spring.cloud.nacos.config.namespace}
            group-id: DEFAULT_GROUP
            data-id: chen-gateway-gw-api
            rule-type: gw-api-group
      scg:
        enabled: true
      # webflux 适配器必须关闭,否则与 scg 适配器双重埋点
      webflux:
        enabled: false

3.2 API 分组定义(chen-gateway-gw-api)

全量请求分组 + 精确路径分组的可用配置:

json 复制代码
[
  {
    "apiName": "global-all-requests",
    "predicateItems": [
      {
        "matchStrategy": 1,
        "pattern": "/**"
      }
    ]
  },
  {
    "apiName": "blacklist-api",
    "predicateItems": [
      {
        "matchStrategy": 0,
        "pattern": "/chen-business/xx/xx/list"
      }
    ]
  }
]

3.3 网关流控规则(chen-gateway-gw-flow-rules)

全量按 Authorization 头限流(同 token 5 秒 1 次)+ 路由级兜底:

json 复制代码
[
  {
    "burst": 0,
    "controlBehavior": 0,
    "count": 1.0,
    "grade": 1,
    "intervalSec": 5,
    "maxQueueingTimeoutMs": 500,
    "paramItem": {
      "fieldName": "Authorization",
      "matchStrategy": 0,
      "parseStrategy": 2
    },
    "resource": "global-all-requests",
    "resourceMode": 1
  },
  {
    "burst": 0,
    "controlBehavior": 0,
    "count": 100.0,
    "grade": 1,
    "intervalSec": 5,
    "resource": "chen-business-route",
    "resourceMode": 0
  }
]

字段说明:resourceMode=0 按 Route ID、=1 按自定义 API 分组;parseStrategy:0=URL 参数、1=Host、2=Header 、3=远程地址;paramItem.matchStrategy=0 表示参数精确匹配。

3.4 matchStrategy 真实语义对照表(字节码级验证,1.8.9)

这是本次踩坑的核心结论。Dashboard UI 的单选框文案与适配器真实行为不一致:

matchStrategy 值 Dashboard UI 标注 适配器真实行为(1.8.9 SCG 适配器) 实现类
0 精确 精确匹配(String.equals) exactPath
1 前缀 ANT 路径模式匹配(Spring AntPathMatcher,/**、/* 通配符) antPath
2 正则 正则全串匹配(Pattern.matches) regexPath

字节码证据(WebExchangeApiMatcher.fromApiPathPredicate,反编译自 sentinel-spring-cloud-gateway-adapter-1.8.9.jar):

复制代码
16: invokevirtual getMatchStrategy
20: lookupswitch { 1: 56, 2: 48, default: 64 }
48: RouteMatchers.regexPath(pattern)    // matchStrategy=2
56: RouteMatchers.antPath(pattern)       // matchStrategy=1
64: RouteMatchers.exactPath(pattern)     // 其他(含 0)

由语义错位直接引出的三条铁律:

  1. 匹配所有请求必须用 matchStrategy=1 + pattern="/**" 。配 pattern="/"(指望"前缀匹配一切")时,AntPathMatcher 判定 / 不含通配符(isPattern=false),退化为精确匹配路径 /,任何真实请求都匹配不上。
  2. 不要用正则匹配全量 。matchStrategy=2 + "/**" 里 * 是非法正则重复符,模式非法无法匹配。
  3. 前缀语义要用 ANT 表达 。想匹配 /chen-business/ 开头的所有路径,写 pattern=/chen-business/**(matchStrategy=1),而不是 /chen-business/。

四、踩坑记录

4.1 坑一:pattern="/" 配置后 API 分组永不匹配

  • 现象 :global-all-requests 分组(matchStrategy=1、pattern=/)在 Nacos 修改后 pod 日志无任何报错,但 Dashboard"请求链路"里只有 Route ID 资源(chen-business-route、gateway-api-route 等),始终不出现 global-all-requests,请求从不被拦。
  • 对照实验 :同一份数据源里的精确匹配分组(matchStrategy=0)能正常出现在请求链路并限流,证明数据源加载、匹配框架、规则转换全链路是好的------唯独"前缀"分组不工作。
  • 根因 :见 3.4 节语义表。matchStrategy=1 走 AntPathMatcher,/ 退化为精确匹配。
  • 修复 :pattern 改为 /**,即时生效(Nacos 长轮询推送,无需重启 Pod 与 Dashboard)。

4.2 坑二:gw-api JSON 格式错误 → 反序列化失败静默重试

  • 现象:gw-api 内容反序列化失败时,pod 日志每 5 秒输出一轮(Nacos 客户端 listener 重试机制):

    ERROR c.a.c.s.d.c.SentinelConverter - sentinel rule convert error: Cannot deserialize value of type
    java.lang.String from Object value (token JsonToken.START_OBJECT)
    (through reference chain: ...ApiDefinition["predicateItems"]->...ApiPathPredicateItem["pattern"])
    ERROR c.a.n.client.config.impl.CacheData - [notify-error] dataId=chen-gateway-gw-api ...

  • 根因 :SCA 2025.0.0.0 的 SentinelGatewayAutoConfiguration$SentinelConverterConfiguration 为 ApiPredicateItem(抽象类)注册了自定义反序列化器 ApiPredicateItemDeserializer,其期望的格式是扁平结构:

json 复制代码
{"matchStrategy": 1, "pattern": "/"}

若把 pattern 字段写成嵌套对象({"pattern": {"matchStrategy": 1, "pattern": "/"}}),反序列化器把整个 item 转 ApiPathPredicateItem 时 pattern 字段收到 Object 而非 String,直接抛 MismatchedInputException。

  • 行为特征 :失败期间 API 分组完全不生效,且不会中断服务、不会在 Dashboard 上有任何提示 ------唯一的信号就是 pod 日志里的这两条 ERROR。所以 gw-api 发布后必看 pod 日志 确认无 sentinel rule convert error。
  • 修复:回到 3.2 节标准格式。

4.3 坑三:API 分组加载失败期间,关联流控规则可能被静默丢弃

  • 场景:gw-api 反序列化失败(坑二)或分组名写错(坑一)期间,gw-flow 数据源已完成加载。
  • 根因 :GatewayRuleManager 把带 paramItem 的网关规则转换为 ParamFlowRule 时,对 resourceMode=1 的规则会校验同名 API 分组是否存在,不存在则该条规则被丢弃,无 ERROR 日志。
  • 后果:修复 API 分组后,gw-flow 数据源内容未变、不会触发重新加载与转换,被丢弃的规则不会自己回来------"分组修好了,还是不拦"。
  • 修复/规程 :修复或新增 API 分组后,必须同步在 Nacos 重新发布一次 chen-gateway-gw-flow-rules(内容不变直接点发布即可),强制触发规则重新转换。

4.4 坑四:网关自有接口自转发 → 全量分组配额双重消耗

  • 背景 :网关自身接口(登录 /gateway/xxx/**、渠道管理 /gateway/api/xxx/**、渠道权限 /gateway/xx/xxion/**)通过路由 uri: http://127.0.0.1:${server.port} + StripPrefix 转发回自身 ,对外统一暴露 /gateway 前缀。
  • 现象 :一次外部调用 /gateway/xx/xx/list,StripPrefix 后的内层请求 /xx/xx/list 同样命中 global-all-requests 的 /** 模式------同一次业务调用在全量分组上消耗 2 次配额。
  • 影响评估 :设全量规则 count=N,则网关自有接口实际每窗口只能被调用约 N/2 次;转发类请求(如 /chen-business/**,不自转发)只计 1 次。
  • 阈值配置要求:给客户报全量限流阈值时,网关自有接口按"配置值 ÷ 2"折算;或按业务重要性评估是否接受该系数。

4.5 坑五:验证入口与验证姿势

  • 验证资源是否匹配 :Dashboard → chen-gateway → **"请求链路"**菜单(该企业版控制台不叫"簇点链路")。先连发几次请求再刷新查看。资源出现的含义:
    • Route ID 资源出现 → SCG 适配器在工作(不证明任何规则生效);
    • 自定义 API 资源出现 → 分组定义已加载且路径匹配成功;
    • 资源出现但"拒绝 QPS"恒为 0 → 匹配 OK,查规则转换(坑三)与 paramItem 参数提取。
  • "实时监控"菜单只展示有 metric 的资源,不能作为规则加载依据。
  • 测试姿势:count=1/intervalSec=5 的规则,手动点两次的间隔很容易超过 5 秒窗口造成"没拦"的误判------用 Apifox 循环连发验证。
  • 429 判定:被限流的请求由 GlobalExceptionHandler 统一返回 HTTP 429 + 业务码 429(详见姊妹篇)。

五、排查 SOP(按顺序二分)

text 复制代码
gw-api 改配置 → 发布
 ├─ ① 看 pod 日志:grep "sentinel rule convert error"
 │     有 → JSON 格式错(回到坑二),修格式,重新走 ①
 │     无 → 进入 ②
 ├─ ② 重新发布 gw-flow(坑三规程)
 └─ ③ 连发请求 + Dashboard"请求链路"刷新
       ├─ 自定义 API 资源没出现 → 匹配失败:查 pattern/matchStrategy(坑一)
       ├─ 资源出现但不 429 → 规则未转换(坑三,确认 ② 做了)
       │                      或 paramItem 提取问题(确认请求头确实带 Authorization)
       └─ 429 了 → 链路全通

六、运维约定

  1. API 分组(chen-gateway-gw-api)只在 Nacos 控制台维护,禁止在 Dashboard UI 编辑------Dashboard 的"编辑自定义 API"对话框按"精确/前缀/正则"文案生成 matchStrategy,与适配器真实语义错位(3.4 节),且编辑保存会推送覆盖 Nacos 里的正确配置,直接复现坑一。
  2. 流控规则(chen-gateway-gw-flow-rules)同样建议在 Nacos 维护,Dashboard 仅用于监控(请求链路/实时监控)。
  3. 新增/修复 API 分组后,必须重新发布 gw-flow(坑三)。
  4. Nacos 规则变更为长轮询实时生效,不需要重启网关 Pod、不需要重启 Dashboard。
  5. 全量分组阈值评估必须计入自转发双重消耗系数(坑四)。
  6. 升级 SCA / Sentinel 适配器版本时,重新验证 3.4 节语义表与 4.2 节 JSON 格式。
相关推荐
spencer_tseng4 小时前
nacos CVE‑2021‑29441
nacos·alibaba
Joy T8 小时前
从 Nginx 到 Gateway 再到微服务:一次 AI 请求的完整链路
nginx·微服务·gateway·controller·路由转发·ai service·接口错误排查
Thomas.Sir10 小时前
第19课:Gateway过滤器、全局拦截、请求响应统一处理
spring cloud·gateway
Joy T20 小时前
Spring AI 项目中的 pom.xml、application.yml 与 Nacos:从依赖管理到运行配置
spring·nacos·pom.xml·profile·参数配置·application.yml
Thomas.Sir1 天前
第18课:Gateway路由规则、内置谓词、自定义谓词实战
spring cloud·gateway
LoneEon2 天前
CentOS7 部署 Nacos3.x 集群实战:从注册中心到 AI 管理中心
linux·人工智能·nacos
2601_962177303 天前
2026年AI API Gateway怎么选?我整理了6种方案的费用、稳定性和适用场景
网络·人工智能·深度学习·gateway
Wang's Blog4 天前
Java框架 SpringCloud 快速入门: Gateway 路由的过滤器配置
java·spring cloud·gateway