ruoyi-vue-pro 开发指南 ruoyi-vue-pro 开发指南
  • 萌新必读
  • 后端手册
  • 中间件手册
  • 工作流手册
  • 报表与大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
  • 运维手册
  • 前端手册 Vue 3.x
  • 前端手册 Vben 5.x
  • 前端手册 Vue 2.x
  • 前端手册 Admin Uniapp
  • 工作流手册
  • 报表与大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
视频教程
  • Vue3 + element-plus (opens new window)
  • Vue3 + vben5(ant-design-vue、element-plus) (opens new window)
  • Vue2 + element-ui (opens new window)
微服务版 (opens new window)
作者博客 (opens new window)
GitHub (opens new window)
  • 萌新必读
  • 后端手册
  • 中间件手册
  • 工作流手册
  • 报表与大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
  • 运维手册
  • 前端手册 Vue 3.x
  • 前端手册 Vben 5.x
  • 前端手册 Vue 2.x
  • 前端手册 Admin Uniapp
  • 工作流手册
  • 报表与大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
视频教程
  • Vue3 + element-plus (opens new window)
  • Vue3 + vben5(ant-design-vue、element-plus) (opens new window)
  • Vue2 + element-ui (opens new window)
微服务版 (opens new window)
作者博客 (opens new window)
GitHub (opens new window)
  • 萌新必读

    • 简介
    • 交流群
    • 视频教程
    • 功能列表
    • 快速启动(后端项目)
    • 快速启动(前端项目)
    • 接口文档
    • 技术选型
    • 项目结构
    • 代码热加载
    • 一键改包
    • 迁移模块(适合新项目)
    • 删除功能(以租户为例)
    • 表结构变更(版本升级)
    • 国产信创数据库(DM 达梦、大金、OpenGauss、瀚高、OceanBase、TiDB、GaussDB、PolarDB、神通、Vastbase、MogDB、TongRDS、CacheDB)
    • 如何去除 Redis 缓存
    • 面试题、简历模版、简历优化
    • 项目外包
    • 文档 MCP
  • 后端手册

    • 新建模块
    • 代码生成【单表】(新增功能)
    • 代码生成【主子表】
    • 代码生成(树表)
    • 代码生成(移动端)
    • 功能权限
    • 数据权限
    • 用户体系
    • 三方登录
    • OAuth 2.0(SSO 单点登录)
    • SaaS 多租户【字段隔离】
    • SaaS 多租户【数据库隔离】
    • WebSocket 实时通信
    • 异常处理(错误码)
    • 参数校验、时间传参
    • 分页实现
    • VO 对象转换、数据翻译
    • 文件存储(上传下载)
    • Excel 导入导出
    • 操作日志、访问日志、异常日志
    • MyBatis 数据库
    • MyBatis 联表&分页查询
    • 多数据源(读写分离)、事务
    • Redis 缓存
    • 本地缓存
    • 异步任务
    • 分布式锁
    • 幂等性(防重复提交)
    • 请求限流(RateLimiter)
    • HTTP 接口签名(防篡改)
    • HTTP 接口加解密
    • 单元测试
    • 验证码
    • 工具类 Util
    • 配置管理
    • 数据库文档
  • 中间件手册

    • 定时任务
    • 消息队列(内存)
    • 消息队列(Redis)
    • 消息队列(RocketMQ)
    • 消息队列(RabbitMQ)
    • 消息队列(Kafka)
    • 限流熔断
      • 1. 方案说明
        • 1.1 与 @RateLimiter 的区别
        • 1.2 限流与熔断
        • 1.3 示例
      • 2. 获取集成材料
      • 3. 接入步骤
        • 3.1 添加依赖
        • 3.2 复制规则与示例代码
        • 3.3 启动 Sentinel Dashboard(可选)
        • 3.4 启动验证
      • 4. 使用说明
        • 4.1 资源与 @SentinelResource
        • 4.2 限流规则
        • 4.3 熔断规则
        • 4.4 规则持久化
        • 4.5 单机阈值
        • 4.6 自动统计所有接口(可选)
        • 4.7 安全注意事项
      • 5. 常见问题
        • 5.1 请求没有被限流、熔断
        • 5.2 被限流时,返回「系统异常」
        • 5.3 报错 JsonParseException 等规则解析失败
        • 5.4 Dashboard 中看不到应用
    • 分库分表
    • 分布式事务
  • 工作流手册

    • 工作流演示
    • 功能开启
    • 工作流(达梦适配)
    • 审批接入(流程表单)
    • 审批接入(业务表单)
    • 流程设计器(BPMN)
    • 流程设计器(钉钉、飞书)
    • 选择审批人、发起人自选
    • 会签、或签、依次审批
    • 流程发起、取消、重新发起
    • 审批通过、不通过、驳回
    • 审批加签、减签
    • 审批转办、委派、抄送
    • 执行监听器、任务监听器
    • 流程表达式
    • 流程审批通知
    • 移动端审批
  • 报表与大屏手册

    • 功能总览
    • UReport2 报表
    • 积木报表与仪表盘
    • GoView 大屏
  • 支付手册

    • 功能开启
    • 支付宝支付接入
    • 微信公众号支付接入
    • 微信小程序支付接入
    • 支付宝、微信退款接入
    • 支付宝转账接入
    • 微信转账接入
    • 钱包充值、支付、退款
    • 模拟支付、退款
    • 移动端支付管理
  • 会员手册

    • 功能开启
    • 微信公众号登录
    • 微信小程序登录
    • 微信小程序订阅消息
    • 微信小程序码
    • 会员用户、标签、分组
    • 会员等级、积分、签到
    • 移动端会员管理
  • 商城手册

    • 商城演示
    • 功能开启
    • 商城装修
    • 在线客服
    • 【商品】商品分类
    • 【商品】商品属性
    • 【商品】商品 SPU 与 SKU
    • 【商品】商品评价
    • 【交易】购物车
    • 【交易】交易订单
    • 【交易】售后退款
    • 【交易】快递发货
    • 【交易】门店自提
    • 【交易】分销返佣
    • 【营销】优惠劵
    • 【营销】积分商城
    • 【营销】拼团活动
    • 【营销】秒杀活动
    • 【营销】砍价活动
    • 【营销】满减送活动
    • 【营销】限时折扣
    • 【营销】内容管理
    • 【统计】会员、商品、交易统计
    • 移动端商城管理
  • ERP手册

    • ERP 演示
    • 功能开启
    • 【产品】产品信息、分类、单位
    • 【库存】产品库存、库存明细
    • 【库存】其它入库、其它出库
    • 【库存】库存调拨、库存盘点
    • 【采购】采购订单、入库、退货
    • 【销售】销售订单、出库、退货
    • 【财务】采购付款、销售收款
    • 移动端 ERP
  • CRM手册

    • CRM 演示
    • 功能开启
    • 【线索】线索管理
    • 【客户】客户管理、公海客户
    • 【商机】商机管理、商机状态
    • 【合同】合同管理、合同提醒
    • 【回款】回款管理、回款计划
    • 【产品】产品管理、产品分类
    • 【通用】数据权限
    • 【通用】跟进记录、待办事项
    • 移动端 CRM
  • AI大模型手册

    • AI 大模型演示
    • 功能开启
    • AI 聊天对话
    • AI 绘画创作
    • AI 知识库(RAG)
    • AI 音乐创作
    • AI 写作助手
    • AI 思维导图
    • AI 工具(function calling)
    • AI 工作流
    • Dify 工作流
    • FastGPT 工作流
    • Coze 智能体
    • 推理模式(thinking)
    • 联网搜索
    • MCP Client 客户端
    • MCP Server 服务端
    • 请求日志与 Token 用量
    • 【模型接入】小米 MiMo
    • 【模型接入】Claude
    • 【模型接入】OpenAI
    • 【模型接入】通义千问
    • 【模型接入】DeepSeek
    • 【模型接入】字节豆包
    • 【模型接入】腾讯混元
    • 【模型接入】硅基流动
    • 【模型接入】MiniMax
    • 【模型接入】月之暗面
    • 【模型接入】百川智能
    • 【模型接入】文心一言
    • 【模型接入】LLAMA
    • 【模型接入】智谱 GLM
    • 【模型接入】讯飞星火
    • 【模型接入】微软 OpenAI
    • 【模型接入】谷歌 Gemini
    • 【模型接入】Stable Diffusion
    • 【模型接入】Midjourney
    • 【模型接入】Suno
    • 【模型接入】Grok
    • 【模型接入】阶跃星辰
    • 移动端 AI 大模型
  • IoT物联网手册

    • 功能开启
    • 产品管理
    • 设备管理
    • 物模型配置
    • 设备网关与子设备
    • 设备动态注册
    • 设备影子
    • 消息透传与数据解析
    • 设备接入(概述)
    • 设备接入(HTTP 协议)
    • 设备接入(MQTT 协议)
    • 设备接入(EMQX 协议)
    • 设备接入(TCP 协议)
    • 设备接入(UDP 协议)
    • 设备接入(WebSocket 协议)
    • 设备接入(CoAP 协议)
    • 设备接入(Modbus Client 模式)
    • 设备接入(Modbus Server 模式)
    • 设备接入(自定义协议)
    • 场景联动
    • 数据流转
    • 告警配置
    • OTA 固件升级
    • 移动端 IoT 物联网
    • 设备网关合并部署
  • MES手册

    • MES 演示
    • 功能开启
    • 【基础】物料产品、分类、计量单位
    • 【基础】客户管理、供应商管理
    • 【基础】车间设置、工作站设置
    • 【基础】编码规则
    • 【生产】工序设置、工艺流程
    • 【生产】生产工单
    • 【生产】生产排产、工序流转卡
    • 【生产】生产报工
    • 【生产】安灯配置、安灯呼叫
    • 【生产】工作记录
    • 【仓库】仓库与库区库位、条码赋码、SN码
    • 【仓库】批次管理、库存现有量、库存事务
    • 【仓库】到货通知、采购入库、采购退货
    • 【仓库】生产领料、生产退料、物料消耗
    • 【仓库】产品产出、产品入库
    • 【仓库】发货通知、销售出库、销售退货
    • 【仓库】外协发料、外协入库
    • 【仓库】其他入库、其他出库
    • 【仓库】调拨单、装箱管理
    • 【仓库】库存盘点
    • 【质量】检测项设置、常见缺陷
    • 【质量】质检方案
    • 【质量】来料检验(IQC)
    • 【质量】过程检验(IPQC)
    • 【质量】出货检验(OQC)
    • 【质量】退货检验(RQC)
    • 【质量】待检任务、检验结果、缺陷记录
    • 【设备】设备类型、设备台账
    • 【设备】点检保养项目、点检保养方案
    • 【设备】点检记录、保养记录、维修单
    • 【工具】工具类型、工装夹具台账
    • 【排班】班组设置、节假日设置
    • 【排班】排班计划、排班日历
    • 移动端 MES
  • WMS手册

    • WMS 演示
    • 功能开启
    • 【基础】仓库
    • 【基础】商品、SKU、分类、品牌
    • 【基础】往来企业(供应商、客户)
    • 【库存】库存记录、流水、统计
    • 【单据】入库
    • 【单据】出库
    • 【单据】移库
    • 【单据】盘库
    • 【其它】WMS、MES、ERP 对比
    • 移动端 WMS
  • HRM人力资源

    • HRM 演示
    • 功能开启
    • 【组织】工作台、组织架构
    • 【员工】员工管理
    • 【招聘】招聘管理
    • 【考勤】考勤管理
    • 【社保】社保管理
    • 【薪资】计薪设置、薪资档案
    • 【薪资】月度工资、工资条
    • 【绩效】绩效模板、绩效计划
    • 【绩效】绩效考核、绩效档案
    • 移动端 HRM
  • FMS财务管理

    • FMS 演示
    • 功能开启
    • 【设置】账套管理、财务参数、财务指标
    • 【设置】币别、科目、辅助核算、初始余额
    • 【设置】凭证字、常用摘要、凭证模板
    • 【凭证】凭证管理
    • 【账簿】账簿管理
    • 【报表】财务报表
    • 【结账】期末结账
    • 移动端 FMS
  • PMS项目管理

    • PMS 演示
    • 功能开启
    • 【项目中心】工作台与项目管理
    • 【项目中心】项目详情与迭代
    • 【项目中心】工作项与协作
    • 【知识中心】知识库管理
    • 【知识中心】文档与协作
    • 移动端 PMS
  • OA协同办公

    • OA 演示
    • 功能开启
    • 【协作】日程、任务、计划与汇报
    • 【协作】公告、讨论、通讯录与笔记
    • 【办公】企业邮箱
    • 【办公】企业云盘
    • 【行政】办公用品、用印管理
    • 【行政】会议室、车辆管理
    • 【流程】公文管理
    • 【流程】出差、费用报销
    • 【流程】考勤、请假、加班、转正与离职
    • 移动端 OA
  • IM即时通讯手册

    • IM 演示
    • 功能开启
    • 【好友】好友关系、好友申请
    • 【群聊】群组、群成员、入群申请
    • 【消息】私聊、群聊、频道消息
    • 【频道】频道、频道素材
    • 【内容】表情、敏感词
    • 【通话】语音通话、视频通话、共享屏幕
    • 【WebSocket】实时推送与离线消息
    • 移动端 IM 即时通讯
  • 公众号手册

    • 功能开启
    • 公众号接入
    • 公众号粉丝
    • 公众号标签
    • 公众号消息
    • 模版消息
    • 自动回复
    • 公众号菜单
    • 公众号素材
    • 公众号图文
    • 公众号统计
    • 移动端公众号管理
  • 系统手册

    • 短信配置
    • 邮件配置
    • 站内信配置
    • Webhook(钉钉、飞书、企微)
    • 数据脱敏、字段权限
    • 敏感词
    • 地区 & IP 库
  • 运维手册

    • 开发环境
    • Linux 部署
    • Docker 部署
    • Jenkins 部署
    • 宝塔部署
    • 1Panel 部署
    • Docker Compose 部署
    • Kubernetes 部署
    • HTTPS 证书
    • 服务监控
    • 生产环境安全
    • Tomcat WAR 部署
    • 东方通服务器部署(TongWeb、TongHttpServer)
    • 宝兰德服务器部署(BES AppServer)
    • 内网穿透
  • 前端手册 Vue 3.x

    • 开发规范
    • 菜单路由
    • Icon 图标
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
    • CRUD 组件
    • 国际化
    • IDE 调试
    • 代码格式化
  • 前端手册 Vben 5.x

    • 开发规范
    • 菜单路由
    • 图标、主题、国际化
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
    • IDE 调试
    • 代码格式化
  • 前端手册 Vue 2.x

    • 开发规范
    • 菜单路由
    • Icon 图标
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
  • 前端手册 Admin Uniapp

    • 开发规范
    • 菜单路由
    • 图标、主题、国际化
    • 字典数据
    • 系统组件
    • 通用方法
    • IDE 调试
    • 代码格式化
    • 运行发布
  • 更新日志

    • 【v2026-11】
    • 【v2026-10】
    • 【v2026-09】
    • 【v2026-08】
    • 【v2026-07】
    • 【v2026-06】
    • 【v2026-05】
    • 【v2026-04】
    • 【v2026-03】
    • 【v2026-01】
    • 【v2025-12】
    • 【v2025-11】
    • 【v2025-10】
    • 【v2025-09】
    • 【v2025-08】
  • 开发指南
  • 中间件手册
芋道源码
2022-04-10
目录

限流熔断

项目默认没有接入 Sentinel。yudao-spring-boot-starter-protection (opens new window) 组件本身也不包含 Sentinel,它提供的是基于 Redis(Redisson)的 《请求限流(RateLimiter)》、《幂等性》、《分布式锁》。

需要按 QPS 限流、按慢调用或异常比例熔断,并且规则与代码分离时,可以基于 Sentinel (opens new window) 按需接入,实际使用的依赖版本见《3.1 添加依赖》小节:

  • 只有添加了 @SentinelResource 注解、并且配置了规则的资源,才会被限流、熔断,其它接口不受影响。
  • 示例的规则从 classpath 中的 JSON 文件加载,只保存在 JVM 内存中,参见《4.4 规则持久化》小节。
  • 单体项目不需要、也不要为了 Sentinel 引入 Spring Cloud、Spring Cloud Alibaba,只使用 Sentinel 自己的核心及注解切面。

友情提示:

微服务项目 yudao-cloud 在网关、服务、Feign 中接入 Sentinel,并将规则持久化到 Nacos,参见 《服务保障》 (opens new window) 文档。

# 1. 方案说明

# 1.1 与 @RateLimiter 的区别

两者解决的问题不同,可以同时使用:

@RateLimiter Sentinel
计数位置 Redis,多个实例共享同一个计数,是全局的配额 每个 JVM 进程的内存,阈值是单机的,参见《4.5 单机阈值》小节
限流维度 时间窗口内最多 N 次,可以按全局、用户、IP、服务节点、Spring EL 表达式分别计数 按资源的 QPS 或并发线程数,支持快速失败、预热、匀速排队
熔断降级 不支持 慢调用比例、异常比例、异常数
规则 注解的属性,修改后需要重新发布 与代码分离,示例从 JSON 文件加载,也可以接入 Nacos 等动态数据源
外部依赖 Redis 无,Dashboard 可选
被限制时 抛出 ServiceException,code = 429 调用 blockHandler,示例返回 CommonResult 错误码

简单来说:「每个用户每分钟只能发送 1 次短信」这类业务配额,使用 @RateLimiter;「保护服务实例不被流量压垮、依赖变慢时快速失败」这类流量防护,使用 Sentinel。

# 1.2 限流与熔断

① 限流(FlowRule):保护当前接口。单位时间内超过阈值的请求直接拒绝。

② 熔断(DegradeRule):保护调用链路。资源的慢调用比例、异常比例超过阈值时,在熔断时长内直接拒绝,不再等待它变慢或出错;熔断时长结束后,放行一个探测请求,成功则恢复,失败则继续熔断。通常加在调用数据库、第三方接口等依赖的方法上。

两者被触发时,都由 @SentinelResource 的 blockHandler 方法决定返回什么。

# 1.3 示例

示例的接口在 yudao-module-infra 模块中,需要登录:

接口 资源名 规则 被阻断时
GET /admin-api/infra/sentinel-demo/flow demo-sentinel-flow 限流:QPS 2 code = 429,msg = "请求过于频繁,请稍后重试"
GET /admin-api/infra/sentinel-demo/degrade?slow=false demo-sentinel-degrade 熔断:慢调用比例,slow=true 时等待 500 毫秒模拟慢调用 code = 503,msg = "服务暂时不可用,请稍后重试"

被阻断时,与 @RateLimiter 一样,返回 HTTP 200 + CommonResult 错误码,前端按业务错误码的方式提示 msg。

# 2. 获取集成材料

集成材料在项目的 script/sentinel/ (opens new window) 目录。目前只有 master-jdk17 分支提供这些材料,master、master-jdk25 分支请先从 master-jdk17 分支获取,同步到对应分支后,也可以直接从当前分支获取。材料按下面三个分支的 API 编写,接入步骤相同,兼容差异如下:

分支 JDK Spring Boot 差异
master 8 2.7.18 无。Sentinel 1.8.10 的常规类按 Java 8 字节码发布
master-jdk17 17 3.5.15 无
master-jdk25 25 4.1.2 无需修改材料。Sentinel 官方没有声明对 Spring Boot 4、Spring Framework 7 的适配,接入后以实际的启动、请求验证为准

示例代码只使用 Java 8 语法,不引用 javax、jakarta 包,规则通过项目的 JsonUtils 解析,不区分 Jackson 2、Jackson 3,所以三个分支无需修改。

目录中的文件及用途如下:

文件 说明 目标位置
dependencies.xml Maven 依赖片段:第 1 段 Sentinel 核心及注解切面(必须),第 2 段与 Dashboard 通信的模块(可选) yudao-module-infra/pom.xml
src/main/resources/sentinel/demo-flow-rules.json 限流规则 yudao-module-infra/src/main/resources/sentinel/
src/main/resources/sentinel/demo-degrade-rules.json 熔断规则 yudao-module-infra/src/main/resources/sentinel/
src/main/java/.../infra/sentineldemo/DemoSentinelConfiguration.java 注册 SentinelResourceAspect 切面,启动时加载上面两个规则文件 yudao-module-infra/src/main/java/ 的同名包
src/main/java/.../infra/sentineldemo/controller/admin/DemoSentinelController.java 示例接口,及被阻断时的 blockHandler yudao-module-infra/src/main/java/ 的同名包

# 3. 接入步骤

# 3.1 添加依赖

将 dependencies.xml 第 1 段的依赖,复制到 yudao-module-infra/pom.xml 中:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.10</version>
</dependency>
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-annotation-aspectj</artifactId>
    <version>1.8.10</version>
</dependency>

① 添加到包含 Sentinel 代码的模块,示例是 yudao-module-infra;yudao-server 已经依赖它,会传递获得。只加在 yudao-server/pom.xml 时,yudao-module-infra 编译失败。

② 单体项目没有 Spring Cloud Alibaba 的 BOM,所以显式指定版本,多个 Sentinel 依赖的版本必须一致。sentinel-annotation-aspectj 传递依赖的 aspectjweaver,版本由项目的 Spring Boot BOM 统一管理,不会改变项目原有的版本。

③ @SentinelResource 依赖 Spring AOP,项目的 Security 组件已经引入,不需要额外添加。

④ 需要使用 Sentinel Dashboard 时,再添加第 2 段的 sentinel-transport-simple-http,参见《3.3 启动 Sentinel Dashboard》小节。

# 3.2 复制规则与示例代码

① 将 src/main/resources/sentinel/ 目录,复制到 yudao-module-infra/src/main/resources/ 下。

demo-flow-rules.json:

[
  {
    "resource": "demo-sentinel-flow",
    "limitApp": "default",
    "grade": 1,
    "count": 2,
    "strategy": 0,
    "controlBehavior": 0,
    "clusterMode": false
  }
]

demo-degrade-rules.json:

[
  {
    "resource": "demo-sentinel-degrade",
    "grade": 0,
    "count": 200,
    "slowRatioThreshold": 0.5,
    "minRequestAmount": 3,
    "statIntervalMs": 10000,
    "timeWindow": 10
  }
]

即:资源 demo-sentinel-flow 每秒最多通过 2 个请求;资源 demo-sentinel-degrade 在 10 秒内至少有 3 个请求、并且响应时间超过 200 毫秒的比例超过 50% 时,熔断 10 秒。规则文件必须是严格的 JSON,不能包含 // 注释,字段的含义参见《4.2 限流规则》、《4.3 熔断规则》小节。

② 将 src/main/java 下的 cn.iocoder.yudao.module.infra.sentineldemo 包,复制到 yudao-module-infra/src/main/java 的同名目录:

  • DemoSentinelConfiguration:注册 SentinelResourceAspect 切面,让 @SentinelResource 注解生效;通过 SmartInitializingSingleton,在所有单例 Bean 初始化之后、Web 服务器开始接收请求之前,加载上面两个规则文件。
  • controller/admin/DemoSentinelController:示例接口。放在 controller.admin 包下,才会和项目其它管理后台接口一样,添加 /admin-api 前缀。

示例接口的核心代码如下:

@GetMapping("/flow")
@SentinelResource(value = "demo-sentinel-flow", blockHandler = "flowBlockHandler")
public CommonResult<String> flow() {
    return success("flow");
}

@GetMapping("/degrade")
@SentinelResource(value = "demo-sentinel-degrade", blockHandler = "degradeBlockHandler",
        exceptionsToIgnore = ServiceException.class) // 业务异常不计入异常比例、异常数的熔断统计,由全局异常处理器照常返回错误码
public CommonResult<String> degrade(@RequestParam(value = "slow", defaultValue = "false") Boolean slow) {
    if (Boolean.TRUE.equals(slow)) {
        ThreadUtil.sleep(500); // 模拟慢调用:超过熔断规则中 200 毫秒的最大响应时间
        return success("slow");
    }
    return success("ok");
}

// blockHandler:被 Sentinel 阻断时调用。参数为原方法的参数 + BlockException,返回值类型与原方法相同
public CommonResult<String> flowBlockHandler(BlockException ex) {
    return buildBlockResult(ex);
}

public CommonResult<String> degradeBlockHandler(Boolean slow, BlockException ex) {
    return buildBlockResult(ex);
}

private static <T> CommonResult<T> buildBlockResult(BlockException ex) {
    if (ex instanceof DegradeException) { // 熔断
        return CommonResult.error(HttpStatus.SERVICE_UNAVAILABLE.value(), "服务暂时不可用,请稍后重试");
    }
    return CommonResult.error(TOO_MANY_REQUESTS); // 限流等其它阻断
}

# 3.3 启动 Sentinel Dashboard(可选)

Sentinel Dashboard (opens new window) 用于查看实时的 QPS、阻断次数,以及资源名,不是必须的:不启动 Dashboard,规则照常生效。

① 从 Sentinel 的 Releases (opens new window) 下载 sentinel-dashboard-1.8.10.jar,它是独立的 Spring Boot 应用,与项目使用的 JDK 版本无关。设置好 SENTINEL_DASHBOARD_PASSWORD 环境变量后启动:

java -Dserver.address=127.0.0.1 -Dserver.port=8858 \
  -Dsentinel.dashboard.auth.username=sentinel \
  -Dsentinel.dashboard.auth.password="${SENTINEL_DASHBOARD_PASSWORD}" \
  -jar sentinel-dashboard-1.8.10.jar
  • -Dserver.address=127.0.0.1:只在本机监听,yudao-server 与 Dashboard 运行在同一台机器上。
  • -Dserver.port=8858:Dashboard 默认使用 8080 端口,改为 8858,避免与其它程序冲突。
  • sentinel.dashboard.auth.*:Dashboard 的登录账号,默认是 sentinel / sentinel,不要在共享环境中使用默认密码。

② 将 dependencies.xml 第 2 段的依赖,也添加到 yudao-module-infra/pom.xml 中:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>1.8.10</version>
</dependency>

③ 在 yudao-server 的启动参数(IDEA Run Configuration 的 VM options)中添加:

-Dcsp.sentinel.dashboard.server=127.0.0.1:8858 -Dproject.name=yudao-server -Dcsp.sentinel.api.port=8719
  • csp.sentinel.dashboard.server:Dashboard 的地址。
  • project.name:在 Dashboard 中显示的应用名。
  • csp.sentinel.api.port:Sentinel 在应用中开启的命令端口,Dashboard 通过它拉取监控数据、推送规则,被占用时自动递增。

命令端口没有鉴权

添加 sentinel-transport-simple-http 后,应用会在本机开启上面的命令端口,可以查询、修改规则,并且没有鉴权。只能在本机或内网访问,通过防火墙、安全组限制,不要对公网开放。它还会传递依赖 fastjson(Sentinel 内部的命令处理使用),不会替换项目接口使用的 Jackson。

# 3.4 启动验证

① 启动 yudao-server,日志中出现下面的内容,说明两条规则都已经加载:

[demoSentinelRuleLoader][加载 Sentinel 规则完成,限流规则(1) 条,熔断规则(1) 条]

数量少于 JSON 文件中的规则数时,说明有规则不合法、被 Sentinel 忽略了,例如说 count 小于 0。

② 下面的请求中,Authorization: Bearer test1 是项目的模拟登录:local 环境默认开启 yudao.security.mock-enable,test + 用户编号 1 即可模拟登录,其它环境需要使用登录接口返回的真实访问令牌;tenant-id: 1 是租户编号。

限流:连续请求 5 次,每秒只有 2 个请求通过:

for i in 1 2 3 4 5; do
  curl -s -w '\n' -H 'Authorization: Bearer test1' -H 'tenant-id: 1' \
    'http://127.0.0.1:48080/admin-api/infra/sentinel-demo/flow'
done
{"code":0,"msg":"","data":"flow"}
{"code":0,"msg":"","data":"flow"}
{"code":429,"msg":"请求过于频繁,请稍后重试"}
{"code":429,"msg":"请求过于频繁,请稍后重试"}
{"code":429,"msg":"请求过于频繁,请稍后重试"}

输出仅供参考,字段顺序、是否包含 "data":null 以实际的 JSON 配置为准。限流按 1 秒的滑动窗口统计,第一个请求较慢时,可能有 3 个请求通过,稍等 1 秒再执行一次即可。

③ 熔断:

URL='http://127.0.0.1:48080/admin-api/infra/sentinel-demo/degrade'
H1='Authorization: Bearer test1'; H2='tenant-id: 1'
# 1. 连续 3 次慢调用,每次约 0.5 秒:慢调用比例 100%,超过 50%,熔断 10 秒
for i in 1 2 3; do curl -s -w '\n' -H "$H1" -H "$H2" "$URL?slow=true"; done
# 2. 熔断期间,即使不是慢调用,也直接返回 blockHandler 的错误码
curl -s -w '\n' -H "$H1" -H "$H2" "$URL"
# 3. 10 秒后,第一个请求作为探测放行,成功且不慢,熔断恢复
sleep 10; curl -s -w '\n' -H "$H1" -H "$H2" "$URL"
步骤 结果
1 3 次都成功:code = 0,data = "slow"
2 code = 503,msg = "服务暂时不可用,请稍后重试"
3 code = 0,data = "ok"

④(可选)Dashboard:浏览器访问 http://127.0.0.1:8858 (opens new window) 登录。Sentinel 在第一次进入资源时才初始化,请求一次示例接口后,Dashboard 中才会出现 yudao-server 应用;「簇点链路」中列出了 demo-sentinel-flow、demo-sentinel-degrade 两个资源,「实时监控」中可以看到通过、拒绝的 QPS。添加了第 2 段依赖时,也可以通过命令端口查看内存中的规则:

curl -s 'http://127.0.0.1:8719/getRules?type=flow'
curl -s 'http://127.0.0.1:8719/getRules?type=degrade'

验证完成后,可以删除 DemoSentinelController 及两个示例规则,DemoSentinelConfiguration 中加载规则的方式可以保留,改为加载自己业务的规则。

# 4. 使用说明

# 4.1 资源与 @SentinelResource

资源是 Sentinel 统计、保护的单位,规则通过 resource 字段与资源一一对应。@SentinelResource 可以加在 Controller、Service 等 Spring Bean 的方法上:

属性 说明
value 资源名,必填,与规则的 resource 一致。建议使用「模块-业务-操作」这类稳定的名字,不要包含参数
blockHandler 被限流、熔断时调用的方法:必须是 public,参数为原方法的参数 + BlockException,返回值类型与原方法相同
blockHandlerClass blockHandler 方法在其它类中时指定,此时该方法必须是 static 的,可以用于多个资源共用
exceptionsToIgnore 不计入熔断统计、直接抛出的异常,建议排除 ServiceException 业务异常
fallback、defaultFallback 业务方法抛出异常时的降级方法。没有配置时,异常照常抛出,由全局异常处理器处理;配置时,注意不要吞掉异常、伪造成功的结果

注意事项:

  • 和 @Transactional 一样,基于 Spring AOP 实现:通过 this.xxx() 自调用、private 方法、非 Spring Bean 上的注解不会生效。
  • 没有配置 blockHandler 时,被阻断会抛出 BlockException。它是受检异常,方法没有声明时会变成 UndeclaredThrowableException,由全局异常处理器返回「系统异常」,所以一定要配置 blockHandler。
  • 也可以不使用注解,通过 SphU.entry("资源名") + try-with-resources 的方式定义资源,参见 Sentinel 的 《基本使用》 (opens new window) 文档。

# 4.2 限流规则

demo-flow-rules.json 的字段:

字段 说明
resource 资源名
limitApp 调用来源,default 表示不区分
grade 阈值类型:1 QPS,0 并发线程数
count 阈值,单个实例的
strategy 流控模式:0 直接,1 关联,2 链路
controlBehavior 流控效果:0 快速失败,1 预热(配合 warmUpPeriodSec,单位:秒),2 匀速排队(配合 maxQueueingTimeMs,单位:毫秒)
clusterMode 是否集群限流,保持 false,参见《4.5 单机阈值》小节

# 4.3 熔断规则

demo-degrade-rules.json 的字段:

字段 说明
resource 资源名
grade 熔断策略:0 慢调用比例,1 异常比例,2 异常数
count 慢调用比例时,是最大响应时间(单位:毫秒),超过即为慢调用;异常比例时,是比例阈值(0.0 ~ 1.0);异常数时,是异常的个数
slowRatioThreshold 慢调用比例的阈值(0.0 ~ 1.0),只在慢调用比例时有效
minRequestAmount 统计时长内的最小请求数,请求数不足时不会熔断
statIntervalMs 统计时长,单位:毫秒
timeWindow 熔断时长,单位:秒。到期后放行一个探测请求,成功则恢复,失败则继续熔断

按异常比例、异常数熔断时,业务方法抛出、并且没有被 exceptionsToIgnore 排除的异常才会被统计。所以,要通过 exceptionsToIgnore = ServiceException.class 排除参数错误、余额不足等业务异常,否则用户的错误操作也可能触发熔断。

# 4.4 规则持久化

示例的规则来自 classpath 中的 JSON 文件,只保存在 JVM 内存中:

  • 修改规则:修改 JSON 文件,重新发布或重启。
  • FlowRuleManager.loadRules、DegradeRuleManager.loadRules 会整体替换同一类型的规则,自己的业务有多个规则来源时,需要合并后再加载。
  • 通过 Dashboard 修改的规则,只推送到当前实例的内存中,不会写回 JSON 文件,重启后恢复为 JSON 文件中的规则;有多个实例时,也只修改了其中一台。

需要运行时动态修改、多个实例统一生效时,可以将规则放到 Nacos、Apollo 等配置中心,通过 Sentinel 的数据源扩展(例如说 sentinel-datasource-nacos)注册到 FlowRuleManager.register2Property,替换示例中加载 JSON 文件的方式,参见 Sentinel 的 《动态规则扩展》 (opens new window) 文档,本文不提供。

# 4.5 单机阈值

规则中的 count 是单个实例的阈值,Sentinel 在每个实例的内存中分别计数。yudao-server 部署 3 个实例时,count = 2 的限流规则,整体每秒最多可以通过约 6 个请求。

需要全局、精确的配额时(例如说每个用户每分钟只能调用 N 次),使用基于 Redis 的 《请求限流(RateLimiter)》。Sentinel 的集群流控(Token Server)需要额外的部署和运维,本文不使用。

# 4.6 自动统计所有接口(可选)

示例只保护添加了 @SentinelResource 的接口。如果希望 Sentinel 自动为每个 Spring MVC 接口创建资源(资源名为接口的路径),需要引入 Sentinel 的 Web 适配模块,并注册它的拦截器。它与 Servlet 的包名有关,三个分支不同,本文不提供,只列出差异:

分支 模块 BlockExceptionHandler
master sentinel-spring-webmvc-adapter(javax) com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler,handle(request, response, ex)
master-jdk17 sentinel-spring-webmvc-v6x-adapter(jakarta) com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback.BlockExceptionHandler,handle(request, response, resourceName, ex)
master-jdk25 同 master-jdk17 同 master-jdk17,它面向 Spring Framework 6,在 Spring Framework 7 中需要自行验证

接入时,在 WebMvcConfigurer#addInterceptors 中注册 SentinelWebInterceptor,并通过 SentinelWebMvcConfig#setBlockExceptionHandler 设置返回 CommonResult 的处理器,否则被阻断时返回的是 Sentinel 默认的 Blocked by Sentinel 文本。

# 4.7 安全注意事项

  • 命令端口:参见《3.3 启动 Sentinel Dashboard》小节,只能在本机或内网访问。
  • Dashboard:修改默认的账号密码,只在内网访问。
  • 本文不使用 Sentinel 的授权规则(黑白名单):它依据的调用来源,通常取自客户端可以伪造的请求头,不能替代 Spring Security 的认证、鉴权。

# 5. 常见问题

# 5.1 请求没有被限流、熔断

  • 启动日志中,加载的规则数是否符合预期,参见《3.4 启动验证》小节。
  • 规则的 resource 与 @SentinelResource 的 value 是否完全一致。
  • @SentinelResource 所在的类,是否是 Spring Bean,是否是通过 this.xxx() 自调用。
  • 是否部署了多个实例,请求被负载均衡到了不同的实例上,参见《4.5 单机阈值》小节。

# 5.2 被限流时,返回「系统异常」

没有配置 blockHandler,或者 blockHandler 方法的参数、返回值与原方法不匹配,Sentinel 找不到它,BlockException 变成了 UndeclaredThrowableException。参见《4.1 资源与 @SentinelResource》小节检查方法签名。

# 5.3 报错 JsonParseException 等规则解析失败

规则文件不是严格的 JSON,例如说包含 // 注释、结尾多余的逗号。可以先用 JSON 格式化工具校验。

# 5.4 Dashboard 中看不到应用

  • 是否添加了 sentinel-transport-simple-http 依赖,以及《3.3 启动 Sentinel Dashboard》小节的启动参数。
  • 是否请求过一次示例接口:Sentinel 在第一次进入资源时才初始化、连接 Dashboard。
  • Dashboard 需要反过来访问应用的命令端口:应用在 Docker 等环境中时,通过 -Dcsp.sentinel.heartbeat.client.ip 设置 Dashboard 能够访问到的 IP,并开放对应的端口。

延伸阅读:《芋道 Spring Boot 服务容错 Sentinel 入门》 (opens new window)。

消息队列(Kafka)
分库分表

← 消息队列(Kafka) 分库分表→

Theme by Vdoing | Copyright © 2019-2026 芋道源码 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×