Skip to content

Sentinel 极简教程


一、基础理论

1. 定位

  • 流量控制:从 QPS / 并发线程数维度限制资源访问,防止服务被打垮。
  • 熔断降级:依赖下游故障时快速失败,避免级联雪崩。
  • 系统保护:根据 Load、CPU、RT 等系统指标进行自适应保护。
  • 阿里开源,对标 Hystrix 且能力更强,Spring Cloud Alibaba 官方推荐。

2. 核心架构

  • 核心库(Client):嵌入业务进程,通过 AOP / 拦截器统计资源指标,判断规则。
  • Dashboard 控制台:可视化实时监控、动态配置规则、查看簇点链路。
  • 通信机制:Client 通过 HTTP 向 Dashboard 暴露 hearts + metric 数据(端口默认 8719)。

3. 流量控制(Flow)

针对**资源(Resource)**设置限流规则,统计维度两种:

Grade说明
QPS(每秒请求数)最常见,超过阈值直接拦截或排队
并发线程数信号量隔离,防止慢调用拖垮线程池

流控效果(Control Behavior)

  1. 快速失败:默认,直接抛 FlowException
  2. Warm Up(预热):缓慢增加阈值,防止冷系统被突发流量击垮(如秒杀预热)。
  3. 匀速排队(Rate Limiter):严格控制请求通过的时间间隔,用于削峰填谷。

流控模式

  • 直接:当前资源达到阈值就限自己。
  • 关联:当关联资源达到阈值,限流当前资源(如支付接口高并发时限制下单接口)。
  • 链路:只针对从指定入口访问到本资源的流量进行限制(细粒度 API 级别)。

4. 熔断降级(Degrade)

当某个资源不稳定(慢调用或异常过多),自动熔断该资源调用。

统计策略说明
慢调用比例响应时间 > 慢调用 RT 阈值的请求占比超过比例,且请求数 ≥ 最小请求数
异常比例异常请求占总请求的比例超过阈值,且请求数 ≥ 最小请求数
异常数近 1 分钟异常数超过阈值

状态机CLOSED(关闭)OPEN(打开,熔断)HALF_OPEN(半开,放行部分请求探测) → 恢复或重新熔断。

5. 热点参数限流(Param Flow)

针对频繁访问的热点参数值进行限流。
例如:对商品 ID 参数限流,普通商品 QPS 1000,但某个爆款商品 ID="10086" 限制 QPS 为 10。

6. 与 Hystrix 对比

维度HystrixSentinel
隔离策略线程池隔离信号量隔离(并发线程数)
流控能力仅熔断,无精细限流QPS / 并发 / 热点 / 系统级 多维限流
熔断策略异常比例/数慢调用比例、异常比例、异常数
动态规则需依赖 ArchaiusDashboard 实时推送,天然支持动态数据源
实时监控Dashboard 搭建复杂开箱即用,秒级监控
社区状态Netflix 已停更维护阿里持续迭代,国内主流

二、工作实践(复制即用)

1. 基础依赖

xml
<!-- Sentinel + Spring Cloud -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2. 接入 Dashboard

yaml
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8858   # 控制台地址
        port: 8719                  # 本地暴露给 Dashboard 通信的端口,默认8719
      # 取消懒加载(可选):启动即注册,而非第一次访问才初始化
      eager: true

启动 Dashboard(Docker)

bash
docker run --name sentinel \
  -p 8858:8858 \
  -d bladex/sentinel-dashboard:1.8.6

# 账号/密码:sentinel / sentinel

⚠️ 关键特性:Sentinel 属于懒加载,服务启动后必须先访问一次接口,Dashboard 才能看到该服务及规则。


3. 注解方式定义资源(最常用)

java
@RestController
public class OrderController {

    /**
     * value: 资源名(Dashboard 中看到的名字)
     * blockHandler: 被 Sentinel 规则拦截时(限流/降级/热点)调用的方法
     * fallback: 业务代码抛出异常时调用的方法
     */
    @GetMapping("/order/{id}")
    @SentinelResource(
        value = "getOrderById",
        blockHandler = "getOrderBlock",
        fallback = "getOrderFallback"
    )
    public OrderDTO getOrder(@PathVariable Long id) {
        // 模拟业务异常
        if (id < 0) {
            throw new IllegalArgumentException("无效订单号");
        }
        return new OrderDTO(id, "订单-" + id);
    }

    /**
     * blockHandler 要求:
     * 1. 返回类型与原方法一致
     * 2. 参数列表在原方法基础上,最后加一个 BlockException(或其子类)
     * 3. 必须与原方法在同一个类;如果在外部类,需用 blockHandlerClass 指定,且方法为 static
     */
    public OrderDTO getOrderBlock(Long id, BlockException ex) {
        return new OrderDTO(id, "系统繁忙,请稍后查询");
    }

    /**
     * fallback 要求:
     * 1. 返回类型与原方法一致
     * 2. 参数列表在原方法基础上,最后加一个 Throwable
     * 3. 负责捕获业务异常(不会捕获 BlockException)
     */
    public OrderDTO getOrderFallback(Long id, Throwable ex) {
        return new OrderDTO(id, "查询失败,请检查参数");
    }
}

4. 代码定义流控规则(单机版 / 测试用)

生产建议通过 DashboardNacos 动态数据源 推送,避免重启丢失。

java
@Component
public class SentinelConfig {

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

        FlowRule rule = new FlowRule();
        rule.setResource("getOrderById");          // 对应 @SentinelResource 的 value
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // QPS 维度
        rule.setCount(10);                          // 阈值:每秒 10 次
        rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); // 快速失败
        rules.add(rule);

        FlowRuleManager.loadRules(rules);
    }
}

5. 热点参数限流

java
@GetMapping("/hot")
@SentinelResource(value = "hotGood", blockHandler = "hotBlock")
public String hotGood(@RequestParam("goodId") Long goodId, @RequestParam("userId") Long userId) {
    return "查询商品:" + goodId;
}

public String hotBlock(Long goodId, Long userId, BlockException ex) {
    return "该商品太火爆了,请稍后再试";
}

配置热点规则(代码或在 Dashboard 中配置)

java
@PostConstruct
public void initParamRule() {
    ParamFlowRule rule = new ParamFlowRule("hotGood")
        .setParamIdx(0)      // 对第0个参数 goodId 限流
        .setCount(10)        // 普通阈值 QPS=10
        .setDurationInSec(1);

    // 针对具体参数值的特殊阈值:goodId=10086 时 QPS 限制为 1
    ParamFlowItem item = new ParamFlowItem()
        .setObject("10086")  // 参数值(String)
        .setCount(1);
    rule.setParamFlowItemList(Collections.singletonList(item));

    ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
}

6. 熔断降级规则

java
@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(0.2);           // 慢调用比例阈值 20%
    rule.setSlowRatioThreshold(500); // 慢调用 RT:超过 500ms 视为慢调用
    rule.setTimeWindow(10);       // 熔断时长:10 秒
    rule.setMinRequestAmount(5);  // 熔断触发的最小请求数
    rule.setStatIntervalMs(1000); // 统计时长:1 秒

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

7. 自定义统一异常返回(BlockExceptionHandler)

如果不配置,默认返回 Blocked by Sentinel (flow limiting) 页面。生产环境必须自定义 JSON:

java
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(429);

        String msg = "系统繁忙,请稍后再试";
        if (e instanceof FlowException) {
            msg = "访问过于频繁,已被限流";
        } else if (e instanceof DegradeException) {
            msg = "服务已熔断,请稍后再试";
        } else if (e instanceof ParamFlowException) {
            msg = "热点参数限流";
        } else if (e instanceof SystemBlockException) {
            msg = "系统保护触发";
        } else if (e instanceof AuthorityException) {
            msg = "没有权限访问";
            response.setStatus(403);
        }

        response.getWriter().write("{\"code\":999,\"message\":\"" + msg + "\"}");
    }
}

8. Feign 整合 Sentinel(熔断降级)

开启支持

yaml
feign:
  sentinel:
    enabled: true

FallbackFactory(详见 OpenFeign 文档,Sentinel 触发时会走进 Fallback)

java
@FeignClient(
    name = "order-service",
    fallbackFactory = OrderClientFallbackFactory.class
)
public interface OrderClient { ... }

9. 网关层限流(Spring Cloud Gateway)

如需网关层全局限流,需引入:

xml
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

并在 Sentinel Dashboard 的 网关流控菜单 中针对 Route ID 或 API 分组配置规则,此处不展开。


三、核心速查表

概念说明
@SentinelResource定义资源名及异常回调方法
value资源唯一标识,Dashboard 中可见
blockHandler处理 BlockException(限流/降级/热点/系统保护)
fallback处理业务异常(Throwable),不会处理 Sentinel 规则异常
blockHandlerClass指定外部类中的静态方法处理限流
FlowRule流控规则:QPS / 并发线程数
DegradeRule熔断规则:慢调用比例 / 异常比例 / 异常数
ParamFlowRule热点参数限流规则
BlockException所有 Sentinel 拦截异常的父类
SystemBlockException系统保护规则触发异常
AuthorityException黑白名单授权规则异常
懒加载Dashboard 默认需先访问资源接口,才显示监控与规则选项

四、排错速查

现象解决
Dashboard 看不到服务1. 检查 spring.cloud.sentinel.transport.dashboard 配置
2. 必须先访问一次接口,Sentinel 懒加载
3. 检查 8719 端口是否被占用或防火墙拦截
@SentinelResource 没生效1. 确认引入了 spring-cloud-starter-alibaba-sentinel
2. 确认类被 Spring 管理(@RestController / @Component
blockHandler 不触发方法签名错误:必须与原方法同返回类型同参数末尾加 BlockException,且在同一类;若在外部类需 static + blockHandlerClass
fallback 捕获不到限流异常正确!fallback 只管业务异常,BlockException 必须由 blockHandler 处理,二者职责分离
规则重启后丢失代码配置仅在内存生效;生产环境务必对接 Nacos / Apollo / ZooKeeper 等持久化数据源,或提交到 DB + ReadableDataSource
规则配置未生效1. 检查资源名是否完全匹配(区分大小写)
2. 检查是否被其他规则覆盖(FlowRuleManager.loadRules 是全量覆盖)