Sentinel 限流熔断与系统防护实战

Sentinel是什么

Sentinel(面向流量防护的轻量级中间件)是 Spring Cloud Alibaba 生态中负责流量控制熔断降级系统负载保护的组件。它解决的核心问题是:微服务之间互相调用时,一个上游的流量尖刺或下游的故障如何不拖垮整个系统。

简单说:Nacos 管"服务在哪里",Sentinel 管"服务能不能抗住"。

为什么需要

问题 没有防护的后果 Sentinel 怎么做
突发流量 瞬间打满 CPU/内存,服务雪崩 限流(直接拒绝 / 排队等待 / 预热)
下游服务变慢 上游线程全部阻塞,连锁故障 熔断降级(快速失败 + fallback)
系统负载过高 服务响应全面退化 系统自适应保护(Load / CPU / RT 自动兜底)

Sentinel 整体架构

graph TB subgraph Sentinel Core SC[核心库<br>资源 + 规则 + 指标统计] end subgraph 客户端集成 WEB[Spring Web<br>拦截器适配] DUBBO[Dubbo<br>过滤器适配] FEIGN[OpenFeign<br>整合] GW[Gateway<br>网关适配] end subgraph 控制台 DS[Dashboard<br>实时监控 + 规则下发] end subgraph 规则存储 NS[Nacos / Apollo<br>动态配置持久化] end WEB --> SC DUBBO --> SC FEIGN --> SC GW --> SC DS -->|API| SC NS -.->|拉取规则| SC style SC fill:#c8e6c9 style DS fill:#e1f5fe style NS fill:#fff9c4

限流(Flow Control)

核心概念

资源 — Sentinel 保护的最小单位,可以是方法、接口或代码块。通过 @SentinelResource 注解定义,或自动适配 Spring MVC 的每个端点。

规则 — 定义"怎么保护资源",由控制台配置或代码预先定义。

限流算法

算法 效果 适合场景
直接拒绝(快速失败) 超出 QPS 阈值直接返回限流异常 大多数 API 接口
Warm Up(冷启动) 阈值从 阈值/coldFactor 逐步升至设定值 系统刚启动或长时间空闲后的流量恢复
排队等待(匀速通过) 请求排队匀速处理,超出队列超时时间直接失败 消息处理、削峰填谷

流控模式

graph LR subgraph 限流模式 D[**直接**] -->|A 资源超阈值| L1[A 被限流] R[**关联**] -->|关联资源 B 超阈值| L2[A 被限流] LK[**链路**] -->|从入口 X 进入的流量<br>超过阈值| L3[入口 X 的请求被限流] end style D fill:#c8e6c9 style R fill:#e1f5fe style LK fill:#fff9c4

关联模式举例: 支付接口(/pay)和订单查询(/order/query)共享数据库连接池。设置 /pay 为关联资源,当 /pay 的 QPS 超阈值时,直接限流 /order/query,保护数据库连接不被 /pay 的慢查询耗尽。这是"放弃非核心保核心"的典型策略。

熔断降级(Circuit Breaking)

熔断器状态机

graph TD C[CLOSED<br>正常状态] -->|慢调用比例/异常比例<br>超过阈值| O[OPEN<br>熔断状态] O -->|熔断时长结束| H[HALF-OPEN<br>半开探测] H -->|探测请求成功| C H -->|探测请求仍失败| O style C fill:#c8e6c9 style O fill:#ffcdd2 style H fill:#fff9c4

三种熔断策略

策略 阈值含义 统计维度 适用场景
慢调用比例 最大 RT(如 > 500ms 就是慢调用) 时间窗口内慢调用占比 下游偶尔变慢的场景
异常比例 异常数/总请求数(如 > 0.5 即 50%) 异常占比 依赖的下游不稳定
异常数 时间窗口内异常总数(如 > 10 次) 绝对次数 异常稀疏但绝对数量可观的场景

熔断后的恢复路径:

  1. 熔断器 OPEN → 所有请求直接降级走 fallback
  2. 经过熔断时长(如 5 秒)→ 进入 HALF-OPEN
  3. HALF-OPEN 放行一个探测请求 → 成功?回到 CLOSED。失败?回到 OPEN

系统自适应保护(System Protection)

Sentinel 从全局入口(所有流量进入应用的第一层)出发做的保护,不是针对单个资源,而是保护整个应用的极限水位。

维度 说明
Load 当系统 Load1(1 分钟平均 Load)超过阈值,且当前并发线程数超过预估容量时触发
CPU 使用率 当 CPU 使用率超过阈值时触发限流
平均 RT 当所有入口流量的平均 RT 超过阈值时触发
并发线程数 当入口流量并发线程数超过阈值时触发
入口 QPS 当所有入口流量的 QPS 超过阈值时触发

和限流的区别: 限流是单资源维度的精准控制;系统保护是整体维度的粗粒度兜底——就像家里的每个电器有自己的保险丝,但总闸也有一个过载保护。

新人上手指南

第一步:启动 Sentinel 控制台

# 下载(当前稳定版 1.8.8)
curl -O https://github.com/alibaba/Sentinel/releases/download/1.8.8/sentinel-dashboard-1.8.8.jar

# 启动(默认运行在 8080 端口)
java -jar sentinel-dashboard-1.8.8.jar

# 访问 http://localhost:8080  默认账号密码: sentinel / sentinel

Sentinel 控制台本质是一个 Spring Boot 应用,用于展示实时监控和配置规则。
生产环境请参考官方文档加 -Dserver.port 和 -Dauth.username/password 参数。

第二步:客户端接入 Sentinel

1. 添加依赖:

<!-- Spring Cloud Alibaba Sentinel 启动器 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2. 配置 application.yml:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080   # 控制台地址
        port: 8719                   # 客户端与控制台通信端口(默认 8719)
  # OpenFeign 整合:开启 Feign 的 Sentinel 支持
feign:
  sentinel:
    enabled: true

3. 启动后访问任意接口:

访问几次业务接口,控制台就能看到实时监控。Sentinel 采用懒加载策略——必须有一次真实请求后,资源才会出现在控制台。

第三步:配置规则

方式一:控制台配置(推荐开发调试时使用)

登陆控制台 → "簇点链路" → 找到对应资源 → "+流控" 或 "+熔断"。配置后立刻生效。

方式二:注解 + 代码配置(推荐生产使用,规则持久化)

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

    @GetMapping("/create")
    @SentinelResource(
        value = "createOrder",                    // 资源名称
        blockHandler = "createOrderBlock",        // 限流/熔断后的兜底方法
        blockHandlerClass = OrderBlockHandler.class,
        fallback = "createOrderFallback"          // 业务异常时的兜底方法
    )
    public Result createOrder(@RequestParam Long userId) {
        // 正常业务逻辑
        if (userId == null) {
            throw new IllegalArgumentException("用户 ID 不能为空");
        }
        return Result.ok("订单创建成功");
    }
}

// 兜底处理类(方法必须为 public static,入参与原方法一致 + BlockException)
public class OrderBlockHandler {
    public static Result createOrderBlock(Long userId, BlockException e) {
        return Result.error("系统繁忙,请稍后再试");
    }

    public static Result createOrderFallback(Long userId, Throwable t) {
        return Result.error("业务异常: " + t.getMessage());
    }
}

@SentinelResource 关键属性速查:

属性 作用 触发条件
value 资源名称,控制台以此识别 必填
blockHandler 被限流/熔断时的兜底 BlockException 触发
fallback 业务代码抛出异常时 非 BlockException 的异常
defaultFallback 通用兜底(未指定 blockHandler/fallback 时生效) 所有异常
exceptionsToIgnore 指定忽略的异常类型,不触发 fallback 特定异常

blockHandler vs fallback 的区别: blockHandler 处理的是 Sentinel 自身的限流/熔断异常(BlockException),fallback 处理的是业务代码抛出的异常。两者可以共存,互不冲突。

常见问题

1. 控制台看不到服务

  • 确认 spring.cloud.sentinel.transport.dashboard 配置正确
  • 访问一次任意接口后再刷新(懒加载)
  • 检查防火墙:控制台 8080 和客户端 8719 端口正常通信
  • 如果用了 Spring Cloud Gateway,需引入 spring-cloud-alibaba-sentinel-gateway 依赖

2. 规则配置后不生效

  • 控制台配置的规则保存在内存中,服务重启后丢失。生产环境需配合 Nacos/Apollo 做规则持久化
  • 资源名不一致:控制台的资源名必须和 @SentinelResource(value = "...") 一致
  • blockHandler 方法签名不匹配:返回值、参数列表(含 BlockException)必须与原方法一致

3. @SentinelResource 限流了但没走 blockHandler

最常见的原因是 blockHandler 方法签名不对

// ❌ 错误:缺少 BlockException 参数
public static String createOrderBlock(Long userId) { ... }

// ✅ 正确:参数必须与原方法一致 + BlockException 放在最后
public static String createOrderBlock(Long userId, BlockException e) { ... }

4. Sentinel 和 Hystrix 的区别(面试常问)

维度 Sentinel Hystrix(已停更)
隔离策略 信号量隔离 线程池/信号量隔离
限流能力 基于 QPS/线程数 + 流量整形(Warm Up、排队等) 有限支持
熔断策略 慢调用比例、异常比例、异常数 基于失败比例
系统自适应保护 ✅ 支持 ❌ 不支持
实时监控 ✅ 开箱即用控制台 ⚠️ 需要整合 Turbine
规则持久化 SPI 扩展,支持 Nacos/Apollo ❌ 无原生支持
活跃状态 ✅ 持续维护 ❌ 2018 年停更

面试题

Q1:Sentinel 的限流和熔断有什么区别?什么时候该用哪个?

参考答案:

限流保护的是自身,熔断保护的是自身不被下游拖垮——这是两者最本质的区别。

限流:当流量超过自身处理能力时主动拒绝请求,防止服务被击垮。触发条件是"流量 > 阈值"(QPS 或线程数)。适用于能预测自身容量边界的场景。

熔断:当下游(或被调用的依赖)出现故障或响应变慢时,主动切断对其的调用链路,快速失败而不是长时间等待。触发条件是"下游的异常/慢调用比例超过阈值"。适用于服务间调用场景(A 调 B,B 变慢时熔断对 B 的调用)。

两者可以同时存在——比如一个订单接口可以既设置 QPS 限流(保护自身),又设置针对下游用户服务的熔断规则(防止用户服务故障拖垮订单服务)。

对比:

限流 熔断
保护对象 自身不被入流量压垮 自身不被故障下游拖垮
触发条件 流量超过设定阈值 下游异常比例/占比超过阈值
恢复方式 流量降下来自动恢复 熔断时长后进入 HALF-OPEN 探测恢复
典型场景 秒杀、大促 下游服务慢/故障

Q2:Sentinel 控制台配置的规则重启后就没了,怎么解决?

参考答案:

Sentinel 控制台的规则是存在内存中的,服务重启或控制台重启都会丢失。生产环境必须做规则持久化。有两种主流方案:

方案一:Nacos 作为规则数据源(推荐)

Sentinel 提供了 SPI 扩展,从 Nacos 中拉取规则配置,控制台修改规则时同步写入 Nacos。

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
spring:
  cloud:
    sentinel:
      datasource:
        flow:                     # 流控规则
          nacos:
            server-addr: localhost:8848
            data-id: sentinel-flow-rules
            rule-type: flow       # 规则类型:flow / degrade / system 等
        degrade:                  # 熔断规则
          nacos:
            server-addr: localhost:8848
            data-id: sentinel-degrade-rules
            rule-type: degrade

在 Nacos 中创建对应的 DataId,配置 JSON 格式的规则内容。这样规则配置和业务配置一样,放在同一个配置中心统一管理。

方案二:启动时代码加载规则

@PostConstruct
public void initFlowRules() {
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule = new FlowRule();
    rule.setResource("createOrder");
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setCount(100);            // 100 QPS
    rules.add(rule);
    FlowRuleManager.loadRules(rules);
}

两种方案的选择:Nacos 持久化适合需要动态调整规则的场景;代码加载适合规则相对固定的场景,改规则需要重启服务。推荐用 Nacos 方案。

Q3:一个请求被 Sentinel 限流后,客户端会收到什么?如何做友好的限流提示?

参考答案:

默认情况下,被 Sentinel 限流后会抛 BlockException,Spring Boot 默认返回 429(Too Many Requests)状态码 + 简单的错误信息。这对用户不友好。

有两种方式做自定义限流提示:

方式一:@SentinelResource 的 blockHandler(推荐,精细控制)

每个资源指定自己的 blockHandler 方法,返回友好的业务错误信息。如前面的例子所示,返回 Result.error("系统繁忙,请稍后再试") 替代默认的异常信息。

方式二:全局的 BlockExceptionHandler(统一兜底)

实现一个全局处理器,所有未在 @SentinelResource 中指定 blockHandler 的资源都会走这里:

@Component
public class MySentinelBlockHandler implements BlockExceptionHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
                       BlockException e) throws Exception {
        response.setStatus(429);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(
            "{\"code\":429, \"msg\":\"系统繁忙,请您稍后再试\"}"
        );
    }
}

两种方式的职责边界:blockHandler 适合"我知道这个接口被限流时该返回什么"的场景;全局 handler 适合"我不知道哪些接口被限流,但要统一保证不返回原始异常"的场景。实践中可以先用全局 handler 兜底,再对核心接口逐个加 @SentinelResource 做精细化的提示。

延伸阅读: Sentinel 官方 Wiki https://github.com/alibaba/Sentinel/wiki 和技术博客《阿里巴巴 Sentinel 技术解密》,里面详细解释了滑动窗口和限流算法的实现细节。

posted @ 2026-07-27 21:34  念笙  阅读(34)  评论(0)    收藏  举报