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 控制台中规则是否还存在(存在则持久化成功)。
相关推荐
云烟成雨TD4 小时前
Spring AI 1.x 系列【51】可观测性技术选型
java·人工智能·spring
unicrom_深圳市由你创科技5 小时前
基于Spring AI框架的RAG应用
人工智能·spring·机器学习
七老板的blog6 小时前
当 Spring StateMachine 遇见大模型:构建工业级 AI 写作流水线
java·人工智能·spring
云烟成雨TD7 小时前
Spring AI 1.x 系列【46】MCP Security 模块
java·人工智能·spring
小旭95278 小时前
Spring AI Alibaba 从入门到实战:一站式掌握企业级 AI 应用开发
java·人工智能·spring
云烟成雨TD9 小时前
Spring AI 1.x 系列【50】可观测性:接入 Prometheus + Grafana
人工智能·spring·prometheus
phltxy10 小时前
MCP 从协议到 Spring AI 实战
人工智能·spring·oracle
Volunteer Technology12 小时前
SpringSecurity请求流转的本质
java·spring
云烟成雨TD14 小时前
Spring AI 1.x 系列【42】MCP 服务端 Spring Boot 启动器
java·人工智能·spring
云烟成雨TD14 小时前
Spring AI 1.x 系列【38】模型上下文协议(MCP)
java·人工智能·spring