
线上跑了半年的Sentinel限流规则突然不生效?加了降级配置请求还是被打满?90%的问题都出在你没搞懂ProcessorSlotChain的执行逻辑,本文从源码层扒透责任链设计,让你从此排查Sentinel问题效率提升10倍。
一、先搞懂:ProcessorSlotChain到底是Sentinel的核心骨架
Sentinel所有的限流、降级、权限校验能力,本质上都是靠责任链模式串起来的一个个处理器完成的,ProcessorSlotChain就是承载所有能力的核心执行骨架。
首先我们看核心类结构,ProcessorSlotChain本身继承了AbstractLinkedProcessorSlot,内部维护了一个双向链表结构,支持在头部或尾部插入Slot处理器:
// 核心责任链抽象类
public abstract class ProcessorSlotChain extends AbstractLinkedProcessorSlot<Object> {
// 在链头部插入处理器
public abstract void addFirst(ProcessorSlot<?> protocolProcessor);
// 在链尾部插入处理器
public abstract void addLast(ProcessorSlot<?> protocolProcessor);
}
责任链的加载逻辑完全基于SPI实现,默认的DefaultSlotChainBuilder会加载classpath下META-INF/services目录中配置的所有ProcessorSlot实现类,并且按照@Order注解的值从小到大排序后插入链表:
// SPI加载Slot核心实现
public class DefaultSlotChainBuilder implements SlotChainBuilder {
@Override
public ProcessorSlotChain build() {
ProcessorSlotChain chain = new DefaultProcessorSlotChain();
// 加载所有SPI配置的ProcessorSlot并按Order排序
List<ProcessorSlot> sortedSlotList = SpiLoader.of(ProcessorSlot.class)
.loadInstanceListSorted();
for (ProcessorSlot slot : sortedSlotList) {
chain.addLast(slot);
}
return chain;
}
}
这里要注意一个核心点:@Order值越小,Slot的执行优先级越高,官方默认的Slot顺序就是严格按照执行依赖关系排序的,一旦顺序被打乱就会出现规则不生效的问题。
二、逐行拆解:责任链全流程执行逻辑
整个Sentinel的请求处理流程可以完全对应下面的UML流程图,每个Slot各司其职,只要有一个Slot校验不通过,整个请求就会被直接拦截:

我们逐个拆解核心Slot的作用:
1. NodeSelectorSlot:负责维护资源的调用路径,将同一个资源的不同调用链路分开统计,是链路流控的核心基础
2. ClusterBuilderSlot:负责构建集群维度的统计节点,存储资源的集群QPS、线程数、响应时间等核心指标
3. LogSlot:负责记录所有规则校验不通过的异常日志,方便后续排查问题
4. StatisticSlot:是整个统计体系的核心,负责在请求通过、被拦截、抛出异常的时候更新对应的统计指标,后续所有规则校验都依赖这里统计的数据
5. AuthoritySlot:负责黑白名单权限校验,判断请求来源是否允许访问当前资源
6. SystemSlot:负责系统级别的流控,校验当前系统的CPU、负载、平均响应时间等指标是否超过阈值
7. ParamFlowSlot:负责热点参数限流,针对请求中的特定参数做更细粒度的流控
8. FlowSlot:核心的流量控制校验,根据配置的限流规则判断当前请求是否允许通过
9. DegradeSlot:核心的降级熔断校验,根据慢调用比例、异常比例等规则判断是否需要熔断当前资源
我们看FlowSlot的核心校验逻辑代码:
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
boolean prioritized, Object... args) throws Throwable {
// 调用流控规则校验逻辑
checkFlow(resourceWrapper, context, node, count, prioritized);
// 校验通过 传递给下一个Slot
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
void checkFlow(ResourceWrapper resource, Context context, DefaultNode node, int count, boolean prioritized)
throws BlockException {
// 获取当前资源配置的所有流控规则
List<FlowRule> rules = FlowRuleManager.getRulesForResource(resource.getName());
if (rules == null || rules.isEmpty()) {
return;
}
for (FlowRule rule : rules) {
// 逐个校验规则 只要有一个不通过就抛出FlowException
if (!ruleChecker.canPass(rule, context, node, count, prioritized)) {
throw new FlowException(rule.getLimitApp(), rule);
}
}
}
这里可以看到,只要有一个规则校验不通过,就会直接抛出异常,不会走到后续的Slot和业务逻辑。
三、踩坑必看:90%的规则失效问题都是这些原因
- 自定义Slot顺序配置错误:很多同学自定义Slot的时候随便写@Order值,如果Order值比FlowSlot的Order(5000)还大,就会出现请求已经走到业务逻辑了才校验限流规则,完全不生效
- 禁用了核心统计Slot:如果禁用了StatisticSlot,所有的指标统计都会失效,后续的限流、降级规则因为没有统计数据完全不会触发
- 多上下文链路统计隔离:如果没有配置正确的上下文,同一个资源的不同链路统计会混在一起,导致链路流控不生效
好了今天的源码拆解就到这,是不是看完终于搞懂Sentinel为啥规则有时候莫名其妙不生效了?你们平时用Sentinel还踩过啥奇葩坑?评论区唠唠,我整理下下期出完整踩坑大全~
夜雨聆风