一、核心目标:统计哪些运行时指标?
Sentinel 中的 StatisticNode 类是所有统计节点(如 ClusterNode、DefaultNode)的基类,承担着实时采集与管理资源性能数据的核心职责。其主要功能是通过滑动窗口机制,在秒级和分钟级两个时间粒度上精确记录 QPS、响应时间(RT)、并发线程数等关键运行指标。
| 指标类型 |
存储方式 |
用途说明 |
| 秒级指标 |
rollingCounterInSecond (默认每秒划分为 2 个桶,每个桶 500ms) |
用于实时流控与熔断判断,响应迅速 |
| 分钟级指标 |
rollingCounterInMinute (共 60 个桶,每桶 1 秒) |
适用于监控展示、历史数据分析及慢规则触发 |
| 当前线程数 |
curThreadNum (基于 LongAdder 实现) |
支持并发控制,例如系统保护策略中的并发限制 |
所有上述指标均基于滑动窗口(Sliding Window)实现,并由底层的 LeapArray 结构配合时间桶进行支撑
ArrayMetric
LeapArray
。
二、滑动窗口的工作原理(核心机制)
Sentinel 并未采用传统的“固定时间窗口”(如 0-1s、1-2s),而是设计了一种连续、重叠且动态滚动的时间窗口,从而更平滑地反映请求流量的变化趋势,避免因窗口切换导致的统计畸变。
以秒级滑动窗口为例(默认配置):
- 总窗口长度:1000ms(即 1 秒)
- 桶数量(sampleCount):2
- 每个桶时长:500ms
当有新请求进入时,系统会根据当前时间定位到对应的桶,并在该桶中累加相关指标(如通过数、阻塞数、响应时间等)。超出 1000ms 的旧桶将被逻辑淘汰,实现“滑出”效果
时间轴: ... |-----500ms-----|-----500ms-----| → 当前窗口 [t-1000, t)
↑
当前时间 t
。
优势分析:
- 有效缓解固定窗口在边界时刻可能出现的“突刺”问题(例如从 0.9s 到 1.1s 瞬间 QPS 虚高)
- 具备更高的实时性,适合毫秒级精度的限流决策
三、关键字段解析
// 秒级滑动窗口:使用2个桶,覆盖1秒时间范围
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 关键字表明这些字段不参与序列化过程
transient
,因为它们属于运行时状态信息,无需持久化保存。
四、指标计算逻辑详解 —— 以 QPS 和 RT 为例
1. 秒级通过 QPS 计算(passQps)
return rollingCounterInSecond.pass() / rollingCounterInSecond.getWindowIntervalInSec();
pass()
:获取当前滑动窗口内所有有效时间桶的累计通过请求数
getWindowIntervalInSec()
:返回窗口总时长(单位为秒,通常为 1.0)
- 最终结果 = 总通过请求数 ÷ 1秒 → 即当前 QPS 值
2. 平均响应时间(avgRt)
long successCount = rollingCounterInSecond.success();
if (successCount == 0) return 0;
return rollingCounterInSecond.rt() / successCount;
rt()
:表示窗口内所有成功请求的总响应耗时(单位:毫秒)
- 除以成功请求数量,得出平均 RT
3. 最近一分钟总请求数(totalRequest)
return rollingCounterInMinute.pass() + rollingCounterInMinute.block();
该值来源于分钟级滑动窗口,常用于全局监控大盘的数据汇总。
值得注意的是:每一次写操作(如请求通过或被拦截)
addPassRequest
,都会同步更新
秒级和分钟级两个维度的统计窗口,确保多粒度数据的一致性。
五、线程安全机制设计
- 滑动窗口(ArrayMetric / LeapArray):内部采用 CAS 操作结合时间戳校验机制,保障多线程环境下的安全写入。
- 并发线程计数(curThreadNum):使用
LongAdder LongAdder
替代传统 AtomicLong AtomicLong
,显著提升高并发场景下的计数性能。
- 子节点列表更新(如 DefaultNode 中的 childList):采用不可变集合的写时复制(copy-on-write)策略,避免锁竞争,提高读取效率。
六、高级特性:预占模式与速率控制
通过 wait() 方法可实现“匀速排队”或“预占令牌”机制
tryOccupyNext(...)
,具体流程如下:
- 当瞬时 QPS 超过设定阈值时,系统不会立即拒绝请求。
- 而是检查未来某个时间窗口是否具备容纳该请求的能力。
- 若可以容纳,则返回一个等待时间(单位:毫秒),要求调用方暂停指定时间后再执行。
这一机制构成了 Sentinel Rate Limiter 模式的核心逻辑,广泛应用于 Warm Up(冷启动)、匀速限流等场景,有效平抑突发流量。
StatisticNode
DefaultNode
ClusterNode
该功能通常被用来实现流量的削峰填谷,有效防止突发请求对系统造成过载冲击。
八、总结:一句话掌握核心
StatisticNode
StatisticNode
作为 Sentinel 的“指标心脏”,
StatisticNode
采用双时间尺度(秒级与分钟级)的滑动窗口机制,以高效、精准且线程安全的方式统计资源的实时运行状态,为流量控制、熔断降级以及系统自适应保护等功能提供关键的数据支撑。
牢记三个核心要点:
- 滑动窗口(Sliding Window) — 实现数据采集的平滑性和实时性
- 双时间尺度(Second + Minute) — 兼顾快速响应能力与历史数据回溯分析
- 指标同步更新(Local + Global) — 支持入口维度隔离与全局数据聚合
当你在调试 Sentinel 行为或开发自定义规则时,理解
StatisticNode
的工作原理,就等于抓住了整个系统的“数据源头”。
七、与整体架构的关联
SphU.entry("res")
↓
Context
↓
NodeSelectorSlot
↓
DefaultNode (extends StatisticNode)
↓
ClusterNode (extends StatisticNode)
↘ ↗
FlowSlot / DegradeSlot
↑
| 读取 QPS/RT/thread
|
DefaultNode
DefaultNode
和
ClusterNode
均继承自
StatisticNode
,共用同一套底层指标统计逻辑。当流控规则(FlowRule)在
FlowSlot
中生效时,会通过调用
node.passQps()
来获取当前的 QPS 数值。