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) { | 
本文转载自: 掘金