侧边栏壁纸
  • 累计撰写 69 篇文章
  • 累计创建 28 个标签
  • 累计收到 21 条评论

目 录CONTENT

文章目录

Spring Boot 3.x 集成 Sentinel:微服务流量控制与熔断降级实战全攻略

Administrator
2026-03-23 / 0 评论 / 0 点赞 / 0 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

前言

在微服务架构中,服务之间的调用链路错综复杂。一旦某个下游服务出现响应变慢或不可用,极容易引发雪崩效应——上游服务因等待响应而线程耗尽,最终导致整个系统崩溃。

Sentinel 是阿里巴巴开源的微服务流量治理框架,提供了流量控制、熔断降级、系统自适应保护等能力,是 Spring Cloud Alibaba 体系中的核心组件。

本文将手把手带你在 Spring Boot 3.x 项目中集成 Sentinel,实现:

  • ✅ 接口级别的 QPS 限流
  • ✅ 基于慢调用比例的熔断降级
  • ✅ 自定义 BlockException 返回结构
  • ✅ Sentinel Dashboard 可视化监控

踩坑提示:Spring Boot 3.x 对应 Spring Cloud 2023.x,与 2.x 时代的配置方式有若干差异,本文会重点标注。


一、核心概念速览

在动手之前,先理清几个核心概念:

概念说明
资源(Resource)需要保护的对象,可以是接口、方法、代码块
规则(Rule)针对资源的限流/熔断策略
BlockException触发规则后抛出的异常基类
Slot ChainSentinel 的处理链,依次经过统计、限流、熔断等 Slot

限流(Flow Control):控制单位时间内的请求数(QPS)或并发线程数。

熔断降级(Circuit Breaker):当资源异常率或响应时间超过阈值时,自动断开调用链,返回兜底结果,防止级联故障。


二、环境准备

2.1 版本说明

JDK 21
Spring Boot 3.2.x
Spring Cloud Alibaba 2023.0.1
Sentinel 1.8.8

2.2 Maven 依赖

<!-- Spring Cloud Alibaba BOM,统一版本管理 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2023.0.1.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <!-- Sentinel Starter -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>

    <!-- Sentinel 对 OpenFeign 的支持(如有 Feign 调用) -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
</dependencies>

⚠️ 踩坑:Spring Boot 3.x 不再兼容 spring-cloud-starter-alibaba-sentinel 2.x 版本,务必使用 2023.0.x 系列。


三、application.yml 配置

spring:
  application:
    name: sentinel-demo

  cloud:
    sentinel:
      transport:
        # Sentinel Dashboard 地址
        dashboard: localhost:8080
        # 本服务向 Dashboard 汇报的端口(默认 8719,多服务部署时注意区分)
        port: 8719
      # 饥饿加载:启动时就初始化 Sentinel,不等第一次请求
      eager: true
      # 开启对 Web 请求的自动拦截(默认 true)
      web-context-unify: false

💡 web-context-unify: false 很关键:设为 false 后,每个接口路径会作为独立资源统计,否则所有 web 请求会被归并到同一上下文,导致链路规则失效。


四、下载并启动 Sentinel Dashboard

Sentinel Dashboard 是一个独立的 Spring Boot 应用,用于可视化配置规则和查看实时流量。

# 下载 jar(1.8.8 版本)
wget https://github.com/alibaba/Sentinel/releases/download/1.8.8/sentinel-dashboard-1.8.8.jar

# 启动(默认端口 8080)
java -Dserver.port=8080 \
     -Dcsp.sentinel.dashboard.server=localhost:8080 \
     -Dproject.name=sentinel-dashboard \
     -jar sentinel-dashboard-1.8.8.jar

访问 http://localhost:8080,默认账号密码均为 sentinel


五、注解方式声明资源

Sentinel 提供了 @SentinelResource 注解,非常简洁地声明受保护的资源。

5.1 基础示例

@RestController
@RequestMapping("/api/order")
public class OrderController {

    @GetMapping("/{id}")
    @SentinelResource(
        value = "getOrderById",          // 资源名称
        blockHandler = "handleBlock",    // 限流/熔断时的处理方法
        fallback = "handleFallback"      // 业务异常时的兜底方法
    )
    public Result<Order> getOrderById(@PathVariable Long id) {
        // 模拟业务逻辑
        return orderService.findById(id);
    }

    // blockHandler:专门处理 BlockException(限流、熔断触发时调用)
    // 方法签名必须与原方法一致,末尾加 BlockException 参数
    public Result<Order> handleBlock(Long id, BlockException ex) {
        log.warn("资源 [getOrderById] 被限流/熔断,id={}, rule={}", id, ex.getRule());
        return Result.fail(429, "服务繁忙,请稍后重试");
    }

    // fallback:处理业务异常(非 BlockException)
    public Result<Order> handleFallback(Long id, Throwable t) {
        log.error("资源 [getOrderById] 业务异常,id={}", id, t);
        return Result.fail(500, "服务暂时不可用");
    }
}

5.2 blockHandler 与 fallback 的区别

属性触发场景典型用途
blockHandlerBlockException(限流、熔断、系统保护触发)返回友好的限流提示
fallback任何 Throwable(业务异常、超时、NPE 等)通用兜底/降级

若同时配置,BlockException 会优先走 blockHandler,业务异常走 fallback


六、流量控制规则配置

6.1 Dashboard 配置(推荐)

在 Sentinel Dashboard 中:

  1. 左侧导航选择你的服务
  2. 找到「流控规则」→「新增流控规则」
  3. 配置如下:
字段示例值说明
资源名getOrderById与 @SentinelResource 的 value 对应
阈值类型QPS也可选「并发线程数」
单机阈值10每秒最多 10 次请求
流控模式直接也可选「关联」或「链路」
流控效果快速失败也可选「Warm Up」或「排队等待」

6.2 代码方式配置(适合测试)

@Configuration
public class SentinelRuleConfig {

    @PostConstruct
    public void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();

        FlowRule rule = new FlowRule();
        rule.setResource("getOrderById");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);  // 按 QPS 限流
        rule.setCount(10);                            // QPS 阈值 10
        rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); // 快速失败

        rules.add(rule);
        FlowRuleManager.loadRules(rules);
        log.info("Sentinel 流控规则初始化完成");
    }
}

6.3 Warm Up 预热模式

对于刚启动的服务,冷启动阶段缓存未预热,突然大流量会压垮服务。Warm Up 模式可以让阈值从低到高逐渐增长:

FlowRule warmUpRule = new FlowRule();
warmUpRule.setResource("getOrderById");
warmUpRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
warmUpRule.setCount(100);                                           // 最终目标 QPS
warmUpRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
warmUpRule.setWarmUpPeriodSec(10);                                  // 10秒内从 33 QPS 爬升到 100

💡 Warm Up 的起始阈值为 count / coldFactor,coldFactor 默认为 3,即从 100/3 ≈ 33 QPS 开始预热。


七、熔断降级规则配置

Sentinel 1.8.x 支持三种熔断策略:

策略枚举值说明
慢调用比例SLOW_REQUEST_RATIO响应时间超过阈值的请求比例超标时熔断
异常比例EXCEPTION_RATIO异常请求比例超标时熔断
异常数EXCEPTION_COUNT统计周期内异常数超标时熔断

7.1 慢调用比例熔断(最常用)

@PostConstruct
public void initDegradeRules() {
    List<DegradeRule> rules = new ArrayList<>();

    DegradeRule rule = new DegradeRule();
    rule.setResource("getOrderById");
    rule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType());
    rule.setCount(500);          // 慢调用 RT 阈值:响应时间 > 500ms 视为慢调用
    rule.setSlowRatioThreshold(0.5);  // 慢调用比例 > 50% 时触发熔断
    rule.setMinRequestAmount(5); // 最小请求数:统计窗口内至少 5 次请求才触发判断
    rule.setStatIntervalMs(1000);// 统计时间窗口:1秒
    rule.setTimeWindow(10);      // 熔断持续时间:10秒后进入半开状态

    rules.add(rule);
    DegradeRuleManager.loadRules(rules);
}

7.2 熔断状态机

Sentinel 的熔断器遵循标准的三态模型:

CLOSED(关闭)
    │  异常/慢调用比例超阈值
    ▼
OPEN(打开)← 所有请求直接走 blockHandler
    │  timeWindow 时间后
    ▼
HALF_OPEN(半开)← 放行一个探测请求
    │  成功 → CLOSED
    │  失败 → OPEN(重置计时)

八、全局异常处理

每个接口都写 blockHandler 太繁琐,推荐用全局处理器统一拦截 Web 层的 BlockException

/**
 * Sentinel 全局 Block 异常处理器
 * 适用于 Spring MVC / Spring Boot Web 项目
 */
@Component
public class SentinelBlockExceptionHandler implements BlockExceptionHandler {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
                       String resourceName, BlockException ex) throws Exception {

        response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");

        String message;
        if (ex instanceof FlowException) {
            message = "请求过于频繁,请稍后重试";
        } else if (ex instanceof DegradeException) {
            message = "服务降级中,请稍后再试";
        } else if (ex instanceof SystemBlockException) {
            message = "系统负载过高,请稍后重试";
        } else {
            message = "服务暂时不可用";
        }

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("code", 429);
        body.put("message", message);
        body.put("resource", resourceName);
        body.put("timestamp", System.currentTimeMillis());

        response.getWriter().write(MAPPER.writeValueAsString(body));
    }
}

⚠️ Spring Boot 3.x 踩坑WebCallbackManager.setBlockHandler() 在 3.x 中已废弃,请使用实现 BlockExceptionHandler 接口并注册为 Bean 的方式。


九、与 OpenFeign 集成(熔断远程调用)

当服务 A 通过 Feign 调用服务 B 时,同样需要熔断保护。

9.1 开启 Feign + Sentinel

feign:
  sentinel:
    enabled: true

9.2 定义 Feign 客户端与 Fallback

@FeignClient(
    name = "inventory-service",
    fallbackFactory = InventoryClientFallbackFactory.class
)
public interface InventoryClient {

    @GetMapping("/api/inventory/{productId}")
    Result<Integer> getStock(@PathVariable Long productId);
}
@Component
public class InventoryClientFallbackFactory
        implements FallbackFactory<InventoryClient> {

    @Override
    public InventoryClient create(Throwable cause) {
        return productId -> {
            log.warn("库存服务调用失败,productId={},原因:{}", productId, cause.getMessage());
            // 返回兜底库存数量(如 0 表示暂时无法查询)
            return Result.fail(503, "库存服务暂时不可用");
        };
    }
}

💡 使用 FallbackFactory 而非直接 fallback,好处是可以拿到原始异常 cause,便于日志追踪。


十、规则持久化到 Nacos

默认情况下,Sentinel 规则存储在内存中,服务重启后规则丢失。生产环境必须做规则持久化。

10.1 添加依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

10.2 配置 Nacos 数据源

spring:
  cloud:
    sentinel:
      datasource:
        # flow-rules 是数据源名称,可自定义
        flow-rules:
          nacos:
            server-addr: localhost:8848
            namespace: dev
            group-id: SENTINEL_GROUP
            data-id: ${spring.application.name}-flow-rules
            rule-type: flow   # 规则类型:flow / degrade / system / authority / param-flow
        degrade-rules:
          nacos:
            server-addr: localhost:8848
            namespace: dev
            group-id: SENTINEL_GROUP
            data-id: ${spring.application.name}-degrade-rules
            rule-type: degrade

10.3 Nacos 中的规则格式(JSON)

在 Nacos 控制台创建配置,Data ID 为 sentinel-demo-flow-rules,内容:

[
  {
    "resource": "getOrderById",
    "grade": 1,
    "count": 10,
    "strategy": 0,
    "controlBehavior": 0,
    "clusterMode": false
  }
]

✅ 规则持久化后,即使服务重启,从 Nacos 拉取规则后立即生效,无需重新在 Dashboard 配置。


十一、常见踩坑汇总

坑 1:@SentinelResource 不生效

原因:Sentinel 基于 AOP 实现,如果 blockHandler/fallback 方法在同一个 Bean 内通过 this.method() 调用,AOP 代理不会生效。

解决:将 blockHandler 提取到独立的类,通过 blockHandlerClass 指定:

@SentinelResource(
    value = "getOrderById",
    blockHandlerClass = OrderBlockHandler.class,
    blockHandler = "handleBlock"
)

坑 2:流控规则对 Feign 调用不生效

原因web-context-unify 默认为 true,所有调用归并到同一上下文。

解决:设置 spring.cloud.sentinel.web-context-unify: false

坑 3:Dashboard 看不到服务

原因:Sentinel 客户端需要接受至少一次请求后才会向 Dashboard 注册。

解决:配置 spring.cloud.sentinel.eager: true,服务启动时主动注册。

坑 4:熔断后一直不恢复

原因timeWindow 配置的是秒数,容易填错为毫秒。

解决:确认 timeWindow 单位是秒(如 10 表示 10 秒后尝试恢复)。


十二、完整演示效果

启动服务后,使用压测工具(如 wrkApache Bench)模拟超阈值请求:

# 使用 ab 工具,发送 100 个并发请求
ab -n 1000 -c 100 http://localhost:8080/api/order/1

当 QPS 超过 10 时,多余的请求会立即收到:

{
  "code": 429,
  "message": "请求过于频繁,请稍后重试",
  "resource": "getOrderById",
  "timestamp": 1742695200000
}

在 Sentinel Dashboard 的「实时监控」页面,可以看到通过数和拒绝数的实时曲线图。


总结

本文从零开始,完整演示了 Spring Boot 3.x 集成 Sentinel 的全过程:

功能实现方式
声明受保护资源@SentinelResource 注解
流量控制FlowRule(QPS/线程数,支持 Warm Up、排队等待)
熔断降级DegradeRule(慢调用比例、异常比例、异常数)
全局异常处理实现 BlockExceptionHandler 接口
Feign 熔断FallbackFactory + feign.sentinel.enabled: true
规则持久化Nacos 数据源,规则零丢失

Sentinel 是微服务稳定性治理的利器,与 Spring Boot 3.x + Spring Cloud Alibaba 的组合已经非常成熟。如果你的项目还没有引入流量治理,现在是最好的时机。

下一篇文章,我们将继续探讨 Sentinel + Gateway 网关层限流,实现统一入口的流量管控,敬请期待!


💬 如有疑问或踩到新的坑,欢迎在评论区留言交流!
⭐ 觉得有用的话,点个赞支持一下~

0

评论区