yudao-cloud 开发指南 yudao-cloud 开发指南
  • 萌新必读
  • 后端手册
  • 微服务手册
  • 工作流手册
  • 大屏手册
  • 支付手册
  • 商城手册
  • 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)
    • 面试题、简历模版、简历优化
    • 项目外包
    • 文档 MCP
  • 后端手册

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

    • 微服务调试(必读)
    • 注册中心 Nacos
    • 配置中心 Nacos
    • 服务网关 Spring Cloud Gateway
    • 服务调用 Feign
    • 定时任务 XXL Job
    • 消息队列(内存)
    • 消息队列(Redis)
    • 消息队列(RocketMQ)
    • 消息队列(RabbitMQ)
    • 消息队列(Kafka)
    • 消息队列(Cloud)
    • 分布式事务 Seata
    • 服务保障 Sentinel
      • 1. 方案说明
        • 1.1 与 @RateLimiter 的区别
        • 1.2 整体结构
        • 1.3 限流、熔断与 Feign 降级
        • 1.4 示例
      • 2. 获取集成材料
      • 3. 接入步骤
        • 3.1 启动 Sentinel Dashboard(可选)
        • 3.2 在 Nacos 中创建规则
        • 3.3 添加依赖
        • 3.4 添加配置
        • 3.5 复制示例代码
        • 3.6 启动验证
      • 4. 使用说明
        • 4.1 网关限流:路由与 API 分组
        • 4.2 服务限流:URL 资源与 @SentinelResource
        • 4.3 熔断规则
        • 4.4 Feign 降级
        • 4.5 规则持久化:Nacos 是规则的唯一来源
        • 4.6 单机阈值
        • 4.7 阻断响应与前端
        • 4.8 安全注意事项
      • 5. 常见问题
        • 5.1 修改了 Nacos 中的规则,没有生效
        • 5.2 Dashboard 中,网关显示为普通的应用,没有「API 管理」菜单
        • 5.3 Dashboard 中修改的规则,重启后丢失,或者过一会儿被还原
        • 5.4 被阻断时,返回的是 Blocked by Sentinel 文本,而不是 CommonResult
        • 5.5 Feign 调用失败时,没有进入 fallback
        • 5.6 为 Feign 资源配置规则后,返回「系统异常」
        • 5.7 报错 No bean found of type interface feign.codec.Encoder
        • 5.8 Dashboard 中看不到应用
    • 分库分表
  • 工作流手册

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

    • 报表设计器
    • 大屏设计器
  • 支付手册

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

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

    • 商城演示
    • 功能开启
    • 商城装修
    • 在线客服
    • 【商品】商品分类
    • 【商品】商品属性
    • 【商品】商品 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 服务端
    • 【模型接入】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

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

需要在网关、服务中按 QPS 限流,按慢调用、异常比例熔断,并且在运行时通过 Nacos 动态调整规则时,可以基于 Sentinel (opens new window) + Spring Cloud Alibaba 按需接入,实际使用的依赖版本见《3.3 添加依赖》小节:

  • 只有接入的服务(示例是 gateway-server、system-server)才会创建 Sentinel 资源。没有规则的资源只统计、不拦截,其它服务不受影响。
  • 规则保存在 Nacos 中,服务启动时读取、运行时监听变更,Nacos 是规则的唯一来源,参见《4.5 规则持久化》小节。
  • 被 Sentinel 阻断时,网关、服务都返回 HTTP 429 或 503,以及 CommonResult 格式的 JSON;Feign 只在显式配置了 fallbackFactory 的客户端上降级,项目已有的 Feign 客户端行为不变。

关于社区的 PR

PR #138 (opens new window)(网关、服务集成 Sentinel,规则持久化到 Nacos)、PR #154 (opens new window)(Feign 统一 fallback)提供了很多思路,感谢参与讨论的同学!本文的材料借鉴了其中的网关接入、Nacos 持久化方式,但没有合并这两个 PR:规则改为严格的 JSON,被阻断时返回 CommonResult;Feign 保持 Sentinel 原生的 SentinelFeign,不替换全局的 Feign.Builder,也不为所有 Feign 客户端注入默认的 fallback,业务错误码仍然由调用方的 getCheckedData() 处理。

# 1. 方案说明

# 1.1 与 @RateLimiter 的区别

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

@RateLimiter Sentinel
计数位置 Redis,多个实例共享同一个计数,是全局的配额 每个 JVM 进程的内存,阈值是单机的,参见《4.6 单机阈值》小节
限流维度 时间窗口内最多 N 次,可以按全局、用户、IP、服务节点、Spring EL 表达式分别计数 按资源的 QPS 或并发线程数,支持快速失败、预热、匀速排队;网关可以按路由、API 分组
熔断降级 不支持 慢调用比例、异常比例、异常数
规则 注解的属性,修改后需要重新发布 与代码分离,保存在 Nacos 中,运行时修改即时生效
外部依赖 Redis 无,Dashboard、Nacos 用于监控和规则管理
被限制时 抛出 ServiceException,HTTP 200 + code = 429 示例返回 HTTP 429/503 + CommonResult,参见《4.7 阻断响应与前端》小节

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

# 1.2 整体结构

curl / 前端
    │  GET /admin-api/system/sentinel-demo/**
    ▼
gateway-server(网关)
    SentinelGatewayFilter:按 API 分组 system-sentinel-demo-api、路由 system-admin-api 统计,执行 gw-flow 规则
    被阻断 → DemoSentinelGatewayConfiguration 的 BlockRequestHandler:HTTP 429/503 + CommonResult
    │
    ▼
system-server(调用方)
    SentinelWebInterceptor:URL 资源 /admin-api/system/sentinel-demo/flow,执行 flow 规则
    被阻断 → DemoSentinelConfiguration 的 BlockExceptionHandler:HTTP 429/503 + CommonResult
    DemoSentinelController#feign
        └── DemoSentinelInfraApi#echo(SentinelFeign):Feign 资源 GET:http://infra-server/rpc-api/infra/sentinel-demo/echo,执行 degrade 规则
                调用失败、被阻断 → DemoSentinelInfraApiFallbackFactory:返回 CommonResult 错误码
                │
infra-server(被调用方,未接入 Sentinel)
    DemoSentinelRpcController#echo:mode = ok 正常、slow 慢调用、biz-error 业务错误

Nacos(命名空间 dev,分组 SENTINEL_GROUP):4 个规则配置,服务启动时读取、运行时监听
Sentinel Dashboard(可选):实时监控;在其中修改的规则只是临时的,不会写回 Nacos

# 1.3 限流、熔断与 Feign 降级

这三者经常被混在一起,作用并不相同:

① 限流(FlowRule、网关的 GatewayFlowRule):保护被调用方。单位时间内超过阈值的请求直接拒绝。网关限流在请求进入服务之前,服务限流保护单个服务实例。

② 熔断(DegradeRule):保护调用方。下游的慢调用比例、异常比例超过阈值时,在熔断时长内直接拒绝调用,不再等待下游超时;熔断时长结束后,放行一个探测请求,成功则恢复,失败则继续熔断。示例在 system-server 中,为调用 infra-server 的 Feign 资源配置熔断规则。

③ Feign 降级(fallbackFactory):决定调用失败、或者被限流熔断阻断后,调用方的代码得到什么结果。没有配置 fallback 时,原来的异常照常抛出;配置后,返回 fallback 的结果。

也就是说,熔断决定「要不要调用下游」,fallback 决定「不调用、或调用失败时返回什么」,两者是独立的。

# 1.4 示例

示例的接口都在 system-server 中,需要登录,通过网关访问:

接口 规则所在服务 资源 规则 被阻断时
GET /admin-api/system/sentinel-demo/gateway-flow gateway-server API 分组 system-sentinel-demo-api 限流,QPS 2 HTTP 429,code = 429
GET /admin-api/system/sentinel-demo/flow system-server URL /admin-api/system/sentinel-demo/flow 限流,QPS 2 HTTP 429,code = 429
GET /admin-api/system/sentinel-demo/feign?mode=ok system-server Feign GET:http://infra-server/rpc-api/infra/sentinel-demo/echo 熔断,慢调用比例 fallback 的错误码:HTTP 200,code = 503

另外,gateway-server 还为路由 system-admin-api(即 /admin-api/system/**)配置了 QPS 200 的限流规则,演示按 routeId 限流。正常访问不会触发,用于《3.6 启动验证》中动态修改规则。

# 2. 获取集成材料

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

分支 JDK Spring Boot Spring Cloud Alibaba Sentinel 差异
master 8 2.7.18 2021.0.6.2 1.8.6 DemoSentinelConfiguration 的 BlockExceptionHandler 需要修改,见《3.5 复制示例代码》小节
master-jdk17 17 3.5.15 2025.0.0.0 1.8.9 无
master-jdk25 25 4.1.2 2025.1.0.0 1.8.9 使用 Feign 的服务(例如说 system-server、infra-server)只有 Pageable、没有 DataWebProperties 时,按条件添加 dependencies-jdk25.xml,见《3.3 添加依赖》小节

Sentinel 的版本由项目已有的 Spring Cloud Alibaba BOM 管理,不需要、也不建议单独指定。master-jdk25 分支,Sentinel 官方没有声明对 Spring Cloud Gateway 5、Spring Framework 7 的适配,接入后以实际的启动、请求验证为准。

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

文件 说明 目标位置
dependencies.xml Maven 依赖片段,分为 2 段 第 1 段:yudao-gateway/pom.xml、yudao-module-system-server/pom.xml;第 2 段:只添加到 yudao-gateway/pom.xml
dependencies-jdk25.xml 仅 master-jdk25 分支按条件补充的 spring-boot-data-commons 依赖片段 满足条件时,添加到对应服务(例如说 system-server、infra-server)的 pom.xml,gateway-server 不适用
sentinel.yaml 按服务分为两段的配置片段 分别合并到 gateway-server、system-server 的 application-local.yaml 等配置文件,或 Nacos 配置
nacos/*.json 4 个规则文件,文件名就是 Nacos 中的 Data ID 在 Nacos 中创建同名配置
src/main/java/.../gateway/sentineldemo/ 网关被阻断时的 BlockRequestHandler yudao-gateway/src/main/java/ 的同名包
src/main/java/.../system/sentineldemo/ 配置类、Feign 客户端及其 fallbackFactory、示例接口 yudao-module-system-server/src/main/java/ 的同名包
src/main/java/.../infra/sentineldemo/ 被调用的 RPC 接口,模拟慢调用、业务错误 yudao-module-infra-server/src/main/java/ 的同名包

# 3. 接入步骤

友情提示:以 `gateway-server` 网关 + `system-server` 调用 `infra-server` 为例子。

示例代码的包名分别是 cn.iocoder.yudao.gateway.sentineldemo、cn.iocoder.yudao.module.system.sentineldemo、cn.iocoder.yudao.module.infra.sentineldemo,在对应服务的扫描范围内。接入其它服务时,需要将包名改到对应服务的 base-package 下。

# 3.1 启动 Sentinel Dashboard(可选)

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

从 Sentinel 的 Releases (opens new window) 下载 1.8.x 版本的 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:只在本机监听,服务与 Dashboard 运行在同一台机器上。
  • -Dserver.port=8858:Dashboard 默认使用 8080 端口,改为 8858,避免与其它程序冲突。
  • sentinel.dashboard.auth.*:Dashboard 的登录账号,默认是 sentinel / sentinel,不要在共享环境中使用默认密码。

浏览器访问 http://127.0.0.1:8858 (opens new window) 登录。服务启动时设置 YUDAO_SENTINEL_DASHBOARD=127.0.0.1:8858 环境变量,才会连接 Dashboard,参见《3.4 添加配置》小节。

# 3.2 在 Nacos 中创建规则

在 Nacos 控制台中,选择服务使用的命名空间(项目默认是 dev,即 spring.cloud.nacos.config.namespace),创建下面 4 个配置。配置内容就是 script/sentinel/nacos/ 目录下同名文件的内容,配置格式选择 JSON:

Data ID Group 使用的服务 说明
gateway-server-gw-api-group-rules.json SENTINEL_GROUP gateway-server 自定义 API 分组
gateway-server-gw-flow-rules.json SENTINEL_GROUP gateway-server 网关流控规则
system-server-flow-rules.json SENTINEL_GROUP system-server 限流规则
system-server-degrade-rules.json SENTINEL_GROUP system-server 熔断规则

注意事项:

  • Data ID 包含 .json 后缀,与文件名完全相同;Group 是 SENTINEL_GROUP,与服务自己的配置(DEFAULT_GROUP)分开。
  • 命名空间要选择服务实际使用的那个。配置中填写的是命名空间的 ID,项目文档中 dev 命名空间的 ID、名字都是 dev;两者不同时,以 ID 为准。
  • 内容必须是严格的 JSON,不能包含 // 注释、结尾多余的逗号。解析失败时,该配置的规则不会生效。各字段的含义,参见《4. 使用说明》。

# 3.3 添加依赖

① 将 dependencies.xml 第 1 段的依赖,复制到 yudao-gateway、yudao-module-system-server 两个服务的 pom.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>

② 将 dependencies.xml 第 2 段的依赖,只复制到 yudao-gateway 的 pom.xml 中:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

说明:

  • 都不写版本,由项目已有的 Spring Cloud Alibaba BOM 管理,对应的 Sentinel 版本见《2. 获取集成材料》小节。
  • spring-cloud-starter-alibaba-sentinel 中的 Servlet 适配,只在 Servlet 应用中生效,它依赖的 servlet-api、spring-webmvc 是 provided 的,不会给网关引入 spring-boot-starter-web 等 Servlet 组件。可以通过 mvn dependency:tree -pl yudao-gateway -Dincludes=org.springframework:spring-webmvc 确认。
  • infra-server 只提供被调用的 RPC 接口,不需要添加上面的 Sentinel 依赖;master-jdk25 分支它是否需要 ③ 的依赖,按 ③ 的条件单独判断。

③ 仅 master-jdk25 分支(Spring Boot 4.1.2 + Spring Cloud OpenFeign 5.0.2):适用于每个使用 Feign 的服务,包括已有、新增的 Feign 客户端,例如说 system-server(新增了 DemoSentinelInfraApi)、infra-server(已有 TenantCommonApi 等);gateway-server 不使用 Feign,不适用。该服务启动时的 classpath 中有 org.springframework.data.domain.Pageable,却没有 spring-boot-data-commons 模块的 org.springframework.boot.data.autoconfigure.web.DataWebProperties 时,OpenFeign 不会创建任何 Encoder,启动报 No bean found of type interface feign.codec.Encoder for xxx(xxx 是 Feign 客户端的名字,例如说 demoSentinelInfraApi)。此时,才将 dependencies-jdk25.xml 中的依赖添加到该服务的 pom.xml,版本由 Spring Boot BOM 管理:

<!-- 仅 master-jdk25 分支,且使用 Feign 的服务只有 Pageable、没有 DataWebProperties 时添加 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-data-commons</artifactId>
</dependency>

这个条件与 Sentinel 无关,不要无条件添加:已经有该模块、或者没有 Pageable 时都不需要,以每个服务实际的 classpath 为准;master、master-jdk17 分支不使用该文件。

# 3.4 添加配置

sentinel.yaml 按服务分为两段,分别合并到对应服务的 application-local.yaml 配置文件中。spring.cloud.sentinel 合并到已有的 spring.cloud 下,不要重复写一个 spring.cloud。

① gateway-server:

spring:
  cloud:
    sentinel:
      eager: true # 启动时就初始化 Sentinel、连接 Dashboard;默认 false,第一次请求时才初始化
      transport:
        dashboard: ${YUDAO_SENTINEL_DASHBOARD:} # Sentinel Dashboard 地址,例如说 127.0.0.1:8858;为空时不连接 Dashboard,规则照常生效
        port: 8719 # Sentinel 的命令端口,没有鉴权,只能在内网访问;同一台机器的多个服务需要不同端口,被占用时 Sentinel 会自动递增
      datasource:
        gw-api-group: # 自定义 API 分组:定义哪些请求路径属于一个 API,供 gw-flow 规则按 API 限流
          nacos:
            server-addr: ${spring.cloud.nacos.server-addr}
            namespace: ${spring.cloud.nacos.config.namespace}
            username: ${YUDAO_NACOS_USERNAME:${spring.cloud.nacos.username:}} # Nacos 开启鉴权时需要;未设置环境变量时,使用服务自己的 Nacos 账号
            password: ${YUDAO_NACOS_PASSWORD:${spring.cloud.nacos.password:}}
            group-id: SENTINEL_GROUP
            data-id: ${spring.application.name}-gw-api-group-rules.json # 即 gateway-server-gw-api-group-rules.json
            data-type: json
            rule-type: gw-api-group
        gw-flow: # 网关流控规则:按 routeId(resourceMode = 0)或自定义 API 分组(resourceMode = 1)限流
          nacos:
            # ... server-addr、namespace、username、password、group-id 与 gw-api-group 相同
            data-id: ${spring.application.name}-gw-flow-rules.json # 即 gateway-server-gw-flow-rules.json
            data-type: json
            rule-type: gw-flow

为了篇幅,上面省略了 gw-flow 中与 gw-api-group 相同的配置项,完整内容见 sentinel.yaml 的第一段,复制时不要遗漏。

② system-server:Sentinel 的配置与 gateway-server 类似,只是命令端口改为 8720,数据源改为 flow(rule-type: flow,Data ID system-server-flow-rules.json)、degrade(rule-type: degrade,Data ID system-server-degrade-rules.json)。另外,在配置文件的顶层开启 Sentinel 对 Feign 的支持:

feign:
  sentinel:
    enabled: true # 开启 Sentinel 对 Feign 的支持:当前服务的【所有】Feign 客户端都由 Sentinel 原生的 SentinelFeign 创建,每个方法是一个资源

完整内容见 sentinel.yaml 的第二段。注意,配置项是 feign.sentinel.enabled,不是 spring.cloud.openfeign 下的配置项。

注意事项:

  • namespace、group-id、data-id 必须与《3.2 在 Nacos 中创建规则》小节创建的配置一致。data-id 通过 ${spring.application.name} 拼接,服务名改变时,Nacos 中的 Data ID 也要一起修改。
  • 每种规则(rule-type)在一个服务中只配置一个数据源:同一种规则的多个数据源,只有最后注册的那个生效。
  • 不要配置 spring.cloud.sentinel.scg.fallback.*:它会覆盖 DemoSentinelGatewayConfiguration 中返回 CommonResult 的处理器。
  • 不需要为 gateway-server 手动设置 csp.sentinel.app.type:spring-cloud-alibaba-sentinel-gateway 启动时会自动设置为 11(Spring Cloud Gateway),Dashboard 按网关应用展示「API 管理」、网关流控规则,参见《5.2》小节。
  • 如果服务的配置放在 Nacos 中,同样合并到 Nacos 中该服务的配置(例如说 gateway-server-local.yaml)。

账号、地址通过环境变量传入,不要把真实密码写入配置文件、提交到 Git:

环境变量 说明 默认值 使用的服务
YUDAO_SENTINEL_DASHBOARD Sentinel Dashboard 的地址 空,不连接 Dashboard 两个服务
YUDAO_NACOS_USERNAME 读取规则的 Nacos 账号,需要有该命名空间的读权限 服务自己的 spring.cloud.nacos.username 两个服务
YUDAO_NACOS_PASSWORD 读取规则的 Nacos 密码 服务自己的 spring.cloud.nacos.password 两个服务

# 3.5 复制示例代码

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

  • DemoSentinelGatewayConfiguration:注册 BlockRequestHandler Bean。spring-cloud-alibaba-sentinel-gateway 会将它注册到 GatewayCallbackManager,网关被阻断时,由优先级最高的 SentinelGatewayBlockExceptionHandler 调用,返回 HTTP 429/503 + CommonResult,不会进入网关的 GlobalExceptionHandler。

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

  • DemoSentinelInfraApi:调用 infra-server 的 Feign 客户端,使用独立的 contextId,并通过 fallbackFactory 显式指定降级。
  • DemoSentinelInfraApiFallbackFactory:调用失败、被阻断时,返回 CommonResult 错误码,参见《4.4 Feign 降级》小节。
  • DemoSentinelConfiguration:通过 @EnableFeignClients(clients = DemoSentinelInfraApi.class) 单独声明 Feign 客户端,不修改已有的 RpcConfiguration;将 fallbackFactory 注册成 Bean;注册 URL 资源被阻断时的 BlockExceptionHandler,它对 system-server 的所有 URL 资源生效。
  • controller/admin/DemoSentinelController:示例接口。放在 controller.admin 包下,才会添加 /admin-api 前缀。

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

  • DemoSentinelRpcController:RPC 接口 /rpc-api/infra/sentinel-demo/echo,在 infra-server 已有安全配置放行的 /rpc-api/infra/** 下。mode=slow 时等待 500 毫秒再返回,mode=biz-error 时抛出业务异常。

示例代码只使用 Java 8 语法和构造方法注入,不直接引用 javax、jakarta 包。只有 master 分支(Sentinel 1.8.6 的 sentinel-spring-webmvc-adapter)需要修改 DemoSentinelConfiguration 的 BlockExceptionHandler:包名不同,handle 方法也没有 resourceName 参数:

// master-jdk17、master-jdk25 分支
import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback.BlockExceptionHandler;
return (request, response, resourceName, ex) -> { ... };

// master 分支:修改为
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
return (request, response, ex) -> { ... };

# 3.6 启动验证

按 Nacos →(可选)Dashboard → infra-server → system-server → gateway-server 的顺序启动。

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

① 确认规则已经加载。命令端口只在本机访问,返回的 JSON 中能看到《3.2》小节创建的规则:

curl -s 'http://127.0.0.1:8719/gateway/getApiDefinitions' # gateway-server 的 API 分组
curl -s 'http://127.0.0.1:8719/gateway/getRules' # gateway-server 的网关流控规则
curl -s 'http://127.0.0.1:8720/getRules?type=flow' # system-server 的限流规则
curl -s 'http://127.0.0.1:8720/getRules?type=degrade' # system-server 的熔断规则

返回 [] 时,参见《5.1 修改了 Nacos 中的规则,没有生效》小节排查。

② 网关限流:连续请求 5 次 /gateway-flow,每秒只有 2 个请求通过,其余被网关拒绝,不会到达 system-server:

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

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

③ 服务限流:把地址换成 /flow,结果与 ② 相同,只是 HTTP 429 由 system-server 的 BlockExceptionHandler 返回。也可以直接请求 system-server 的 48081 端口验证,不经过网关。

④ Feign 熔断降级:

URL='http://127.0.0.1:48080/admin-api/system/sentinel-demo/feign'
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 ' HTTP %{http_code}\n' -H "$H1" -H "$H2" "$URL?mode=slow"; done
# 2. 熔断期间,即使 mode=ok,也不会调用 infra-server,直接返回 fallbackFactory 的错误码
curl -s -w ' HTTP %{http_code}\n' -H "$H1" -H "$H2" "$URL?mode=ok"
# 3. 10 秒后,第一个请求作为探测放行,成功且不慢,熔断恢复
sleep 10; curl -s -w ' HTTP %{http_code}\n' -H "$H1" -H "$H2" "$URL?mode=ok"
# 4. 业务错误:infra-server 返回业务错误码,不会进入 fallback,也不计入熔断的统计
curl -s -w ' HTTP %{http_code}\n' -H "$H1" -H "$H2" "$URL?mode=biz-error"
步骤 结果
1 3 次都成功:code = 0,data = "slow",HTTP 200
2 code = 503,msg = "infra-server 暂时不可用,请稍后重试",HTTP 200。fallback 返回的错误码由 getCheckedData() 抛出 ServiceException,再由全局异常处理器返回
3 code = 0,data = "ok"
4 code = 400,msg = "模拟 infra-server 的业务错误":业务错误码原样返回给前端,不会被 fallback 替换

还可以停止 infra-server 后请求 mode=ok:同样返回 code = 503,并且 system-server 的日志中打印 [buildErrorResult][调用 infra-server 失败] 及完整的异常,便于排查。

⑤ 动态修改规则:在 Nacos 中,将 system-server-flow-rules.json 的 count 从 2 改为 5 并发布,不需要重启服务,再执行一次 ③,每秒可以通过 5 个请求;curl -s 'http://127.0.0.1:8720/getRules?type=flow' 中的 count 也变为 5.0。按 routeId 的规则同理:将 gateway-server-gw-flow-rules.json 中 system-admin-api 的 count 临时改为 1,所有 /admin-api/system/** 的请求每秒只能通过 1 个,验证完成后记得改回。

⑥(可选)Dashboard:设置了 YUDAO_SENTINEL_DASHBOARD 时,在 Dashboard 中可以看到 gateway-server、system-server 两个应用,「簇点链路」中列出了上面的资源名,「实时监控」中可以看到通过、拒绝的 QPS。

验证完成后,可以删除 DemoSentinelController、DemoSentinelInfraApi、DemoSentinelInfraApiFallbackFactory、DemoSentinelRpcController 等示例类,以及 Nacos 中的示例规则;两个 BlockExceptionHandler、BlockRequestHandler 可以保留,作为自己业务的阻断响应。

# 4. 使用说明

# 4.1 网关限流:路由与 API 分组

网关的规则有两种资源:

  • 路由(resourceMode = 0):资源名是网关配置中路由的 id,即 spring.cloud.gateway.server.webflux.routes[].id(master 分支是 spring.cloud.gateway.routes[].id),例如说 system-admin-api 对应 /admin-api/system/**。
  • 自定义 API 分组(resourceMode = 1):资源名是 gw-api-group 中的 apiName,由一组请求路径组成,可以跨路由,粒度比路由更细。

一个请求可能同时属于一个路由、多个 API 分组,它们的规则都会生效,任意一个超过阈值就会被拒绝。

gateway-server-gw-api-group-rules.json 的字段:

字段 说明
apiName API 分组的名字,与 gw-flow 规则的 resource 一致
predicateItems[].pattern 请求路径,匹配的是网关收到的原始路径,例如说 /admin-api/system/sentinel-demo/gateway-flow
predicateItems[].matchStrategy 匹配方式:0 精确匹配,1 前缀匹配(例如说 /admin-api/system/sentinel-demo/**),2 正则匹配

gateway-server-gw-flow-rules.json 的字段:

字段 说明
resource 路由的 id,或者 API 分组的 apiName
resourceMode 0 路由,1 自定义 API 分组
grade 阈值类型:1 QPS,0 并发线程数
count 阈值,单个网关实例的
intervalSec 统计窗口的时长,单位:秒,默认 1
controlBehavior 流控效果:0 快速失败,2 匀速排队(配合 maxQueueingTimeoutMs,单位:毫秒)
burst 快速失败时,额外允许的突发请求数
paramItem 可选,按客户端 IP、Host、请求头、URL 参数、Cookie 分别计数,参见 Sentinel 的 《网关流量控制》 (opens new window) 文档

按客户端 IP 计数时,Sentinel 取的是网关看到的连接地址:网关在 Nginx 等反向代理之后时,所有请求的 IP 都是代理的地址,需要改为按 X-Forwarded-For 等请求头计数,并且只信任代理设置的请求头。

# 4.2 服务限流:URL 资源与 @SentinelResource

① URL 资源:引入 spring-cloud-starter-alibaba-sentinel 后,Sentinel 自动为 Spring MVC 的每个接口创建资源,资源名是匹配到的路径模式,包含 /admin-api、/app-api、/rpc-api 等前缀,路径变量保持原样,例如说 /admin-api/system/user/get、/admin-api/system/xxx/{id}。资源名可以在 Dashboard 的「簇点链路」中确认。

spring.cloud.sentinel.http-method-specify 默认是 false,资源名不带 HTTP 方法;master-jdk17、master-jdk25 分支的 Sentinel 1.8.9 中,webmvc-v6x 适配开启它时添加的方法前缀有问题(Sentinel 1.8.10 修复),建议保持默认值。

② @SentinelResource:需要保护 Service 方法等非 URL 的资源时,在方法上添加 @SentinelResource 注解,Spring Cloud Alibaba 已经注册了它的切面。用法参见单体项目的 《限流熔断》 (opens new window) 文档。

system-server-flow-rules.json 的字段:

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

# 4.3 熔断规则

system-server-degrade-rules.json 的字段:

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

哪些情况会被统计为「异常」,需要注意:

  • Feign 资源:只有调用本身失败才算,例如说超时、连接失败、没有可用的实例、HTTP 状态码不是 2XX。项目的 RPC 接口会将业务异常转换成 HTTP 200 的 CommonResult 错误码,Sentinel 不会把它当作下游故障,这是期望的行为:业务错误不应该导致熔断。
  • URL 资源:项目的全局异常处理器会把异常转换成 CommonResult 返回,是否计入异常与 Sentinel 的版本有关。需要按异常比例、异常数熔断时,建议在 Service 方法上使用 @SentinelResource,并通过 exceptionsToIgnore = ServiceException.class 排除业务异常。
  • 下游变慢、但不报错时,异常比例无法发现,使用慢调用比例更合适,示例即是如此。

# 4.4 Feign 降级

① 开启 feign.sentinel.enabled 后,当前服务的所有 Feign 客户端,都由 Sentinel 原生的 SentinelFeign 创建,每个方法是一个资源,资源名是「HTTP 方法:http://服务名 + 路径」,例如说 GET:http://infra-server/rpc-api/infra/sentinel-demo/echo。项目已有的 Feign 客户端没有配置 fallback:调用失败时,原来的异常照常抛出,行为与接入前相同。

② 只有在 @FeignClient 上显式配置了 fallbackFactory(或 fallback)的客户端,才会降级:

@FeignClient(name = ApiConstants.NAME, contextId = "demoSentinelInfraApi",
        fallbackFactory = DemoSentinelInfraApiFallbackFactory.class)
public interface DemoSentinelInfraApi { ... }
  • 优先使用 fallbackFactory,它能拿到失败的原因(Throwable cause);同时配置时,fallback 优先。
  • fallbackFactory 必须注册成 Bean,Sentinel 通过 FeignClientFactory 按类型查找它,找不到时启动报错。
  • 它要实现接口的所有方法。接口的 default 方法不是 Sentinel 资源,它调用的其它方法仍然会经过 Sentinel。

③ fallback 的写法,参考 DemoSentinelInfraApiFallbackFactory:

  • 返回 CommonResult 错误码,不要抛出异常:调用方通过 getCheckedData() 或 checkError() 抛出 ServiceException,由全局异常处理器返回给前端。master 分支的 Spring Cloud Alibaba 2021.0.6.2 还会把 fallback 中抛出的异常包装成 AssertionError。
  • 不要伪造成功的结果:例如说创建订单、扣减库存等写操作,fallback 返回成功会让调用方误以为已经执行。只有「查询失败时返回空列表」这类业务可以接受的场景,才返回降级的数据。
  • 提示中不要包含原始的异常信息,避免泄漏下游的地址、报错等;但对 Sentinel 阻断以外的异常,要打印完整的错误日志,不要吞掉。
  • 只对返回 CommonResult 的方法这样处理。不是 CommonResult 的方法,需要按其返回类型单独设计,不要一概返回 null。

④ 调用方必须检查结果:

return success(demoSentinelInfraApi.echo(mode).getCheckedData());

不检查时,调用方会把失败当作成功,拿着为 null 的 data 继续执行。

⑤ 为 Feign 资源配置限流、熔断规则时,该客户端一定要配置 fallback。没有 fallback 时,Sentinel 抛出的 BlockException 是受检异常,接口方法没有声明,会变成 UndeclaredThrowableException,由全局异常处理器返回「系统异常」。

为什么不为所有 Feign 客户端注入默认的 fallback?

统一的默认 fallback 需要替换 Feign.Builder 或 InvocationHandlerFactory,与 Sentinel 原生的 SentinelFeign 冲突:要么 Sentinel 的统计、熔断失效,要么默认 fallback 失效。并且,它很难正确处理所有的返回类型、default 方法和业务错误码:把业务错误码也当作失败去降级,会改变调用方原有的语义。所以,本文只在需要降级的客户端上显式配置。

# 4.5 规则持久化:Nacos 是规则的唯一来源

规则的流转如下:

  • 修改:在 Nacos 中修改规则配置并发布,服务通过 Nacos 的监听即时收到,整体替换该服务这一类型的规则,不需要重启。Nacos 的历史版本可以用于回滚。
  • 启动:服务启动时从 Nacos 读取一次。Nacos 中没有该配置时,没有规则,等创建后再收到推送。
  • Dashboard:官方 Dashboard 修改规则时,只是通过命令端口推送到当前这台实例的内存,不会写回 Nacos。下次 Nacos 中的配置变更、或者服务重启时,就会被 Nacos 中的规则覆盖;有多个实例时,也只修改了其中一台。

所以,Dashboard 只用于查看监控、确认资源名,以及紧急情况下临时调整;需要长期生效的规则,一定要修改 Nacos 中的配置。要让 Dashboard 的修改直接写入 Nacos,需要自行改造 Dashboard 的源码,本文不提供。

# 4.6 单机阈值

规则中的 count 是单个实例的阈值,Sentinel 在每个实例的内存中分别计数:

  • 网关部署 3 个实例时,count = 2 的规则,整体每秒最多可以通过约 6 个请求;服务同理。
  • 实例数变化(扩缩容、滚动发布)时,整体的上限随之变化,需要按「整体阈值 ÷ 实例数」估算 count。

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

# 4.7 阻断响应与前端

场景 HTTP 状态码 响应
网关、服务被限流 429 {"code": 429, "msg": "请求过于频繁,请稍后重试"}
网关、服务的 URL 资源被熔断 503 {"code": 503, "msg": "服务暂时不可用,请稍后重试"}
Feign 被限流等普通阻断,进入 fallback 200 {"code": 429, "msg": "请求过于频繁,请稍后重试"},与项目其它的业务错误码一样
Feign 被熔断或调用失败,进入 fallback 200 {"code": 503, "msg": "infra-server 暂时不可用,请稍后重试"},与项目其它的业务错误码一样

前端的表现:

  • yudao-ui-admin-vben:HTTP 状态码不是 2XX 时,弹出响应中的 msg,即「请求过于频繁,请稍后重试」。
  • yudao-ui-admin-vue3:HTTP 状态码不是 2XX 时,弹出通用的请求失败提示及状态码,不读取 msg。

如果希望所有前端都按业务错误码处理,可以把 BlockRequestHandler、BlockExceptionHandler 中的状态码改为 200。代价是网关、Nginx 的访问日志和监控中,无法再通过 HTTP 状态码区分被限流的请求。

# 4.8 安全注意事项

  • 命令端口(示例的 8719、8720)没有鉴权,可以查询、修改规则,只能在本机或内网访问,通过防火墙、安全组限制,不要对公网开放。
  • Dashboard 修改默认的账号密码,只在内网访问。
  • Nacos 中的规则配置,有写权限的人都可以修改,按命名空间控制权限;读取规则的账号只需要读权限。
  • 本文不使用 Sentinel 的授权规则(黑白名单):它依据的调用来源,通常取自客户端可以伪造的请求头,不能替代 Spring Security 的认证、鉴权。
  • 本文也没有启用系统自适应规则、热点参数规则、集群流控,需要时参见 Sentinel 的官方文档,并自行验证。

# 5. 常见问题

# 5.1 修改了 Nacos 中的规则,没有生效

按顺序排查:

  • 命名空间:创建配置时选择的命名空间,与服务的 spring.cloud.nacos.config.namespace 是否一致;配置中填写的是命名空间的 ID。
  • Group、Data ID:是否是 SENTINEL_GROUP,Data ID 是否与 sentinel.yaml 中拼接的结果完全一致,包括 .json 后缀、服务名。
  • JSON 格式:是否包含注释、结尾多余的逗号。可以先用 JSON 格式化工具校验,再发布。
  • 鉴权:Nacos 开启鉴权时,是否设置了有读权限的账号。
  • rule-type:例如说网关的规则是 gw-flow、gw-api-group,不是 flow。
  • 资源名:是否与实际的资源名一致,可以在 Dashboard 的「簇点链路」中确认;count 等字段不合法的规则会被 Sentinel 忽略。

然后通过《3.6 启动验证》的 ① 查看服务内存中实际的规则。Sentinel 自己的日志在 ${user.home}/logs/csp/ 目录下,sentinel-record.log 中记录了规则的加载。

# 5.2 Dashboard 中,网关显示为普通的应用,没有「API 管理」菜单

当前的 Spring Cloud Alibaba 网关适配器(三个分支的 spring-cloud-alibaba-sentinel-gateway)启动时会自动将 csp.sentinel.app.type 设置为 11(Spring Cloud Gateway),不需要手动添加启动参数。出现这个现象时,依次排查:

  • 适配器是否接入:yudao-gateway 的 pom.xml 是否添加了《3.3 添加依赖》小节的 spring-cloud-alibaba-sentinel-gateway;通过《3.6 启动验证》的 ① 请求 gateway/getRules,能返回网关规则,说明网关适配已经生效。
  • Dashboard 的版本与连通性:是否使用 1.8.x 版本的 Dashboard(例如说《3.1》小节的 1.8.10),gateway-server 是否连接上了 Dashboard,参见《5.8 Dashboard 中看不到应用》小节。
  • 实际注册的应用类型:Dashboard 在内存中按应用名保存应用,应用类型取自该应用第一次注册的机器,之后的注册、移除机器都不会更新它。同名应用之前以普通应用注册过时,核对是否遗留了旧的应用类型;必要时在可控的测试环境中重启 Dashboard,等 gateway-server 重新注册后再确认。
  • 初始化顺序:若 Sentinel 的 SentinelConfig 在网关自动配置之前已经被提前初始化,需要结合实际注册的应用类型、初始化顺序排查。

它只影响 Dashboard 的展示,不影响规则的执行。

# 5.3 Dashboard 中修改的规则,重启后丢失,或者过一会儿被还原

这是预期的行为:Dashboard 的修改只保存在实例的内存中,不会写回 Nacos,参见《4.5 规则持久化》小节。需要长期生效的规则,修改 Nacos 中的配置。

# 5.4 被阻断时,返回的是 Blocked by Sentinel 文本,而不是 CommonResult

  • 网关:DemoSentinelGatewayConfiguration 是否在 cn.iocoder.yudao.gateway 包下被扫描到;是否配置了 spring.cloud.sentinel.scg.fallback.*,它会覆盖 BlockRequestHandler。
  • 服务:DemoSentinelConfiguration 是否被扫描到;master 分支是否按《3.5 复制示例代码》小节修改了 BlockExceptionHandler 的包名。

# 5.5 Feign 调用失败时,没有进入 fallback

  • 是否配置了 feign.sentinel.enabled: true。没有开启时,OpenFeign 会忽略 fallbackFactory,失败时直接抛出异常。
  • fallbackFactory 是否注册成了 Bean。
  • 下游返回的是不是业务错误码:HTTP 200 的 CommonResult 错误码不是调用失败,不会进入 fallback,由调用方的 getCheckedData() 处理,参见《4.4 Feign 降级》小节。

# 5.6 为 Feign 资源配置规则后,返回「系统异常」

该 Feign 客户端没有配置 fallback,BlockException 变成了 UndeclaredThrowableException,参见《4.4 Feign 降级》小节的 ⑤。

# 5.7 报错 No bean found of type interface feign.codec.Encoder

例如说 IllegalStateException: No bean found of type interface feign.codec.Encoder for demoSentinelInfraApi,出现在 master-jdk25 分支使用 Feign 的服务(例如说 system-server、infra-server)启动时。按《3.3 添加依赖》小节的 ③ 确认该服务只有 Pageable、没有 DataWebProperties 后,为该服务添加 dependencies-jdk25.xml 中的 spring-boot-data-commons 依赖。可以通过 mvn dependency:tree -Dincludes=org.springframework.boot:spring-boot-data-commons 确认是否已经存在。

# 5.8 Dashboard 中看不到应用

  • 是否设置了 YUDAO_SENTINEL_DASHBOARD 环境变量,地址、端口是否正确。
  • 没有开启 eager 时,服务收到第一个请求后才会连接 Dashboard。
  • Dashboard 需要反过来访问服务的命令端口拉取监控数据:服务在 Docker 等环境中时,通过 spring.cloud.sentinel.transport.client-ip 设置 Dashboard 能够访问到的 IP,并开放对应的端口。

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

分布式事务 Seata
分库分表

← 分布式事务 Seata 分库分表→

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