Sentinel源码一:Entry
概述
最近对 sentinel 框架的使用作了一个了解,为了在团队内对 sentinel 做分享学习一下其中的原理。
源码解析
看一下简单的使用
1 | public void entry(){ |
根据上面的代码可以知道 sentinel 对代码的限流/熔断都是由 Entry 类和 SphU 类作为入口的,所以源码解读可以从这些类开始.
在 Sentinel 里面,所有的资源都对应一个资源名称(resourceName),每次资源调用都会创建一个 Entry 对象。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 SphU API 显式创建。Entry 创建的时候,同时也会创建一系列功能插槽(slot chain),这些插槽有不同的职责。
Entry类
Entry 类是一个抽象类
继承关系
1 | public abstract class Entry implements AutoCloseable{} |
成员变量
1 | private static final Object[] OBJECTS0 = new Object[0]; |
方法
1 | public ResourceWrapper getResourceWrapper() { |
Entry 构建 SphU.entry
SphU.entry 是最开始的入口,委托了 Env.sph.entry 执行1
2
3
4
5private static final Object[] OBJECTS0 = new Object[0];
public static Entry entry(String name) throws BlockException {
return Env.sph.entry(name, EntryType.OUT, 1, OBJECTS0);
}
Env 类
sph 的实现类是 CtSph1
2
3
4
5
6
7
8
9public class Env {
public static final Sph sph = new CtSph();
static {
// If init fails, the process will exit.
InitExecutor.doInit();
}
}
Sph
Sph 用于对资源的保护,如果发生 block 就会抛出 BlockException,成功就会返回一个 entry。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
29public interface Sph {
Entry entry(String name) throws BlockException;
Entry entry(Method method) throws BlockException;
Entry entry(Method method, int count) throws BlockException;
Entry entry(String name, int count) throws BlockException;
Entry entry(Method method, EntryType type) throws BlockException;
Entry entry(String name, EntryType type) throws BlockException;
Entry entry(Method method, EntryType type, int count) throws BlockException;
Entry entry(String name, EntryType type, int count) throws BlockException;
Entry entry(Method method, EntryType type, int count, Object... args) throws BlockException;
Entry entry(String name, EntryType type, int count, Object... args) throws BlockException;
AsyncEntry asyncEntry(String name, EntryType type, int count, Object... args) throws BlockException;
Entry entryWithPriority(String name, EntryType type, int count, boolean prioritized) throws BlockException;
Entry entryWithPriority(String name, EntryType type, int count, boolean prioritized, Object... args)
throws BlockException;
}
CtSph
继承关系
1 | public class CtSph implements Sph{} |
成员变量
1 | private static final Object[] OBJECTS0 = new Object[0]; |
核心方法
entryWithPriority()
所有同步的都是走的entryWithPriority,只是带不带优先级的区别
执行逻辑
- 获取上下文Context;
- 如果上下文是NullContext,则返回new CtEntry(resourceWrapper, null, context);
- 如果上下文为空,生成默认上下文;
- 如果Constants.ON为false,则返回new CtEntry(resourceWrapper, null, context);
- 获取插槽链;
- 如果插槽链为Null,则返回new CtEntry(resourceWrapper, null, context);
- 生成带插槽链的Entry;
- 执行插槽链的entry方法;
- 返回Entry
1 | private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args) |
插槽链 lookProcessChain
1 | ProcessorSlot<Object> lookProcessChain(ResourceWrapper resourceWrapper) { |
默认插槽链1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class DefaultSlotChainBuilder implements SlotChainBuilder {
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;
}
}
public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
end.setNext(protocolProcessor);
end = protocolProcessor;
}
DefaultProcessorSlotChain.entry
DefaultProcessorSlotChain 的 entry 方法就是执行插槽链上各个节点的 transformEntry 方法1
2
3
4
5
6
7
8
9
10
11
12
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 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);
}
}
CtEntry
继承关系
1 | class CtEntry extends Entry{} |
成员变量
CtEntry 是一个双向链表1
2
3
4
5protected Entry parent = null;
protected Entry child = null;
protected ProcessorSlot<Object> chain;
protected Context context;
构造器
1 | CtEntry(ResourceWrapper resourceWrapper, ProcessorSlot<Object> chain, Context context) { |
主要方法
退出 exit
1 |
|
退出 exitForContext
exitForContext 主要是执行插槽的 exit 方法并更新当前上下文的CurEntry1
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
41protected void exitForContext(Context context, int count, Object... args) throws ErrorEntryFreeException {
if (context != null) {
// Null context should exit without clean-up.
if (context instanceof NullContext) {
return;
}
// 当前节点没有正确执行exit,导致当前节点不是curEntry
if (context.getCurEntry() != this) {
String curEntryNameInContext = context.getCurEntry() == null ? null : context.getCurEntry().getResourceWrapper().getName();
// Clean previous call stack.
CtEntry e = (CtEntry)context.getCurEntry();
while (e != null) {
e.exit(count, args);
e = (CtEntry)e.parent;
}
String errorMessage = String.format("The order of entry exit can't be paired with the order of entry"
+ ", current entry in context: <%s>, but expected: <%s>", curEntryNameInContext, resourceWrapper.getName());
throw new ErrorEntryFreeException(errorMessage);
} else {
// 执行插槽的 exit 方法
if (chain != null) {
chain.exit(context, resourceWrapper, count, args);
}
// Restore the call stack.
// 将当前Entry设置为上一个节点
context.setCurEntry(parent);
if (parent != null) {
((CtEntry)parent).child = null;
}
// 没有上一个节点就退出
if (parent == null) {
// Default context (auto entered) will be exited automatically.
if (ContextUtil.isDefaultContext(context)) {
ContextUtil.exit();
}
}
// Clean the reference of context in current entry to avoid duplicate exit.
clearEntryContext();
}
}
}
置空上下文 clearEntryContext
1 | protected void clearEntryContext() { |
getLastNode
1 | public Node getLastNode() { |