slot概述
在 Sentinel 里面,所有的资源都对应一个资源名称(resourceName
),每次资源调用都会创建一个 Entry
对象。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 SphU
API 显式创建。Entry 创建的时候,同时也会创建一系列功能插槽(slot chain),这些插槽有不同的职责,例如:
NodeSelectorSlot
负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;ClusterBuilderSlot
则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;StatisticSlot
则用于记录、统计不同纬度的 runtime 指标监控信息;FlowSlot
则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;AuthoritySlot
则根据配置的黑白名单和调用来源信息,来做黑白名单控制;DegradeSlot
则通过统计信息以及预设的规则,来做熔断降级;SystemSlot
则通过系统的状态,例如 load1 等,来控制总的入口流量;
下面是关系结构图
solt的基本逻辑及代码演示
每个Slot执行完业务逻辑处理后,会调用fireEntry()
方法,该方法将会触发下一个节点的entry
方法,下一个节点又会调用他的fireEntry
,以此类推直到最后一个Slot
,由此就形成了sentinel
的责任链。
- 工作流概述:
下面我会根据slot 的基本实现processorSlot
讲一下slot 的基本结构及用法
- 先看看顶层接口ProcessorSlot
1 | java复制代码public interface ProcessorSlot<T> { |
这个接口有4个方法,entry,fireEntry,exit,fireExit
- ProcessorSlot 的抽象实现 AbstractLinkedProcessorSlot
1 | java复制代码public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSlot<T> { |
+ **DefaultProcessorSlotChain实现了上述的chain(setNext和getNext)**
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
java复制代码public class DefaultProcessorSlotChain extends ProcessorSlotChain {
//直接实现了AbstractLinkedProcessorSlot的实例并作为first,可以理解为当前slot
AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {
@Override
public void entry(... )
throws Throwable {
super.fireEntry(context, resourceWrapper, t, count, prioritized, args);
}
@Override
public void exit(... ) {
super.fireExit(context, resourceWrapper, count, args);
}
};
//默认的end(可以理解为当前的后一个slot)
AbstractLinkedProcessorSlot<?> end = first;
@Override
public void addFirst(AbstractLinkedProcessorSlot<?> protocolProcessor) {
protocolProcessor.setNext(first.getNext());
first.setNext(protocolProcessor);
//如果当前为最后一个
if (end == first) {
end = protocolProcessor;
}
}
@Override
public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
//将后一个slot放进当前slot的next
end.setNext(protocolProcessor);
//将end指向后一个slot
end = protocolProcessor;
}
}
- AbstractLinkedProcessorSlot 的实例 DemoSlot :
1 | java复制代码public class DemoSlot extends AbstractLinkedProcessorSlot<DefaultNode> { |
到这里我们看完了Slot
的基本执行过程,总结一下:
- 1.初始化
first
和end
的slot
, - 2.开始执行
entry
- 3.开始执行
fireEntry
并查询是否下一个slot
,如果有则执行第2步 - 4.开始执行
exit
- 5.开始执行
fireExit
并查询是否有下一个slot
,如果有则执行第4步 - 6.结束
我们使用Slot
方式进行处理时,需要实现一个类似tomcat 的lifeCycle,但是差异是tomcat
的lifeCycle
是一个使用异步事件的方式执行容器内逻辑,而sentinel
使用的是一种子父依赖关系的链式调用,强调了顺序性执行。
默认的各个插槽之间的顺序是固定的,因为有的插槽需要依赖其他的插槽计算出来的结果才能进行工作。
下面我们看看是如何保证顺序的
–
SLOT的加载
1.定义顺序
sentinel
在每个实例化的slot
上面备注了顺序的参数,如
1 | java复制代码@SpiOrder(-10000) |
这是一个自定义的注解,保存的内容主要就是上面的(-10000)作为顺序权重
2.SPI加载
默认的chain
会调用sentinel
的类加载工具SpiLoader
的loadPrototypeInstanceListSorted(ProcessorSlot.class)
;
这个方法会将所有实现了ProcessorSlot
的类,用SPI的方式加载
1 | java复制代码@SpiOrder(-10000) |
3.加载完后排序
1 | java复制代码 public static <T> List<T> loadPrototypeInstanceListSorted(Class<T> clazz) { |
本文转载自: 掘金