当前位置: 首页 > news >正文

RuoYi-Cloud 接入 Sentinel 的 3 种限流方式

场景:

  • 服务:ruoyi-robot(对外接口统一在 /external/gs/**

  • 网关:ruoyi-gateway(转发到 ruoyi-robot

  • 注册/配置:Nacos

  • 流控:Sentinel 1.8.x + 控制台 Dashboard(我用 8718 端口)

  • 目标:既能“一把梭”限整个对外能力(按 URL 前缀),也能给个别 API 做业务化兜底提示

总览:三种限流姿势放在一起怎么选?

方案生效层级是否改 robot 代码规则是否持久化命中后的典型返回适用场景
A. 服务内方法级 @SentinelResource服务要(按方法)可持久化,也可不持久化200 + 业务 JSON(我自定义429精细化/业务化兜底
B. 网关控制台临时规则网关HTTP 500(默认)演示/排障,重启丢失
C. 网关 API 分组 + Nacos 规则(推荐)网关✅(Nacos)HTTP 500给整组 URL 做统一限流

官方参考文档:服务网关 | RuoYi

A. 服务内方法级限流(@SentinelResource

1)服务接入 Sentinel 控制台

ruoyi-robot-dev.yml(节选)

spring:cloud:sentinel:eager: truetransport:dashboard: 127.0.0.1:8718

目的:ruoyi-robot 也把自身资源(URL、注解资源)上报到控制台,便于在服务内做细粒度流控/降级。

2)对具体方法加注解与兜底方法

/external/gs/robots 为例

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;@SentinelResource(value = "listRobots",blockHandler = "listRobotsBlockHandler",fallback = "listRobotsFallback")
@GetMapping("/robots")
public AjaxResult listRobots(@RequestParam(value = "robotSn", required = false) String robotSn) {// ...业务逻辑...return AjaxResult.success(robots);
}/** 限流/熔断被触发时走这里(签名要匹配,最后一个参数必须是 BlockException) */
public AjaxResult listRobotsBlockHandler(String username, BlockException ex) {return AjaxResult.error("请求超过最大数,请稍候再试"); // 你现在返回的是 code=429 的 JSON
}

注意

  • blockHandler/fallback 方法的返回类型要与原方法一致,参数也要能匹配(blockHandler 最后必须有 BlockException)。

  • 兜底方法可以写到同类或独立类(独立类需 public static)。

3)命中时的返回差异

  • 这种方式是在服务内处理,你返回的是 业务 JSON(比如 {"code":429,"msg":"Too Many Requests"}),HTTP 状态多半还是 200

  • 如果你希望连 HTTP 状态也用 429,可以在 blockHandler抛出带 429 的异常并用全局异常处理器转成响应;或统一让网关(方案 A/B)兜底。

4)如何“看见”和“控住”这个资源

  • 只要接口被调用一次,控制台就会在 ruoyi-robotsentinel_spring_web_context 和你自定义的 "listRobots" 资源下出现统计。

  • ruoyi-robot 应用上新增一条针对 listRobots流控规则(比如 QPS=1),即可触发 blockHandler

B. 网关控制台临时规则(不持久化)

  • 做法:直接在 Sentinel 控制台给 ruoyi-gateway 新增流控规则(可选按 Route,也可选 API 分组)。

  • 特点:重启规则就没了,适合验想法/演示。

  • 行为:和 A 一样,返回 500,只是数据不落 Nacos。

C. 网关「API 分组」限流

1)Nacos 保存网关规则(持久化)

  • API 分组定义ruoyi-gateway-gw-api-defs

  • [{"apiName": "external-gs-api","predicateItems": [{ "pattern": "/external/gs/**", "matchStrategy": 1 }]}
    ]
    

    分组限流规则ruoyi-gateway-gw-flow

  • [{"resource": "external-gs-api","resourceMode": 1,   // 1=API分组, 0=Route"grade": 1,          // 1=QPS"count": 1,          // 阈值 1 QPS"intervalSec": 1,"controlBehavior": 0,// 直接拒绝"burst": 0}
    ]
    

    2)网关接入 Sentinel 与 Nacos 数据源

    ruoyi-gateway-dev.yml(节选)

    spring:cloud:sentinel:eager: truetransport:dashboard: 127.0.0.1:8718datasource:gw-api:nacos:server-addr: localhost:8848group-id: DEFAULT_GROUPnamespace: publicdata-id: ruoyi-gateway-gw-api-defsdata-type: jsonrule-type: gw-api-groupgw-flow:nacos:server-addr: localhost:8848group-id: DEFAULT_GROUPnamespace: publicdata-id: ruoyi-gateway-gw-flowdata-type: jsonrule-type: gw-flow
    

    3)验证

# 连续高频请求
curl -i http://localhost:8080/external/gs/robots

curl -i http://localhost:8080/external/gs/robots
命中限流时:HTTP/1.1 500 Too Many Requests,终端能看到 Blocked by Sentinel (flow limiting)。

Sentinel 控制台:在 ruoyi-gateway 应用下,请求链路 / API 管理 都能看到 external-gs-api 的统计与规则。

    Sentinel 限流常见问题与修复方案

    FAQ 1:Code200,401令牌不能为空

    症状

    • 压测的时候报Code200,401令牌不能为空

    根因

    • ruoyi-gateway-dev.yml中验证码没关

    • 没有为你的自定义API设置白名单

    修复

    • captcha中把enabled改为:false

    • 在ignore中为你的API设置白名单

    FAQ 2:控制台看不到实例 / 资源列表是空的

    症状

    • Sentinel 控制台没有 ruoyi-gatewayruoyi-robot 实例

    • 或者“资源链路”里没有 URL/方法名

    根因

    • Dashboard 端口不一致 / 服务没连上

    • Sentinel 默认懒加载,未触发调用不汇报

    • 依赖缺失 / 网段不通

    修复

    • application-*-dev.yml 开启:

    spring:cloud:sentinel:eager: truetransport:dashboard: 127.0.0.1:8718
    

    启动 Dashboard(端口一致):

    java -Dserver.port=8718 \-Dcsp.sentinel.dashboard.server=localhost:8718 \-Dcsp.sentinel.api.port=8719 \-jar sentinel-dashboard-1.8.x.jar
    

    打一次接口触发资源上报:

    curl -i http://localhost:8080/external/gs/robots
    

    FAQ 3:Nacos 已配规则,但网关不生效

    症状

    • 控制台能看到实例,但限流不触发,或“API 管理”看不到你的分组。

    根因

    • DataId / group / namespace / rule-type / data-type 任一不匹配

    • JSON 不合法

    • 你自定义的API类在Nacos没有设置Sentinel

    修复清单

    • ruoyi-gateway-dev.yml 的数据源必须与 Nacos 完全一致:

    • gw-api-defsgw-flowapiName/resource 要对应(你用的是 external-gs-api)。

      datasource:gw-api:nacos:server-addr: localhost:8848group-id: DEFAULT_GROUPnamespace: publicdata-id: ruoyi-gateway-gw-api-defsdata-type: jsonrule-type: gw-api-groupgw-flow:nacos:server-addr: localhost:8848group-id: DEFAULT_GROUPnamespace: publicdata-id: ruoyi-gateway-gw-flowdata-type: jsonrule-type: gw-flow
      
    • 以ruoyi-robot-dev.yml为例,增加配置

      spring:cloud:sentinel:# 取消控制台懒加载eager: truetransport:# 控制台地址dashboard: 127.0.0.1:8718

    FAQ 4:我压不出 429,是不是没生效?

    可能原因

    • 阈值太高 / 压测强度不够

    • burstintervalSec 没理解

    修复

    • 先把阈值设成 count: 1intervalSec: 1 做冒烟。

    • 命令行快速压测:

    # Linux/Mac
    for i in {1..10}; do curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/external/gs/robots; done# Windows(PowerShell)
    1..10 | % { (Invoke-WebRequest -UseBasicParsing http://localhost:8080/external/gs/robots).StatusCode }
    

    FAQ 5:怎么区分 B 与 C

        1.看控制台“API类型”这一列

    • C(API 分组/Nacos 下发):在 ruoyi-gateway → API管理 必须能看到 external-gs-api;对应的流控规则里“API 类型”显示 自定义API,API 名称就是 external-gs-api

    • B(Route ID 临时规则/控制台添加):在 ruoyi-gateway → 流控规则 里“API 类型”显示 Route ID,比如 ruoyi-robot(你的第二张图就是这个)。

         2.看“重启后的持久性”

    • C:重启 gateway 后,规则会 自动重新出现(来自 Nacos 的 gw-api-defs / gw-flow)。

    • B:如果你只是控制台临时添加,重启就没了(除非你的控制台本身配置了 Nacos Publisher,把它也持久化到 Nacos——多数环境没配)。

         3.看配置是否存在

    • C 必须有 gateway 里的这段 datasource 配置 + Nacos 中的两个 DataId:
      ruoyi-gateway-gw-api-defs(API 分组)和 ruoyi-gateway-gw-flow(分组流控)。

    • B 不需要这两个 DataId,单靠控制台在 “流控规则(Route ID)” 新增就能生效。

        4.看“API管理”页面是否有分组

    • Cexternal-gs-api 一定会出现在 API管理 列表里。

    • B:API管理可以是空的(就像你第一张图),依然能在“流控规则”里对 Route ID 限流。

    http://www.lryc.cn/news/619876.html

    相关文章:

  • Android 双屏异显技术全解析:从原理到实战的多屏交互方案
  • Ubuntu 20.04 虚拟机安装完整教程:从 VMware 到 VMware Tools
  • 基于.Net Framework4.5 Web API 引用Swagger
  • nginx高性能web服务器实验
  • INTERSPEECH 2025 | 数据堂诚邀您参加MLC-SLM挑战赛暨研讨会
  • JVM安全点轮询汇编函数解析
  • 【个人简单记录】PLT,GOT函数加载机制
  • 海康视觉平台VM创建项目
  • FxSound:为你的音频体验注入专业级享受
  • Android图片加载库Glide深度解析与实践指南
  • 4 种方法将联系人从 iPhone 传输到 realme
  • 用了Cursor AI之后,我的编程效率翻倍了?——一位程序员的真实体验分享
  • 小迪23年-32~40——java简单回顾
  • Dots.ocr:告别复杂多模块架构,1.7B参数单一模型统一处理所有OCR任务22
  • 直播预告|鸿蒙生态中的AI新玩法
  • 09--解密栈与队列:数据结构核心原理
  • 图像分割-动手学计算机视觉9
  • 算法提升-树上问题之(dfs序)
  • WPF的c1FlexGrid的动态列隐藏和动态列名设置
  • 《设计模式之禅》笔记摘录 - 15.观察者模式
  • WMware的安装以及Ubuntu22的安装
  • MCP协议更新:从HTTP+SSE到Streamable HTTP,大模型通信的进化之路
  • 学习STM32 脉冲计数实验
  • 猫头虎AI分享:Word MCP,让AI具备Word文档操作能力,文档创建、内容添加、格式编辑等AI能力
  • HGDB的分区表实现SQL Server的分区视图
  • 健永科技工业自动化RFID解决方案
  • Maven配置Docker插件推送至远程私有仓库
  • 相机按键功能解析
  • python基于Hadoop的超市数据分析系统
  • SODA自然美颜相机(甜盐相机国际版) v9.3.0