如何将Spring Boot与Sentinel结合实现QPS限流?

摘要:摘要 介绍Spring Boot 4 如何集成流量治理神器Sentinel实现QPS限流。 目录Sentinel简介启动 Sentinel 控制台下载sentinel访问 Sentinel 控制台注解@SentinelResource使用方
摘要 介绍Spring Boot 4 如何集成流量治理神器Sentinel实现QPS限流。 目录Sentinel简介启动 Sentinel 控制台下载sentinel访问 Sentinel 控制台注解@SentinelResource使用方法用@SentinelResource限流统一处理Sentinel异常|done结束语Reference Sentinel简介   什么是Sentinel?随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由/调度、流量控制、流量整形、熔断降级、系统自适应过载保护/实例摘除、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。   同一个资源可以创建多条限流规则。Sentinel底层中的 FlowSlot 会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕。   在实际的项目开发中,一般不会直接写类似《Spring Boot整合Sentinel之流量控制入门》中那段限流入门演示代码,通常需要将Sentinel集成到应用框架中。本文以《一步步搭建JDK 21 Spring Boot项目》搭建的Spring Boot项目为基础,展示如何将Sentinel集成到Spring Boot项目中,并基于注解 @SentinelResource 进行限流。demo中只介绍了qps限流策略,它有多种策略备选,请根据业务需要自行选定。 启动 Sentinel 控制台   Sentinel 的使用可以分为两个部分: 控制台(Dashboard):控制台主要负责管理规则推送、监控、集群限流、分配管理、机器发现等。 核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 7 及以上版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。 下载sentinel   从sentinel控制台传送门下载需要的sentinel jar。   我下载了当前最新版v1.8.9。下载后在Mac 终端进入jar包存放目录后,执行命令 java -Dserver.port=8080 -jar sentinel-dashboard-1.8.9.jar 即可启动控制台。默认端口是8080,为了避免端口好冲突,可以设置为诸如9000等。 访问 Sentinel 控制台    在浏览器访问sentinel控制台地址http://localhost:8080或者http://127.0.0.1:8080/即可进入如下登录页面,默认账号密码都是 sentinel。恭喜你!此时此刻sentinel下载运行成功。   Sentinel 开源控制台支持实时监控和规则管理。接入控制台的步骤如下: spring.cloud.sentinel.transport.dashboard=localhost:8080 spring.cloud.sentinel.transport.heartbeat-interval-ms=500 spring.cloud.sentinel.eager=true   配置 heartbeat-interval-ms 用于指定应用与 Sentinel 控制台之间的心跳上报间隔,单位是毫秒。配置为 500 表示 👉 应用每 500ms(0.5 秒) 向 Sentinel Dashboard 发送一次心跳,用于上报实例存活状态和基础运行信息。 应用启动时 立即初始化 Sentinel 核心组件并向控制台发起连接,而不是等到第一次流量进入时再初始化。   配置 spring.cloud.sentinel.eager=true表示应用启动时 立即初始化 Sentinel 核心组件并向控制台发起连接,而不是等到流量第一次进入时再初始化。两者组合使用的整体业务含义: ✅ Sentinel 在应用启动阶段即完成初始化,服务一上线就受到限流与熔断保护; ✅ 应用与控制台之间保持高频心跳,同步实例状态更及时; ✅ 更有利于稳定性监控、规则推送和快速问题预警; 注解@SentinelResource使用方法   简单介绍下注解@SentinelResource中各个属性: value - 指定资源的名称 blockHandler - 服务限流后会抛出BlockException异常,此属性用来指定一个函数(方法)来处理BlockException异常的。 注意: 这个方法必须是public的,且返回类型需要与原方法相匹配,参数类型默认与原方法一致,且最后加一个额外的参数,类型为BlockException blockHandlerClass - 若属性blockHandler指定的函数与原方法不在一个类中,则需要使用该属性指定所在的类 注意:必须配合blockHandler属性一起使用,且blockHandler属性指定的方法必须为static静态函数,否则无法解析 fallback - 用于抛出异常时,执行处理逻辑,可以针对所有类型的异常进行处理 注意:Sentinel 1.6.0 之前,fallback函数只针对降级异常(DegradeException)进行处理,不能处理业务异常 返回值类型必须与原函数一致,且方法参数也要与原函数一致,可以在最后加一个额外的参数,类型为Throwable类型 fallbackClass - 若属性fallback指定的函数与原方法不在一个类中,则需要使用该属性指定所在的类 注意:必须配合fallback属性一起使用,且fallback属性指定的方法必须为static静态函数,否则无法解析 defaultFallback - 默认的fallback函数名称,用于通用的fallback逻辑 exceptionsToIgnore - 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入fallback逻辑中,而是会原样抛出 用@SentinelResource限流   pom配置如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>4.0.0</version> <relativePath/> </parent> <groupId>com.cactus</groupId> <artifactId>wiener</artifactId> <version>0.0.1-SNAPSHOT</version> <name>wiener</name> <description>wiener</description> <properties> <java.version>21</java.version> <sentinel.version>1.8.9</sentinel.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.42</version> </dependency> <!-- Sentinel核心服务 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>${sentinel.version}</version> </dependency> <!-- Sentinel本地应用接入控制台,版本需要与控制台保持一致 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-transport-simple-http</artifactId> <version>${sentinel.version}</version> </dependency> <!-- Sentinel提供注解无侵入定义资源 https://mvnrepository.com/artifact/com.alibaba.csp/sentinel-annotation-aspectj --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-annotation-aspectj</artifactId> <version>${sentinel.version}</version> </dependency> </dependencies> <!-- 如果希望在项目级别使用阿里云镜像,就添加alimaven --> <repositories> <repository> <id>alimaven</id> <name>aliyun maven</name> <url>https://maven.aliyun.com/repository/central</url> </repository> </repositories> </project>   先定义一个测试用例getFlow1,验证注解 @SentinelResource限流是否生效: @RestController @RequestMapping("/sentinel") public class SentinelTestController { /** * 只添加blockHandler属性 指定getFlowBlockHandler方法处理异常 */ @GetMapping(value = "getFlow1") @SentinelResource(value = SentinelRuleConfig.RESOURCE_QPS_LIMIT, blockHandler = "getFlowBlockHandler") public String getFlow1() { // 返回值 return "流量正常"; } /** * getFlow1 处理异常逻辑 */ public String getFlowBlockHandler(BlockException ex) { log.info("触发限流"); if (ex instanceof FlowException) { return "getFlow1限流-流控"; } else if (ex instanceof DegradeException) { return "getFlow1限流-降级"; } return "getFlow1限流"; } }   其中,@SentinelResource(value = SentinelRuleConfig.RESOURCE_QPS_LIMIT, blockHandler = "getFlowBlockHandler")表示对函数 getFlow1 进行限流监控,资源名是my_resource。我们可以通过编写代码或使用 Sentinel 控制台来设置规则。例如,以下是一个定义限流QPS=3的Java代码片段: import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import java.util.ArrayList; import java.util.List; /** * @Author Wiener * @Date 2025-12-11 * @Description: 设置限流规则 */ public class FlowRules { /** * 入门版限流规则 * @param resourceName */ public static void initFlowRules(String resourceName) { List<FlowRule> rules = new ArrayList<>(); FlowRule rule = new FlowRule(); rule.setResource(resourceName); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); rule.setCount(3); // 设置 QPS 为 3 rules.add(rule); FlowRuleManager.loadRules(rules); } }   其中,resource表示资源名,grade表示降级策略。 import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Author Wiener * @Description: 加载全局限流配置类 */ @Configuration public class SentinelRuleConfig implements InitializingBean { public final static String RESOURCE_QPS_LIMIT = "my_resource"; @Bean public SentinelResourceAspect sentinelResourceAspect(){ return new SentinelResourceAspect(); } @Override public void afterPropertiesSet() { FlowRules.initFlowRules(RESOURCE_QPS_LIMIT); } }   类SentinelResourceAspect是让 @SentinelResource 从“注解装饰品”变成“真正限流熔断入口”的关键引擎。如果没有它,@SentinelResource 只是个普通注解,不会做任何限流、熔断或者降级处理,使得Sentinel 只是“库”;如果有了它,Sentinel 才是流量“治理工具”。   检查效果。在 Spring Boot 应用启动之前,从下图中 Modify options 找到 Add VM options设置JVM 启动参数: -Dcsp.sentinel.dashboard.server=127.0.0.1:8080 -Dproject.name=wiener   本示例是用于给服务打开限流和监控能力的启动配置。它通过 JVM 启动参数为 Spring Boot 本地服务注入 Sentinel 配置,-Dcsp.sentinel.dashboard.server 指定控制台地址(127.0.0.1:8080),-Dproject.name 于定义当前 Spring Boot 应用在 Sentinel 中的唯一标识名称(指定应用名为 wiener)。控制台通过该名称区分不同服务实例,并按应用维度进行指标统计和流控规则管理。通过上述 JVM 启动参数,Spring Boot 应用即可完成与 Sentinel 控制台的集成,实现服务运行状态可视化和流量治理能力。   在服务启动后,多次访问接口 /getFlow1 后可以看到下图所示监控数据: 从流控规则页面可以查到服务端通过代码配置的限流阈值:   我把QPS阈值改为1再刷新Api,限流效果如下: 图中【通过QPS】为1,说明控制台配置的限流规则已经下发到服务端。至此,已经完成Spring Boot整合Sentinel 注解@SentinelResource进行限流并从控制台查看限流效果。 统一处理Sentinel异常|done   Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则和热点参数规则。其所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。默认情况下,触发上述规则时,都会抛出异常到调用方。如果要自定义异常的返回结果,需要实现BlockExceptionHandler接口: public interface BlockExceptionHandler { /** * 处理请求被限流、降级、授权拦截时抛出的异常:BlockException */ void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception; }   BlockException包含很多个子类,分别对应不同的限流场景: 异常 说明 FlowException 限流异常 ParamFlowException 热点参数限流的异常 DegradeExceptionn 熔断降级异常 AuthorityExceptionn 授权规则异常 SystemBlockException 系统保护规则异常   注意,实现BlockExceptionHandler接口的类必须用@Component注解注入到Spring Boot中。统一处理Sentinel异常的代码示例如下: @Component public class SentinelExceptionHandler implements BlockExceptionHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception { String msg = "未知异常"; int status = 429;// 请求过多 //异常处理逻辑:根据e异常的类型判断是触发了限流还是降级等,进一步做出不同的处理逻辑 if (e instanceof FlowException) { msg = "请求被限流"; } else if (e instanceof ParamFlowException) { msg = "请求被热点参数限流"; } else if (e instanceof DegradeException) { msg = "请求被熔断降级"; } else if (e instanceof AuthorityException) { msg = "没有访问权限"; status = 401; } response.setContentType("application/json;charset=utf-8"); response.setStatus(status); response.getWriter().write(msg); response.getWriter().println("{\"msg\":\""+msg+"\", \"status\":" + status + "}"); } } 结束语   以上就是这篇文章的全部内容了,希望本文对道友的学习或者工作能带来一定的帮助,如有疑问请留言交流。Wiener在此祝各位生活愉快!工作顺利! Reference https://github.com/alibaba/Sentinel/wiki/How-to-Use https://sentinelguard.io/zh-cn/docs/introduction.html