SpringCloud 系列 03:Sentinel集成配置+核心规则+Nacos持久化

Sentinel简介

官方定义:Sentinel 是阿里巴巴开源的分布式系统流量防卫兵,专注于流量控制、熔断降级、系统负载保护和热点防护,目的是保障分布式系统的稳定性。

通俗理解:Sentinel 就像我们服务的"智能保镖",它24小时监控服务的流量、接口调用、系统资源状态,当发现异常(流量超负载、下游服务故障、系统资源耗尽)时,会自动采取"限流、熔断、降级"等措施,挡住风险,保护服务不被拖垮,同时尽可能保证核心功能的可用性。

与传统的限流工具(如Guava RateLimiter)相比,Sentinel 的核心优势在于"分布式支持、可视化管控、动态规则、场景丰富",不仅能解决单体服务的流量问题,更能适配大规模微服务集群的治理需求。


一、核心定位与价值

  • 定位:面向分布式、多语言架构的流量控制 / 熔断降级组件,以流量为切入点保障服务稳定。
  • 核心价值
    • 防止流量洪峰压垮服务(如秒杀、大促)
    • 阻断服务故障雪崩(依赖服务异常不扩散)
    • 提供实时监控与动态规则,降低运维成本

二、三大核心能力

1. 流量控制(限流)
  • 目标 :限制资源访问的QPS / 线程数,削峰填谷。
  • 策略
    • 直接拒绝(快速失败)
    • 排队等待(匀速通过)
    • 预热启动(冷启动场景)
    • 热点参数限流(如按用户 ID / 商品 ID 限流)
2. 熔断降级
  • 目标 :当依赖服务异常 / 超时 / 错误率过高时,快速切断调用,返回降级结果。
  • 触发条件
    • 异常比例 / 错误数
    • 慢调用比例(RT 超过阈值)
    • 并发线程数
  • 降级策略:返回默认值、执行本地逻辑、静默失败。
3. 系统自适应保护
  • 目标 :从全局系统维度(CPU/Load/RT/QPS)自动调整流量,防止整体过载。
  • 机制:根据系统负载实时调整准入阈值,避免单点故障拖垮全局。

三、核心组件与架构

组件 作用 部署方式
Sentinel Client 核心 SDK,嵌入应用,执行限流 / 熔断逻辑、采集指标 引入 Jar 包(Java)/SDK(Go/C++)
Sentinel Dashboard 可视化控制台:配置规则、实时监控、查看集群状态 独立 Web 应用(Spring Boot)
规则中心 存储限流 / 熔断规则(支持 Nacos/Apollo/ 本地文件) 独立配置中心

四、工作流程

  1. 定义资源:接口 / 方法 / URL / 代码块(Sentinel 保护的最小单元)。
  2. 埋点统计:Client 实时统计资源的 QPS、RT、异常数等指标。
  3. 规则匹配:按预设规则判断是否限流 / 熔断。
  4. 执行策略:放行、拒绝、排队或降级。
  5. 监控上报:数据同步到 Dashboard,可视化展示。

下载控制台

sentinel-dashboard 是阿里巴巴 Sentinel 流量治理组件的可视化控制台,核心用来:

  1. 监控:实时查看业务服务中各接口 / 方法的流量、QPS、异常、限流熔断触发情况;
  2. 配置:通过网页界面快速设置 / 修改限流、熔断、降级等规则,规则实时生效无需重启服务;
  3. 管理:统一维护所有流量规则,是管控 Sentinel 核心能力的「操作面板」。

安装sentinel-dashboard ,访问https://github.com/alibaba/Sentinel/releases,下载对应jar包,下载好之后放到指定目录,在下载目录输入cmd打开控制台

控制台打开后输入java -jar sentinel-dashboard-1.8.8.jar,启动控制台

启动完成访问8080端口打开控制台

账号密码默认为:sentinel

集成 Sentinel

  1. 引入依赖

在services父模块中引入sentinel依赖:

XML 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2.加配置:

在项目的yml文件中加上一段sentienl的配置

配置加完打开控制台,就能在控制台中定义一些规则

3.标记资源(@SentinelResource注解)

使用@SentinelResource注解标记需要保护的资源(接口、方法),并配置限流/熔断的兜底方法(自定义异常提示)

例如在订单服务的创建订单的方法上添加一个@SentinelResource,value为createOrder然后我们去请求一下create

请求成功之后我们可以来到sentienl控制台簇点链路中可以看到调用链的过程

我们可以看到我们发起了一个create请求然后他认为create是一个资源,而create请求又调用了createOrder而createOrder是我们通过注解定义的资源,sentienl也会认为这是一个资源,我们可以对任意一个资源进行一些控制,比如上面的,流控、熔断、热点、授权。

我们来测试一下流控

点击流控,可以看到我们可以配置QPS也就是每秒的并发数,并设置阈值,或者并发线程的数量

我们配置一个QPS为1来进行测试

创建好以后可以在流控规则中看到对应的规则

我们来测试一下流控是否有效,继续访问localhost:8000/create,并快速点击刷新让其每秒访问次数超过1次

可以看到他会出现一个Blocked by Sentinel (flow limiting)也就是被Sentinel给限制访问了

Sentienl异常处理

从上面的例子可以看到如果我们的请求被Sentienl限制默认会返回Blocked by Sentinel (flow limiting)这当然不是我们需要的,那我们可以进行处理

当我们触发了Sentienl限制后他会抛出一个BlockException异常这是个父类异常:

BlockException 的继承体系,它是 Sentinel 触发防护规则时抛出的顶层异常,下面有 5 个具体的实现类,分别对应不同的防护场景:

异常类名 全限定名 触发场景
AuthorityException com.alibaba.csp.sentinel.slots.block.authority 触发授权规则(如未授权的来源 IP / 服务调用)
DegradeException com.alibaba.csp.sentinel.slots.block.degrade 触发降级规则(如下游服务熔断、RT / 异常比例超标)
FlowException com.alibaba.csp.sentinel.slots.block.flow 触发流控规则(如 QPS / 线程数超过阈值)
ParamFlowException com.alibaba.csp.sentinel.slots.block.flow.param 触发热点规则(如热点参数访问频率超标)
SystemBlockException com.alibaba.csp.sentinel.slots.block.system 触发系统规则(如 CPU / 负载 / 线程数超过阈值)

而对于这些异常由于资源方式的不同又会有不同的处理机制,我们先来针对Web接口来做一个处理

BlockExceptionHandler实现

1.创建一个MyBlockExceptionHandel类并实现BlockExceptionHandel这是Sentinel专门用于处理SpringMVC这些web接口的异常,再去重写它的handle方法:

2.在方法内只需要通过httpServletResponse.getWriter()去写一个JSON数据对于这个JSON数据我们可以定义一个通用的返回对象 R对象,在公共的Model模块下去创建一个通用的包common,去创建一个R对象:

完整代码:

java 复制代码
public class R<T> implements Serializable {
  private static final long serialVersionUID = 1L;

  private Integer code;
  private String message;
  private T data;
  private Long timestamp;

  public R() {
    this.timestamp = System.currentTimeMillis();
  }

  public R(Integer code, String message) {
    this();
    this.code = code;
    this.message = message;
  }

  public R(Integer code, String message, T data) {
    this(code, message);
    this.data = data;
  }

  // 成功响应,无数据
  public static <T> R<T> ok() {
    return new R<>(200, "操作成功");
  }

  // 成功响应,带消息
  public static <T> R<T> ok(String message) {
    return new R<>(200, message);
  }

  // 成功响应,带数据
  public static <T> R<T> ok(T data) {
    return new R<>(200, "操作成功", data);
  }

  // 成功响应,带消息和数据
  public static <T> R<T> ok(String message, T data) {
    return new R<>(200, message, data);
  }

  // 失败响应,默认500错误
  public static <T> R<T> error() {
    return new R<>(500, "操作失败");
  }

  // 失败响应,带消息
  public static <T> R<T> error(String message) {
    return new R<>(500, message);
  }

  // 失败响应,指定状态码和消息
  public static <T> R<T> error(Integer code, String message) {
    return new R<>(code, message);
  }

  // 失败响应,指定状态码、消息和数据
  public static <T> R<T> error(Integer code, String message, T data) {
    return new R<>(code, message, data);
  }

  // getter和setter方法
  public Integer getCode() {
    return code;
  }

  public void setCode(Integer code) {
    this.code = code;
  }

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }

  public T getData() {
    return data;
  }

  public void setData(T data) {
    this.data = data;
  }

  public Long getTimestamp() {
    return timestamp;
  }

  public void setTimestamp(Long timestamp) {
    this.timestamp = timestamp;
  }

  @Override
  public String toString() {
    return "R{" +
        "code=" + code +
        ", message='" + message + '\'' +
        ", data=" + data +
        ", timestamp=" + timestamp +
        '}';
  }
}

3.MyBlockExceptionHandle完整实现:

java 复制代码
@Component
public class MyBlockExceptionHandle implements BlockExceptionHandler {
    // 创建一个ObjectMapper对象
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    public void handle(HttpServletRequest httpServletRequest,
                       HttpServletResponse httpServletResponse, String s, BlockException e) throws Exception {

        // 设置响应的Content-Type为JSON
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        // 获取响应的输出流
        PrintWriter writer = httpServletResponse.getWriter();
        // 创建一个R对象,并设置错误信息
        R<Object> error = R.error(500, s + "被Sentinel限制了,原因:" + e.getClass());
        String json = objectMapper.writeValueAsString(error); // 将对象转为JSON
        // 将JSON写入响应的输出流
        writer.write(json);
        writer.flush();
        writer.close();
    }
}

4.重启项目进行测试,注意重启项目后需要再次配置规则,然后连续点击刷新触发限流查看它的响应:

可以看到成功的响应了JSON格式

@SentinelResource注解实现

通过@SentinelResource注解的两个核心属性,分别处理"阻塞异常"和"业务异常",配置简单、无侵入,适合绝大多数业务场景,也是实战中最常用的方式。

核心属性说明:

  • blockHandler:专门处理 BlockException(阻塞异常),兜底方法需满足两个条件:① 与原方法参数完全一致;② 最后多一个 BlockException 类型的参数(用于接收具体的阻塞异常);

  • fallback:专门处理 业务异常(包括自定义异常、运行时异常),兜底方法需与原方法参数完全一致,无需额外参数;

  • fallbackClass(可选):当兜底方法不在当前类时,指定兜底类(兜底类中的方法需为 static 修饰),解决"兜底方法冗余"问题。

blockHandler实现:

java 复制代码
    // 兜底处理
    public Order createOrderFallBack(Long productId, Long userId, BlockException throwable){
        Order order = new Order();
        order.setId(0L);
        order.setTotalAmount(new BigDecimal(0));
        order.setUserId(0L);
        order.setNickName("未知用户");
        order.setAddress("未知地址");
        order.setProductList(null);
        return order;
    }

流控规则

一、流控模式(决定对谁限流)

  1. 直接(默认)

    • 直接对当前资源(这里是 createOrder)进行流量控制。
    • createOrder 的 QPS 或并发数超过阈值时,直接触发限流。
    • 适用场景:最常用的基础限流,比如限制下单接口每秒最多 100 次。
  2. 关联

    • 当关联的另一个资源达到阈值时,对当前资源进行限流。
    • 例如:当支付接口 pay 超过阈值时,限制下单接口 createOrder,以保护核心支付链路。
    • 适用场景:读写分离、核心业务优先保障。
  3. 链路

    • 只对从指定调用链路过来的请求进行限流,而不是所有访问该资源的请求。
    • 例如:只限制从商品详情页过来的下单请求,而不限制从购物车过来的。
    • 适用场景:精细化控制不同入口的流量。

二、流控效果(决定超过阈值后怎么处理)

  1. 快速失败(默认)

    • 当请求超过阈值时,立即拒绝并抛出 FlowException
    • 响应最快,适合对延迟敏感、非核心的接口。
    • 适用场景:秒杀、抢购等需要快速拒绝多余流量的场景。
  2. Warm Up(预热)

    • 服务刚启动时,阈值从一个较低值缓慢提升到设定的最大值,避免冷启动时被瞬间流量打垮。
    • 例如:设定阈值 100,预热时长 10 秒,则前 10 秒阈值逐步从 30 升到 100。
    • 适用场景:服务重启、系统初始化后,防止流量突增导致服务不可用。
  3. 排队等待

    • 请求会进入队列,按照固定的时间间隔依次处理,保证请求间的间隔不小于 1000ms / QPS阈值
    • 如果等待时间超过设定的超时时间,则拒绝请求。
    • 适用场景:需要平滑处理流量、避免毛刺的场景,如消息队列消费、定时任务。

熔断规则

在 Sentinel 里,熔断规则是为了防止某个不稳定的依赖服务把整个系统拖垮,当它出现大量错误或响应变慢时,就会暂时切断对它的调用,让系统有时间恢复。


一、熔断策略(触发条件)

  1. 慢调用比例(SLOW_REQUEST_RATIO)

    • 以慢调用比例作为阈值。当单位统计时长内,请求的响应时间超过设定的最大 RT(慢调用)的比例超过阈值时,触发熔断。
    • 适用场景:依赖服务响应变慢,需要及时切断调用,避免拖慢整个链路。
  2. 异常比例(ERROR_RATIO)

    • 以异常比例作为阈值。当单位统计时长内,业务异常的比例超过阈值时,触发熔断。
    • 适用场景:依赖服务频繁抛出业务异常,继续调用也大概率失败,此时熔断可以节省资源。
  3. 异常数(ERROR_COUNT)

    • 以异常数作为阈值。当单位统计时长内,业务异常的次数超过阈值时,触发熔断。
    • 适用场景:对异常数量敏感的场景,比如支付接口,短时间内出现多次失败就需要熔断。

二、核心配置项

表格

配置项 说明
资源名 需要熔断的资源名称,例如 createOrder
熔断策略 选择慢调用比例、异常比例或异常数
阈值 触发熔断的阈值,比例为 0-1 之间的小数,异常数为整数
熔断时长 熔断触发后,持续多久不允许访问该资源(单位:秒)
统计时长 用于统计慢调用或异常的时间窗口(单位:秒)
最小请求数 在统计时长内,至少达到多少请求才开始统计熔断条件,避免少量请求就误判
最大 RT(慢调用策略) 超过这个响应时间的请求会被统计为慢调用

三、熔断状态流转

  1. 关闭(CLOSED):服务正常,所有请求都可以通过。
  2. 打开(OPEN):触发熔断条件,所有对该资源的请求直接被拒绝,返回降级结果。
  3. 半开(HALF_OPEN) :熔断时长结束后,进入半开状态,允许少量请求通过,用于探测服务是否恢复。
    • 如果探测成功,恢复到关闭状态。
    • 如果探测失败,再次进入打开状态。

四、示例配置

createOrder 为例,配置一个基于异常比例的熔断规则:

  • 资源名:createOrder
  • 熔断策略:异常比例
  • 阈值:0.5(50%)
  • 统计时长:10 秒
  • 最小请求数:10
  • 熔断时长:30 秒

含义:在 10 秒内,如果 createOrder 收到至少 10 个请求,且其中超过 50% 的请求抛出业务异常,就触发熔断,接下来 30 秒内所有对 createOrder 的请求都会被直接拒绝。

热点规则

在 Sentinel 中,热点规则(热点参数限流) 是一种更细粒度的流控策略,它可以针对资源中某个具体的热点参数(比如用户 ID、商品 ID、IP 地址等)进行单独限流,而不是对整个资源进行一刀切的限制。


一、核心概念

  • 热点参数:指在请求中频繁出现的参数值,比如某个热门商品 ID、高频访问的用户 ID。
  • 隔离限流:对这些热点参数单独设置阈值,防止单个热点参数耗尽整个资源的容量,保证其他参数的请求也能正常处理。

二、适用场景

  1. 热门商品秒杀:限制单个商品 ID 的请求 QPS,防止某个爆款商品的流量压垮整个下单服务。
  2. 用户行为限制:限制单个用户 ID 的请求频率,防止恶意刷接口。
  3. IP 限流:限制单个 IP 地址的访问次数,防止爬虫或攻击。

三、核心配置项

配置项 说明
资源名 需要限流的资源,如 createOrder
参数索引 热点参数在方法参数列表中的位置(从 0 开始),例如 createOrder(String userId, String productId) 中,productId 的索引是 1
统计窗口时长 统计热点参数请求的时间窗口(单位:秒)
单机阈值 单个热点参数在统计窗口内的最大请求数
参数例外项 对特定参数值设置单独的阈值,比如对 VIP 用户 ID 不限制,或对特定商品设置更高阈值

四、示例配置

createOrder(String userId, String productId) 为例,配置热点规则:

  • 资源名:createOrder
  • 参数索引:1(对 productId 限流)
  • 统计窗口时长:1 秒
  • 单机阈值:10
  • 参数例外项:productId = "123456",阈值设置为 100

含义:

  • 对所有商品 ID,每秒最多允许 10 次下单请求。
  • 对热门商品 ID 123456,单独放宽到每秒 100 次请求。

五、工作原理

  1. 参数提取:Sentinel 会根据配置的参数索引,从请求中提取热点参数值。
  2. 统计计数:在滑动时间窗口内,对每个参数值的请求次数进行独立统计。
  3. 阈值判断:当某个参数值的请求次数超过设定阈值时,对该参数值的后续请求进行限流,其他参数值的请求不受影响。

Sentinel持久化

Sentinel 本身默认是将规则保存在内存中的,应用重启后规则就会消失,所以持久化的核心思路是将规则同步到外部存储(如 Nacos、Apollo、ZooKeeper 等),并实现规则的动态推送和拉取 。下面我以最常用的 Nacos 为例,详细讲解实现步骤。

一、实现思路

  1. 规则写入:通过 Sentinel 控制台配置规则时,将规则同步写入 Nacos。
  2. 规则读取:应用启动时从 Nacos 拉取规则并加载到 Sentinel 内存中。
  3. 动态监听:监听 Nacos 配置变化,实时更新 Sentinel 内存中的规则。

二、具体实现步骤(基于 Spring Cloud Alibaba)

1. 引入依赖

在项目的 pom.xml 中添加 Sentinel 与 Nacos 集成的依赖:

XML 复制代码
<!-- Sentinel 核心依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Sentinel 规则持久化到 Nacos -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!-- Nacos 客户端依赖 -->
<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
</dependency>
2. 配置 Nacos 数据源(application.yml)
复制代码
spring:
  cloud:
    sentinel:
      # Sentinel 控制台地址
      transport:
        dashboard: localhost:8080
      # 配置 Nacos 作为规则持久化数据源
      datasource:
        # 自定义数据源名称(如 flow 表示流控规则)
        flow:
          nacos:
            server-addr: localhost:8848  # Nacos 服务地址
            data-id: ${spring.application.name}-sentinel-flow  # 配置文件ID
            group-id: DEFAULT_GROUP  # 分组
            data-type: json  # 数据格式
            rule-type: flow  # 规则类型(flow:流控 / degrade:降级 / authority:授权 / param-flow:热点参数)
        # 可选:配置降级规则持久化
        degrade:
          nacos:
            server-addr: localhost:8848
            data-id: ${spring.application.name}-sentinel-degrade
            group-id: DEFAULT_GROUP
            data-type: json
            rule-type: degrade
3. 自定义 Sentinel 控制台规则同步(关键)

Sentinel 控制台默认不会将规则推送到 Nacos,需要修改控制台的代码,实现规则配置后同步到 Nacos:

注:需下载 Sentinel 控制台源码(官方源码),修改 sentinel-dashboard 模块。

步骤 1:给控制台添加 Nacos 依赖

sentinel-dashboard/pom.xml 中添加:

XML 复制代码
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
</dependency>
步骤 2:实现 Nacos 规则推送类
java 复制代码
package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;

// 流控规则推送到 Nacos
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {

    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<List<FlowRuleEntity>, String> converter;
    // Nacos 配置ID(需和应用端配置一致)
    public static final String FLOW_DATA_ID_POSTFIX = "-sentinel-flow";
    public static final String GROUP_ID = "DEFAULT_GROUP";

    @Override
    public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
        if (app == null || app.isEmpty()) {
            throw new IllegalArgumentException("应用名称不能为空");
        }
        // 转换规则为 JSON 字符串
        String ruleJson = converter.convert(rules);
        // 写入 Nacos
        configService.publishConfig(app + FLOW_DATA_ID_POSTFIX, GROUP_ID, ruleJson);
    }
}
步骤 3:修改控制台的规则控制器

找到 FlowControllerV2 类,注入上面的 FlowRuleNacosPublisher,并修改保存 / 删除规则的方法:

java 复制代码
@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

// 保存规则
@PostMapping("/rule")
public Result<FlowRuleEntity> addFlowRule(@RequestBody FlowRuleEntity entity) {
    // 原有保存逻辑...
    // 新增:推送到 Nacos
    publishRules(entity.getApp());
    return Result.success(entity);
}

// 推送规则到 Nacos
private void publishRules(String app) throws Exception {
    List<FlowRuleEntity> rules = repository.findAllByApp(app);
    rulePublisher.publish(app, rules);
}
4. 测试验证
  1. 启动 Nacos 服务(默认端口 8848)。
  2. 启动修改后的 Sentinel 控制台(端口 8080)。
  3. 启动你的应用,访问 Sentinel 控制台配置流控规则。
  4. 打开 Nacos 控制台(http://localhost:8848/nacos),查看配置列表,能看到生成的规则配置文件。
  5. 重启应用,检查 Sentinel 控制台中规则是否还存在(存在则持久化成功)。
相关推荐
亓才孓2 小时前
[Spring MVC]BindingResult
java·spring·mvc
会算数的⑨2 小时前
Spring AI Alibaba 学习(三):Graph Workflow 深度解析(下篇)
java·人工智能·分布式·后端·学习·spring·saa
小钻风33662 小时前
Spring MVC拦截器的快速应用
java·spring·mvc
wsfk12342 小时前
总结:Spring Boot 之spring.factories
java·spring boot·spring
callJJ2 小时前
Java 源码阅读方法论:从入门到实战
java·开发语言·人工智能·spring·ioc·源码阅读
SuniaWang3 小时前
Spring Boot + Spring AI + Vue 3 + TypeScript + Milvus 项目实战
java·人工智能·spring boot·spring·typescript·框架·前端开发
摇滚侠3 小时前
Spring SpringMVC SpringBoot SpringCloud SpringAI 分别是做什么的
spring boot·spring·spring cloud
deephub3 小时前
Prompt 缓存的四种策略:从精确匹配到语义检索
spring·缓存·prompt
e***8903 小时前
开源模型应用落地-工具使用篇-Spring AI-Function Call(八)
人工智能·spring·开源