概述

解析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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class DefaultSlotChainBuilder implements SlotChainBuilder {

@Override
public ProcessorSlotChain build() {
ProcessorSlotChain chain = new DefaultProcessorSlotChain();
chain.addLast(new NodeSelectorSlot());
chain.addLast(new ClusterBuilderSlot());
chain.addLast(new LogSlot());
chain.addLast(new StatisticSlot());
chain.addLast(new SystemSlot());
chain.addLast(new AuthoritySlot());
chain.addLast(new FlowSlot());
chain.addLast(new DegradeSlot());

return chain;
}
}

可以发现默认实现是 DefaultProcessorSlotChain。

插槽链 ProcessorSlotChain

ProcessorSlotChain 类的功能只是定义链表的添加头结点和尾节点的方法

1
2
3
4
5
6
public 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
34
public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSlot<T> {

private AbstractLinkedProcessorSlot<?> next = null;

@Override
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);
}
}

@SuppressWarnings("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);
}

@Override
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
12
public 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
60
public class DefaultProcessorSlotChain extends ProcessorSlotChain {

AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {

@Override
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);
}

@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
super.fireExit(context, resourceWrapper, count, args);
}

};
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) {
end.setNext(protocolProcessor);
end = protocolProcessor;
}

/**
* Same as {@link #addLast(AbstractLinkedProcessorSlot)}.
*
* @param next processor to be added.
*/
@Override
public void setNext(AbstractLinkedProcessorSlot<?> next) {
addLast(next);
}

@Override
public AbstractLinkedProcessorSlot<?> getNext() {
return first.getNext();
}

@Override
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);
}

@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
first.exit(context, resourceWrapper, count, args);
}

}