Spring Boot整合Sentinel之QPS限流

摘要 介绍Spring Boot 4 如何集成流量治理神器Sentinel实现QPS限流。

目录

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 开源控制台支持实时监控和规则管理。接入控制台的步骤如下:

java 复制代码
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配置如下:

java 复制代码
<?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限流是否生效:

java 复制代码
@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代码片段:

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表示降级策略。

java 复制代码
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 启动参数:

java 复制代码
-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接口:

java 复制代码
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异常的代码示例如下:

java 复制代码
@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

相关推荐
Coder_Boy_2 小时前
基于SpringAI的智能平台基座开发-(四)
java·人工智能·spring boot·langchain·springai
码界奇点3 小时前
基于Spring Boot的内容管理系统框架设计与实现
java·spring boot·后端·车载系统·毕业设计·源代码管理
乐韵天城5 小时前
SpringBoot中如何手动开启数据库事务
数据库·spring boot
墨着染霜华5 小时前
Spring Boot整合Kaptcha生成图片验证码:新手避坑指南+实战优化
java·spring boot·后端
我爱学习好爱好爱6 小时前
Prometheus监控栈 监控java程序springboot
java·spring boot·prometheus
老华带你飞6 小时前
考试管理系统|基于java+ vue考试管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
WZTTMoon6 小时前
Spring Boot OAuth2 授权码模式开发实战
大数据·数据库·spring boot
赵得C6 小时前
完整 Oracle 12c 分页 Demo(Spring Boot+MyBatis+PageHelper)
spring boot·oracle·mybatis
机智的人猿泰山7 小时前
spring boot 运行测试类时:Error creating bean with name ‘serverEndpointExporter‘ 问题
java·spring boot·后端