Sentinel源码二:ProcessorSlotChain
概述
解析Entry源码中涉及到了ProcessorSlotChain,这篇对插槽链作一个解析.
解析
默认构造过程:
- com.alibaba.csp.sentinel.SphU#entry -> com.alibaba.csp.sentinel.CtSph#entryWithPriority
- com.alibaba.csp.sentinel.CtSph#lookProcessChain -> com.alibaba.csp.sentinel.slotchain.SlotChainProvider#newSlotChain
- com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder#build
这里使用了建造者模式 DefaultSlotChainBuilder
ProcessorSlotChain类中保存了一个 ProcessorSlot 链,通过这个 ProcessorSlot 链来实现责任链模式。
- NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;
- ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;
- StatisticSlot 则用于记录、统计不同纬度的 runtime 指标监控信息;
- FlowSlot 则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;
- AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
- DegradeSlot 则通过统计信息以及预设的规则,来做熔断降级;
- SystemSlot 则通过系统的状态,例如 load1 等,来控制总的入口流量;

Sentinel 将 SlotChainBuilder 作为 SPI 接口进行扩展,使得 Slot Chain 具备了扩展的能力。您可以自行加入自定义的 slot 并编排 slot 间的顺序,从而可以给 Sentinel 添加自定义的功能。

1 | public class DefaultSlotChainBuilder implements SlotChainBuilder { |
可以发现默认实现是 DefaultProcessorSlotChain。
插槽链 ProcessorSlotChain
ProcessorSlotChain 类的功能只是定义链表的添加头结点和尾节点的方法1
2
3
4
5
6public abstract class ProcessorSlotChain extends AbstractLinkedProcessorSlot<Object> {
public abstract void addFirst(AbstractLinkedProcessorSlot<?> protocolProcessor);
public abstract void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor);
}
插槽抽象类 AbstractLinkedProcessorSlot
AbstractLinkedProcessorSlot 使得 ProcessorSlot 通过存储下一个节点(next)成为一个链表结构
在ProcessorSlot执行完entry后会执行fireEntry 方法,此时会执行next的entry方法,产生传递。
同样执行完exit方法后会执行fireExit方法,传递给next处理。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
34public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSlot<T> {
private AbstractLinkedProcessorSlot<?> next = null;
public void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)
throws Throwable {
if (next != null) {
next.transformEntry(context, resourceWrapper, obj, count, prioritized, args);
}
}
("unchecked")
void transformEntry(Context context, ResourceWrapper resourceWrapper, Object o, int count, boolean prioritized, Object... args)
throws Throwable {
T t = (T)o;
entry(context, resourceWrapper, t, count, prioritized, args);
}
public void fireExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
if (next != null) {
next.exit(context, resourceWrapper, count, args);
}
}
public AbstractLinkedProcessorSlot<?> getNext() {
return next;
}
public void setNext(AbstractLinkedProcessorSlot<?> next) {
this.next = next;
}
}
插槽接口 ProcessorSlot
ProcessorSlot 定义了进入和退出的入口方法。1
2
3
4
5
6
7
8
9
10
11
12public interface ProcessorSlot<T> {
void entry(Context context, ResourceWrapper resourceWrapper, T param, int count, boolean prioritized,
Object... args) throws Throwable;
void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized,
Object... args) throws Throwable;
void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args);
void fireExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args);
}
插槽链默认实现 DefaultProcessorSlotChain
类图

DefaultProcessorSlotChain 中维护了一个插槽链,first 和 end 代表头结点和尾节点
在执行 DefaultProcessorSlotChain 的 exit 或者 entry 方法都会传递给头结点(first)。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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60public class DefaultProcessorSlotChain extends ProcessorSlotChain {
AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {
public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args)
throws Throwable {
super.fireEntry(context, resourceWrapper, t, count, prioritized, args);
}
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
super.fireExit(context, resourceWrapper, count, args);
}
};
AbstractLinkedProcessorSlot<?> end = first;
public void addFirst(AbstractLinkedProcessorSlot<?> protocolProcessor) {
protocolProcessor.setNext(first.getNext());
first.setNext(protocolProcessor);
if (end == first) {
end = protocolProcessor;
}
}
public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
end.setNext(protocolProcessor);
end = protocolProcessor;
}
/**
* Same as {@link #addLast(AbstractLinkedProcessorSlot)}.
*
* @param next processor to be added.
*/
public void setNext(AbstractLinkedProcessorSlot<?> next) {
addLast(next);
}
public AbstractLinkedProcessorSlot<?> getNext() {
return first.getNext();
}
public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args)
throws Throwable {
first.transformEntry(context, resourceWrapper, t, count, prioritized, args);
}
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
first.exit(context, resourceWrapper, count, args);
}
}