StatisticSlot是 Sentinel(阿里巴巴开源的流量治理组件) 中的核心类之一。它的作用是在请求进入和退出 Sentinel 保护的资源时,统计实时指标(如 QPS、线程数、响应时间、异常数等)。
下面我们将从 设计目的、关键逻辑、问题修复(Issue #2374)、整体流程 四个维度来深入理解它。
一、设计目的:做什么?
StatisticSlot 是一个 统计型 Slot(插槽),属于 Sentinel 责任链(Slot Chain)中的一环。
它的核心职责是:
✅ 在 entry(进入)时:
- 如果请求通过(未被限流/熔断),则增加 线程数 + 成功请求数;
- 如果被阻塞(BlockException),则增加 拒绝计数;
- 如果发生内部错误,记录异常。
✅ 在 exit(退出)时:
- 计算 响应时间(RT);
- 减少 当前线程数;
- 增加 成功完成计数 或 异常计数;
- 触发 exit 回调。
📌 它统计的对象包括:
DefaultNode:当前上下文(Context)下该资源的统计;OriginNode:按调用来源(origin)区分的统计;ClusterNode/Constants.ENTRY_NODE:全局入口总览统计。
二、关键方法解析
1. entry() 方法 ------ 请求进入时
java
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node,
int count, boolean prioritized, Object... args) throws Throwable
主要逻辑分支:
| 情况 | 处理 |
|---|---|
| 正常通过 | 调用 fireEntry()(继续责任链)→ 增加线程数、成功数 |
| PriorityWaitException | 特殊等待场景(如匀速排队),仍视为"通过",增加线程数 |
| BlockException | 被限流/熔断 → 记录 block QPS,触发 onBlocked 回调,抛出异常 |
| 其他 Throwable | 记录 error,向上抛出 |
🔍 注意:只有 未被 block 的请求 才会走到
exit()方法。
2. exit() 方法 ------ 请求退出时
java
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args)
核心步骤:
-
只处理非 block 请求(因为 block 的请求不会执行业务逻辑,也就不需要 exit):
javaif (context.getCurEntry().getBlockError() == null) { ... } -
计算响应时间 RT:
javalong rt = completeStatTime - context.getCurEntry().getCreateTimestamp(); -
调用
recordCompleteFor()更新指标:- 增加 RT 和成功数;
- 减少线程数(
decreaseThreadNum()); - 如果有非 Block 异常,增加异常 QPS。
-
触发 exit 回调:
javafor (ProcessorSlotExitCallback handler : exitCallbacks) { handler.onExit(context, resourceWrapper, count, args); } -
关键修复:传递
args给下一个 slot:javafireExit(context, resourceWrapper, count, args); // ← 修复点
三、重点:Issue #2374 的修复
❓ 问题是什么?
在旧版本中,exit() 方法最后一行是:
java
fireExit(context, resourceWrapper, count); // ❌ 没传 args
但 fireExit 的签名是:
java
protected void fireExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args)
丢失了 args 参数!
⚠️ 后果
- 后续的 Slot(比如自定义的监控、日志、审计 Slot)在
exit阶段无法获取原始调用参数(如用户 ID、订单号等); - 导致基于
args的回调逻辑失效。
✅ 修复方式
将:
java
fireExit(context, resourceWrapper, count);
改为:
java
fireExit(context, resourceWrapper, count, args); // ✔️ 传递 args
🔗 GitHub Issue: Param args missing in fireExit of StatisticSlot #2374
🔗 PR: #2523
这是一个典型的 参数透传遗漏 bug,虽然不影响主流程,但破坏了扩展性。
四、整体流程图解
[请求进入]
↓
StatisticSlot.entry()
├──→ fireEntry() → 下一个 Slot(如 FlowSlot)
│ ↓
│ [业务逻辑执行]
│ ↓
└──← exit() 被调用
↓
if (!blocked) {
计算 RT
更新 DefaultNode / OriginNode / ENTRY_NODE 的指标
}
↓
触发所有 ProcessorSlotExitCallback.onExit(...)
↓
fireExit(...) → 通知责任链中后续的 Slot 执行 exit 逻辑
💡
fireEntry和fireExit是AbstractLinkedProcessorSlot提供的方法,用于 将请求传递给责任链中的下一个 Slot。
五、为什么需要统计这些指标?
Sentinel 的核心能力(限流、熔断、系统保护)都依赖于 实时指标数据:
| 指标 | 用途 |
|---|---|
threadNum |
线程隔离、系统负载保护 |
passQps |
成功率、流量趋势 |
blockQps |
限流效果评估 |
rt |
响应时间监控、慢调用比例熔断 |
exceptionQps |
异常比例熔断 |
StatisticSlot 就是这些数据的 采集器。
六、总结
StatisticSlot 是 Sentinel 中 默默无闻但至关重要 的组件:
- 它不参与决策(如是否限流),只负责 收集数据;
- 它保证了每个资源在不同维度(全局、来源、上下文)下的指标一致性;
- 它通过 回调机制 支持扩展(如自定义监控上报);
- 它的
args透传修复(#2374)体现了 对扩展性细节的重视。
🧠 理解建议:
- 结合
FlowSlot(限流)、DegradeSlot(熔断)一起看,理解"统计 → 决策 → 执行"闭环;- 尝试注册一个
ProcessorSlotExitCallback,打印args,验证参数是否正确传递。
如果你正在使用 Sentinel 做自定义监控、审计或埋点,确保你的 onExit 回调能拿到 args ------ 这正是这个修复的价值所在。