Sentinel 中 StatisticNode 类的实现,它是所有统计节点(如 DefaultNode、ClusterNode)的基类 ,负责 实时采集和管理资源的运行时指标(metrics)。
它的核心思想是:
用滑动窗口(Sliding Window)机制,在秒级和分钟级两个时间维度上,高效、准确地统计 QPS、RT、线程数等关键指标。
下面我们从 设计目标、核心结构、滑动窗口原理、指标计算逻辑、线程安全 等角度深入解析。
一、核心目标:统计什么?
StatisticNode 负责维护三类实时指标:
| 指标类型 | 存储方式 | 用途 |
|---|---|---|
| 秒级指标 | rollingCounterInSecond(默认 1 秒分 2 个桶 → 每桶 500ms) |
实时流控、熔断决策(响应快) |
| 分钟级指标 | rollingCounterInMinute(60 个桶,每桶 1 秒) |
监控展示、历史回溯、慢速规则 |
| 当前线程数 | curThreadNum(LongAdder) |
并发控制(如系统保护规则) |
✅ 所有指标都基于 滑动窗口(Sliding Window) 实现,底层由
ArrayMetric+LeapArray支撑。
二、滑动窗口原理(关键!)
Sentinel 的滑动窗口不是"固定窗口"(如 0-1s, 1-2s),而是连续、重叠、滚动的窗口,能更平滑地反映流量变化。
📌 以秒级窗口为例(默认配置):
-
总窗口长度:1000ms(1秒)
-
桶数量(sampleCount):2
-
每个桶长度:500ms
时间轴: ... |-----500ms-----|-----500ms-----| → 当前窗口 [t-1000, t)
↑
当前时间 t -
每次请求进来,会找到对应的时间桶(bucket),累加指标(pass、block、rt 等)。
-
超过 1000ms 的旧桶会被自动丢弃(逻辑上"滑出"窗口)。
✅ 优势:
- 避免固定窗口的"边界突刺"问题(如 0.9s 到 1.1s 瞬间 QPS 翻倍)
- 实时性高,适合做毫秒级流控
三、关键字段详解
java
// 秒级滑动窗口(默认:2个桶,总长1000ms)
private transient volatile Metric rollingCounterInSecond =
new ArrayMetric(SampleCountProperty.SAMPLE_COUNT, IntervalProperty.INTERVAL);
// 分钟级滑动窗口(60个桶,每桶1秒,总长60秒)
private transient Metric rollingCounterInMinute =
new ArrayMetric(60, 60 * 1000, false);
// 当前线程并发数(使用 LongAdder 高性能计数)
private LongAdder curThreadNum = new LongAdder();
💡
transient表示不参与序列化(这些是运行时状态,无需持久化)
四、指标如何计算?------ 以 QPS 为例
1. passQps()(秒级通过 QPS)
java
return rollingCounterInSecond.pass() / rollingCounterInSecond.getWindowIntervalInSec();
pass():返回当前滑动窗口内所有有效桶的 总通过请求数getWindowIntervalInSec():窗口总时长(单位:秒),如 1.0- 结果 = 总通过数 / 1秒 → 即 QPS
2. avgRt()(平均响应时间)
java
long successCount = rollingCounterInSecond.success();
if (successCount == 0) return 0;
return rollingCounterInSecond.rt() / successCount;
rt():窗口内所有成功请求的 总响应时间(毫秒)- 除以成功次数 → 平均 RT
3. totalRequest()(最近1分钟总请求数)
java
return rollingCounterInMinute.pass() + rollingCounterInMinute.block();
- 使用 分钟级窗口,用于监控大盘数据
🔁 所有写操作(如
addPassRequest)都会同时更新 秒级 + 分钟级 两个窗口!
五、线程安全设计
- 滑动窗口(ArrayMetric/LeapArray):内部使用 CAS + 时间戳校验,保证多线程写入安全。
- curThreadNum :使用
LongAdder(比AtomicLong更高性能的并发计数器)。 - childList 更新(在 DefaultNode 中) :采用 不可变集合替换(copy-on-write) 策略,避免锁竞争。
六、高级功能:预占(Warm Up / 匀速排队)
tryOccupyNext(...) 方法支持 "匀速排队"或"预占令牌" 场景:
- 当 QPS 超过阈值时,不直接拒绝,而是看 未来某个时间窗口是否能容纳。
- 如果可以,返回需要等待的时间(ms),让请求 sleep 后再执行。
- 这是 Sentinel Rate Limiter 模式 的核心实现。
⚠️ 此功能常用于削峰填谷,避免突发流量打垮系统。
七、与整体架构的关系
DefaultNode和ClusterNode都继承StatisticNode,共享同一套统计逻辑。- 流控规则(FlowRule)在
FlowSlot中执行时,会调用node.passQps()获取当前 QPS。
八、总结:一句话理解 StatisticNode
StatisticNode是 Sentinel 的"指标心脏",它通过双时间尺度(秒/分)的滑动窗口,高效、准确、线程安全地采集资源的实时运行数据,为流控、熔断、系统保护等能力提供决策依据。
🧠 记住三个关键词:
- 滑动窗口(Sliding Window) → 平滑、实时
- 双时间尺度(Second + Minute) → 快速响应 + 历史回溯
- 指标同步更新(Local + Global) → 支持入口隔离与全局聚合
如果你在调试 Sentinel 或自定义规则,理解 StatisticNode 就等于掌握了它的"数据源头"。