【流量控制系列6】Sentinal 详细介绍-SlotChain源码解析

核心实现

责任链模式

责任链模式介绍-扩展链接

时序图

  • 限流功能-基于FlowSlot

图片

SoltChain源码解析

  • 类图

图片

  • SoltChain内部
1
2
3
4
5
6
7
8
9
10
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);
}
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

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;
}
}

AbstractLinkedProcessorSlot为一个Slot节点,通过setNext指定下一个Slot节点,通过 fireEntry()方法,调用下一个节点的transformEntry()最终调用到下一个Slot节点的entry方法,本身的结构类似于

1
2
3
clsss Slot {
Slot next;
}
  • ProcessorSlotChain和DefaultProcessorSlotChain
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);
}
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

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;
}


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

DefaultProcessorSlotChain实质是指定头节点FirstSlot和endSnot的链表。就如下面结构 :

1
2
3
4
public Class Chain{
Slot first;
Slot end;
}

com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilde

1
2
3
4
5
6
7
8
9
10
11
12
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;
}

结构图

图片

各个slot职责

  • NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;

  • ClusterBuilderSlot则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;

  • StatistcSlot 则用于记录,统计不同纬度的 runtime 信息;

  • SystemSlot 则通过系统的状态,例如 load1 等,来控制总的入口流量;

  • AuthorizationSlot 则根据黑白名单,来做黑白名单控制;

  • FlowSlot则用于根据预设的限流规则,以及前面 slot 统计的状态,来进行限流;

  • DegradeSlot则通过统计信息,以及预设的规则,来做熔断降级;

可以看到,我需要的熔断,限流,白名单控制都可以通过配置AuthorizationSlot,FlowSlot,DegradeSlot实现。

扩展

基于SPI与责任链模式的实现扩展。

  1. 新增自己的Slot。继承AbstractLinkedProcessorSlot。实现自己的流控业务。
  2. sentinel-core下的SPI配置:
    com.alibaba.csp.sentinel.soltchain.SoltChainBuilder初始化追加扩展的Solt

参考:
【sentinel】深入浅出之原理篇SlotChain

文档索引

【流量控制系列1】引言和索引
【流量控制系列2】流量控制的基础方法和算法
【流量控制系列3】Semaphore信号量介绍
【流量控制系列4】Sentinel和Hystrix对比
【流量控制系列5】Sentinel 详细介绍
【流量控制系列6】Sentinel 详细介绍-SlotChain源码解析
【流量控制系列7】Sentinel实践