Alibaba Sentinel 的核心实现类 CtSph(Core Template Sph),它是 Sph 接口的默认实现,负责执行资源保护的核心逻辑:创建 Entry、构建 Slot 链、触发规则校验、处理异常等。
我们从 设计目标、关键机制、核心流程、重要细节 四个维度来深入理解:
一、整体定位
CtSph是 Sentinel 的"执行引擎"。- 它实现了
Sph接口中所有entry(...)和asyncEntry(...)方法。 - 每次调用
SphU.entry("xxx"),最终都会委托给CtSph的某个entry(...)方法。
🧠 类比:如果把 Sentinel 比作一个安检系统,
CtSph就是那个站在入口、检查每个人(请求)是否符合规则的安检员。
二、关键机制解析
1. Slot Chain 缓存机制(核心性能优化)
java
private static volatile Map<ResourceWrapper, ProcessorSlotChain> chainMap = new HashMap<>();
- 每个唯一的资源(
ResourceWrapper)对应一条ProcessorSlotChain。 ResourceWrapper包含:资源名、类型(String/Method)、流量方向(IN/OUT)、资源分类(resourceType)。- 全局共享 :无论在哪个
Context中访问同一个资源,都复用同一条 Slot 链。 - 懒加载 + 线程安全:通过双重检查锁(DCL) + 不可变 Map 更新(copy-on-write)保证线程安全。
- 容量限制 :最多缓存
Constants.MAX_SLOT_CHAIN_SIZE(默认 6000)条链,超限后不再做规则检查(直接放行)。
✅ 目的:避免重复构建 Slot 链,提升性能;同时防止内存爆炸。
2. Context 管理
java
Context context = ContextUtil.getContext();
if (context == null) {
context = InternalContextUtil.internalEnter(Constants.CONTEXT_DEFAULT_NAME);
}
- Sentinel 使用
Context表示一次调用链路(类似 TraceID)。 - 如果当前线程没有
Context,会自动创建一个默认上下文(sentinel_default_context)。 NullContext表示上下文数量已达上限(防 OOM),此时跳过所有规则检查。
⚠️ 注意:
InternalContextUtil绕过了正常的上下文名称校验(仅内部使用)。
3. 全局开关控制
java
if (!Constants.ON) {
return new CtEntry(...); // 不走 Slot 链,直接放行
}
- 可通过
SentinelConfig.setConfig(SentinelConfig.FEATURE_DISABLE_ALL, "true")关闭 Sentinel 全局功能。 - 用于紧急降级或调试。
4. Entry 生命周期管理
- 同步 Entry :返回
CtEntry,需调用.exit()(通常用 try-with-resources)。 - 异步 Entry :返回
AsyncEntry,需手动调用.exit()或在回调中完成。 - 异常处理 :
- 若
chain.entry(...)抛出BlockException,立即调用entry.exit()清理资源,再抛出异常。 - 若抛出其他异常(如 Sentinel 内部 bug),记录日志但不中断流程。
- 若
5. 异步支持特殊处理
java
asyncEntry.initAsyncContext();
asyncEntry.cleanCurrentEntryInLocal();
- 异步任务不应阻塞当前线程的上下文。
- 创建
AsyncEntry后,立即将其从当前线程的Context中移除(cleanCurrentEntryInLocal())。 - 异步任务完成后,需手动调用
asyncEntry.exit()。
三、核心流程(以 entry(String name, ...) 为例)
-
封装资源
javaStringResourceWrapper resource = new StringResourceWrapper(name, type, resourceType); -
获取上下文
- 无 Context → 创建默认 Context
- NullContext 或全局关闭 → 跳过规则检查
-
获取 Slot 链
- 从
chainMap缓存中取 - 不存在 → 加锁创建新链(
SlotChainProvider.newSlotChain()) - 超过最大数量 → 返回 null(跳过规则)
- 从
-
创建 Entry 对象
javaEntry e = new CtEntry(resource, chain, context, count, args); -
执行 Slot 链
javachain.entry(context, resource, null, count, prioritized, args);- 依次经过:NodeSelectorSlot → ClusterBuilderSlot → StatisticSlot → FlowSlot → DegradeSlot → SystemSlot ...
- 任一 Slot 触发
BlockException,立即退出并清理
-
返回 Entry
- 业务代码需在 finally 或 try-with-resources 中调用
e.exit()
- 业务代码需在 finally 或 try-with-resources 中调用
四、重要设计细节
| 特性 | 说明 |
|---|---|
| ResourceWrapper 作为 key | 基于 equals() 和 hashCode(),确保相同资源复用 Slot 链 |
| Copy-on-write 更新 chainMap | 避免加锁读,写时复制整个 Map,适合读多写少场景 |
| EntryType 决定 SystemRule 生效范围 | 只有 EntryType.IN 会被系统保护规则拦截 |
| args 支持热点参数限流 | 传递给 ParameterFlowSlot 进行细粒度控制 |
| prioritized 支持优先级流量 | 高优请求可突破部分流控限制(需规则配置) |
五、典型调用链示例
java
// 用户代码
try (Entry entry = SphU.entry("orderService", EntryType.IN, 1, userId)) {
// do business
} catch (BlockException ex) {
// fallback
}
内部执行路径:
SphU.entry()
→ Env.sph.entry() // 即 CtSph.entry()
→ new StringResourceWrapper(...)
→ ContextUtil.getContext()
→ lookProcessChain(resource)
→ SlotChainProvider.newSlotChain() // 首次调用时
→ new CtEntry(...)
→ chain.entry(...) // 执行所有 Slot
→ FlowSlot.checkFlow()
→ DegradeSlot.checkDegrade()
→ SystemSlot.checkSystem()
→ return entry
六、总结
CtSph 是 Sentinel 的核心调度器,它:
- 统一入口:所有资源保护请求都经过它;
- 高效复用 :通过
ResourceWrapper缓存 Slot 链; - 安全退出:确保 Entry 被正确清理;
- 灵活扩展:支持同步/异步、优先级、参数化、资源分类;
- 容错设计:全局开关、上下文限制、Slot 链数量限制,防止自身成为瓶颈。
💡 开发者须知:
- 不要手动创建
CtSph实例,应使用SphU工具类;- 必须保证
Entry.exit()被调用(推荐 try-with-resources);- 异步场景务必使用
AsyncEntry并手动管理生命周期。
理解 CtSph,就等于理解了 Sentinel 如何将"规则"作用到"每一次调用"上的核心机制。