WindowWrapLeapArrayArrayMetricSentinel(阿里巴巴开源的流量治理组件) 中用于实时指标统计的核心模块。这些类共同构成了 Sentinel 的“滑动窗口统计引擎”,为限流、熔断、系统保护等核心功能提供数据支撑。

下面我将从 作用、职责、协作关系 三个维度,帮你彻底理解这些类在 Sentinel 中的意义。


🧩 一、整体架构概览

+------------------+
|   ArrayMetric    | ← 对外暴露的统一指标接口(Metric)
+------------------+
         ↓
+------------------+      +----------------------+
|   LeapArray<T>   | ◄─── | BucketLeapArray / OccupiableBucketLeapArray |
+------------------+      +----------------------+
         ↓
+------------------+      +------------------+
| WindowWrap<T>    | ◄─── | MetricBucket     |
+------------------+      +------------------+
  • WindowWrap<T>:时间窗口的包装器(包含起始时间 + 数据)
  • MetricBucket:具体统计数据容器(pass/block/rt 等)
  • LeapArray<T>:滑动窗口数组(环形 buffer + 时间淘汰逻辑)
  • BucketLeapArrayLeapArray<MetricBucket> 的具体实现
  • ArrayMetric:对外提供的 Metric 接口实现,封装了统计操作

💡 一句话总结
ArrayMetric 是用户(如 FlowSlot)使用的“统计 API”;
它内部用 LeapArray 管理多个 WindowWrap<MetricBucket>,每个 bucket 记录一小段时间内的请求指标。


📦 二、逐个类详解

1. WindowWrap<T>

作用:代表一个固定时间长度的统计窗口(bucket)

  • 字段

    • windowStart: 窗口开始时间(如 1000ms)
    • windowLengthInMs: 窗口长度(如 100ms)
    • value: 实际统计数据(如 MetricBucket
  • 关键方法

    • isTimeInWindow(time): 判断某时间是否属于此窗口
    • resetTo(startTime): 重置窗口起始时间(用于复用旧 bucket)

设计意义:解耦“时间信息”和“统计数据”,便于复用和滑动。


2. MetricBucket

作用具体的指标计数器,记录各类事件数量

  • 内部结构

    private final LongAdder[] counters; // 按 MetricEvent 类型索引
    private volatile long minRt;        // 最小响应时间
    
  • 支持的事件类型(MetricEvent

    • PASS:通过的请求
    • BLOCK:被限流拒绝的请求
    • EXCEPTION:异常请求数
    • RT:总响应时间(用于算平均 RT)
    • SUCCESS:成功完成的请求
    • OCCUPIED_PASS:预占(排队等待)的请求(用于“匀速排队”模式)
  • 线程安全:使用 LongAdder(高性能并发计数器)

设计意义:一个 bucket 就是一个“迷你仪表盘”,记录 100ms 内所有关键指标。


3. LeapArray<T>

作用滑动窗口的核心容器,管理多个 WindowWrap<T>

  • 核心机制

    • 环形数组(AtomicReferenceArray<WindowWrap<T>>
    • 时间对齐:windowStart = time - time % windowLength
    • 按需创建/重置 bucket(CAS + 低频锁)
    • 自动淘汰过期 bucket(isWindowDeprecated()
  • 抽象方法

    • newEmptyBucket(): 创建空数据
    • resetWindowTo(): 重置过期 bucket

设计意义:高效、并发安全地维护一个“滚动时间窗口”,避免内存爆炸。


4. BucketLeapArray(继承 LeapArray<MetricBucket>

作用:为 Sentinel 提供标准的 QPS 统计能力

  • 实现了抽象方法:
    • newEmptyBucket()new MetricBucket()
    • resetWindowTo() → 重置时间 + 清零计数器

这是 Sentinel 默认使用的滑动窗口实现

🔸 补充:还有 OccupiableBucketLeapArray(支持“请求排队”场景),但你贴的是基础版。


5. ArrayMetric implements Metric

作用对外暴露的统计接口,业务层(如 StatisticSlot)直接使用它

  • 核心能力

    • 写入addPass(), addBlock(), addRT() → 更新当前 bucket
    • 读取
      • pass(): 返回最近 intervalInMs 内总通过数
      • block(): 总拒绝数
      • rt(): 总响应时间
      • minRt(): 最小响应时间
      • getAvg(MetricEvent.PASS): 平均 QPS(= 总 pass / 时间秒数)
  • 内部委托

    • 所有操作都通过 data.currentWindow() 获取当前 bucket
    • 聚合统计时调用 data.values() 获取所有有效 bucket

设计意义:隐藏底层滑动窗口细节,提供简洁、统一的指标 API。


🔗 三、它们如何协作?—— 以一次请求为例

假设一个请求通过了 Sentinel 的校验(未被限流):

  1. StatisticSlot 调用

    metric.addPass(1);
    metric.addRT(requestRt);
    
  2. ArrayMetric.addPass()

    • 调用 data.currentWindow() → 获取当前时间对应的 WindowWrap<MetricBucket>
    • 调用 wrap.value().addPass(1)
  3. LeapArray.currentWindow()

    • 计算当前时间属于哪个 bucket(索引 + 起始时间)
    • 如果 bucket 不存在 → CAS 创建
    • 如果 bucket 过期 → 加锁重置
    • 返回有效 bucket
  4. MetricBucket.addPass()

    • counters[PASS.ordinal()].add(1) → 原子递增
  5. 后续限流判断(如 QPS > 阈值)

    • 调用 metric.pass() → 遍历所有有效 bucket,累加 pass()
    • 得到最近 1 秒总通过数 → 与阈值比较

🎯 四、为什么这样设计?

设计点目的
滑动窗口 + 环形数组高效利用内存,避免频繁 GC
按时间对齐 bucket精确控制统计粒度(如 100ms)
CAS + 低频锁高并发下性能优异(写多读少场景)
LongAdderAtomicLong 更高的并发写性能
抽象 LeapArray支持不同统计策略(如普通 bucket / 可占用 bucket)
Metric 接口封装解耦统计逻辑与业务逻辑

🧠 五、总结:它们在 Sentinel 中的角色

角色类比
WindowWrap<T>时间窗口的“信封”信封(写明时间段)
MetricBucket指标的“记分牌”记分牌(pass=5, block=2)
LeapArray<T>滑动窗口的“转盘”转盘(10 个格子循环使用)
BucketLeapArray标准转盘实现标准记分转盘
ArrayMetric对外的“统计员”统计员(你问他“最近1秒多少QPS?”,他去转盘上加总)

最终目标
在高并发下,以极低开销,实时、准确地回答:“过去 N 秒内,这个接口的 QPS/错误率/RT 是多少?”
这就是 Sentinel 实现智能限流、熔断的基础!


如果你继续深入 Sentinel,会发现:

  • 每个 Resource(资源)都有自己的 ArrayMetric
  • FlowRuleChecker 依赖 metric.pass() 做 QPS 限流
  • DegradeSlot 依赖 metric.rt()exception() 做熔断

这些类虽小,却是 Sentinel 实时感知系统状态的“眼睛”和“大脑”

更多推荐