Skip to content

Sentinel ​

Java 高级 · 阿里中间件

Sentinel 是分布式系统的"流量防卫兵"。它不止是"加个注解就限流",真正的能力在于:用滑动窗口做高精度实时统计、用责任链(ProcessorSlot)把限流/熔断/系统保护串成可扩展管线、用状态机管理熔断的恢复探测。本文把统计内核、责任链、熔断状态机与热点/集群流控讲透。

一、资源与规则:一切皆"资源" ​

Sentinel 的保护对象是 Resource(资源)——任意逻辑单元(方法、URL、RPC 接口、代码块)。通过 @SentinelResource 或框架适配(Spring MVC、Dubbo、Gateway)自动定义。对资源施加的约束就是 Rule:

  • FlowRule(限流):基于 QPS 或线程数限制访问速率。
  • DegradeRule(熔断降级):基于慢调用比例 / 异常比例 / 异常数,触发后熔断。
  • ParamFlowRule(热点参数限流):对方法参数粒度限流(如某 userId 被刷)。
  • SystemRule(系统保护):按 Load、CPU、平均 RT 做自适应保护。
  • AuthorityRule(黑白名单):来源 IP/来源应用控制。

二、统计内核:LeapArray 滑动窗口 ​

限流/熔断的"决策依据"是实时统计值(QPS、RT、异常数),而统计的核心是 LeapArray(滑动窗口)。它把时间切成多个 Window(时间槽),每个槽存一小段时间内的统计:

java
// LeapArray 本质: 环形数组 + 时间映射
public class LeapArray<T> {
    int windowLengthInMs;   // 单窗口时长(如 500ms)
    int sampleCount;        // 窗口数(如 2) → 总窗长 1s
    AtomicReferenceArray<WindowWrap<T>> array;  // 环形数组
}

为什么用滑动窗口而非固定窗口? 固定窗口在"窗口边界"会出现两倍流量穿透:例如限流 100/s,第 1 秒后 500ms 来 100 个、第 2 秒前 500ms 又来 100 个,固定窗口各自放行,但实际 1 秒内来了 200 个。滑动窗口统计"过去 N 秒"的连续区间,边界处也平滑准确。

LeapArray 用原子数组 + CAS 重置过期窗口实现无锁高性能;WindowWrap 内用 LongAdder 累加(高并发下分段计数,减少 CAS 争用)。

三、责任链:ProcessorSlotChain ​

一次资源访问会穿过一条 ProcessorSlot 责任链(类似 Netty 的 Pipeline):

  • NodeSelectorSlot:为每个资源建 DefaultNode(调用树节点),支撑按调用链路限流。
  • ClusterBuilderSlot:建 ClusterNode(资源维度的全局统计,跨 EntranceNode 共享)。
  • StatisticSlot:核心统计点——在 entry 通过前/后记录 pass、block、RT、exception,喂给 LeapArray。
  • FlowSlot:依据 FlowRule + 实时统计做限流判断(rule.passQps vs 当前窗口 pass 数)。
  • DegradeSlot:依据 DegradeRule 判断是否需要熔断(慢调用/异常比例超阈值)。
  • SystemSlot:系统级保护(Load/CPU 超阈值直接拒)。
  • AuthoritySlot:黑白名单。

TIP

责任链设计的妙处:每个 Slot 只关心自己那一小段逻辑,新增一种保护策略只需加一个 Slot。限流/熔断的"规则"和"统计"解耦——StatisticSlot 沉淀数据,FlowSlot/DegradeSlot 只做决策。这也解释了为什么规则可以动态推送:改 FlowRuleManager 的规则集合即可,责任链结构不动。

四、限流效果与调用关系 ​

FlowRule 不只是"超了就拒",还有丰富的语义:

  • 流控效果:
    • DIRECT(快速失败):超阈值立即抛 FlowException,由 blockHandler 兜底。
    • WARM_UP(预热):冷启动时阈值从 threshold / 3 缓缓升到阈值,应对缓存预热(如令牌桶)。
    • RATE_LIMITER(排队等待):以匀速处理,超过则排队,超时则拒,用于削峰填谷。
  • 调用关系:STRATEGY_DIRECT(对本身限流)、STRATEGY_RELATE(关联资源,如"支付接口忙时限制查询")、STRATEGY_CHAIN(链路:仅对特定调用入口限流,靠 NodeSelectorSlot 的调用树)。

五、熔断状态机:closed / open / half-open ​

熔断降级用经典状态机,避免"上游慢/错 → 自身线程堆积 → 雪崩":

  • Closed(关闭):正常放行,持续统计。当慢调用比例(RT > slowRtMs 的请求占比)或异常比例超阈值,且请求数达最小采样,转 Open。
  • Open(打开):拒绝所有请求(直接抛 DegradeException),给上游 fallback 兜底。经过 timeWindow 休眠期后进入 HalfOpen。
  • HalfOpen(半开):放少量探测请求,成功则恢复 Closed,失败则回到 Open 重新计时。

5.1 代码示例 ​

java
@SentinelResource(value = "createOrder",
    blockHandler = "blockHandler",     // 限流/熔断触发时兜底(参数末位加 BlockException)
    fallback = "fallback")             // 业务异常时兜底(参数末位加 Throwable)
public Order createOrder(Long userId) { return orderSvc.create(userId); }

// 限流/熔断兜底: 返回降级响应, 防止雪崩扩散
public Order blockHandler(Long userId, BlockException ex) {
    throw new BizException("系统繁忙,请稍后再试");
}
// 代码/配置中心推送规则
List<FlowRule> rules = new ArrayList<>();
rules.add(new FlowRule("createOrder").setCount(200).setGrade(RuleConstant.FLOW_GRADE_QPS));
FlowRuleManager.loadRules(rules);

WARNING

  • 只配限流不配熔断:上游故障时会因线程堆积拖垮自己。限流防"过载",熔断防"雪崩",二者配合。
  • blockHandler / fallback 签名必须正确:必须是"原方法参数 + BlockException/Throwable",否则不生效且报错。
  • 规则只存内存,重启丢失:生产必须接 Nacos/ZK/Apollo 做规则持久化(DynamicRulePublisher/DynamicRuleSource),否则重启即"裸奔"。
  • 热点参数未设例外项:对 VIP 用户误伤,应配置 ParamFlowItem 例外项(如某 userId 阈值放宽)。

六、热点参数与集群流控 ​

  • 热点参数限流(ParamFlowRule):对 @SentinelResource 方法的某个参数(如 userId/skuId)单独限流,配合 ParamFlowItem 对特定参数值设例外阈值。底层用滑动窗口 + 参数维度的 LRU 统计(只统计 Top N 热点参数,避免内存爆炸)。
  • 集群流控(ClusterFlowConfig):单机限流在集群多实例下会"各限各的",总阈值不可控。Sentinel 引入 Token Server(令牌服务器) 模式:各实例向 Token Server 申请令牌,由 Server 做全局配额(ClusterStrategy)。Token Server 可独立部署或 embed 在某一节点(需指定 flowId 与 namespace)。

七、生产落地 ​

  • 接入 Dashboard 统一管控,规则持久化到 Nacos,变更经评审。
  • 核心接口配置"限流 + 熔断 + 系统保护"三层防护;流控优先 WARM_UP(冷启动)与 RATE_LIMITER(削峰)。
  • 监控 pass/block/rt/exception 指标(Sentinel 暴露到 Micrometer/Prometheus),设容量告警。

📚 官方文档与参考资料 ​

✏️ 练习与自测 ​

  1. 为下单接口设计"QPS 限流 200 + 异常比例熔断 50%"组合规则,画出触发逻辑与 DegradeSlot 的判断依据。
  2. 用 @SentinelResource 写一个有 blockHandler 与 fallback 的示例,区分两者触发时机(BlockException vs Throwable)。
  3. 解释 LeapArray 滑动窗口相比固定窗口限流精度优势,并画出窗口环形复用结构。
  4. 如何用集群流控保证 10 个实例的总 QPS 不超过 2000?说明 Token Server 的角色。

本节小结

Sentinel 用"资源定义 + LeapArray 滑动窗口实时统计"支撑限流、熔断、热点、系统保护;ProcessorSlot 责任链把各种保护串成可扩展管线(StatisticSlot 沉淀数据,FlowSlot/DegradeSlot 决策);熔断用 closed/open/half-open 状态机做故障隔离与自愈。落地三件事:限流防过载、熔断防雪崩、规则持久化防重启丢失,配合 Dashboard 实现可视化治理。