构建执行链
上文中我们分析了核心逻辑入口是SphU.entry(target, EntryType.IN),我们只分析了一些初始化逻辑下面,我们分析一下核心限流处理逻辑
public class Env {
public static final Sph sph = new CtSph();
static {
// If init fails, the process will exit.
//初始化
InitExecutor.doInit();
}
}
CtSph类的
public Entry entry(String name, EntryType type, int count, Object... args) throws BlockException {
//封装成resource
StringResourceWrapper resource = new StringResourceWrapper(name, type);
return entry(resource, count, args);
}
经过执行逻辑跟踪最终会走到entryWithPriority方法
private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)
throws BlockException {
//之前已经创建了上下文
Context context = ContextUtil.getContext();
//超出了创建context数量限制
if (context instanceof NullContext) {
// The {@link NullContext} indicates that the amount of context has exceeded the threshold,
// so here init the entry only. No rule checking will be done.
return new CtEntry(resourceWrapper, null, context);
}
//之前还没创建context
if (context == null) {
// Using default context.
context = MyContextUtil.myEnter(Constants.CONTEXT_DEFAULT_NAME, "", resourceWrapper.getType());
}
// Global switch is close, no rule checking will do.
// 全局开关已关闭,不会进行任何规则检查。
if (!Constants.ON) {
return new CtEntry(resourceWrapper, null, context);
}
//核心方法-构建拦截链路
ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);
/*
* Means amount of resources (slot chain) exceeds {@link Constants.MAX_SLOT_CHAIN_SIZE},
* so no rule checking will be done.
*/
//资源的拦截链数量超过最大值,则不执行任何规则检查
if (chain == null) {
return new CtEntry(resourceWrapper, null, context);
}
Entry e = new CtEntry(resourceWrapper, chain, context);
try {
//开启链路调用
chain.entry(context, resourceWrapper, null, count, prioritized, args);
} catch (BlockException e1) {
e.exit(count, args);
throw e1;
} catch (Throwable e1) {
// This should not happen, unless there are errors existing in Sentinel internal.
RecordLog.info("Sentinel unexpected exception", e1);
}
return e;
}
这里主要完成以下几个事情
- 创建运行上下文
private static ThreadLocal<Context> contextHolder = new ThreadLocal<>();
public static Context getContext() {
return contextHolder.get();
}
首先查看之前线程有没有创建了context,如果已经有了就直接获取,如果没有则创建默认的context
protected static Context trueEnter(String name, String origin) {
//每个线程一个Context
Context context = contextHolder.get();
if (context == null) {
Map<String, DefaultNode> localCacheNameMap = contextNameNodeMap;
DefaultNode node = localCacheNameMap.get(name);
if (node == null) {
if (localCacheNameMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) {
setNullContext();
return NULL_CONTEXT;
} else {
try {
LOCK.lock();
node = contextNameNodeMap.get(name);
if (node == null) {
if (contextNameNodeMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) {
setNullContext();
return NULL_CONTEXT;
} else {
//入口node,name:"sentinel_default_context"
node = new EntranceNode(new StringResourceWrapper(name, EntryType.IN), null);
// Add entrance node.
Constants.ROOT.addChild(node);
//为什么重新创建map进行赋值,不直接使用ConcurrentHashMap
Map<String, DefaultNode> newMap = new HashMap<>(contextNameNodeMap.size() + 1);
newMap.putAll(contextNameNodeMap);
newMap.put(name, node);
contextNameNodeMap = newMap;
}
}
} finally {
LOCK.unlock();
}
}
}
context = new Context(node, name);
context.setOrigin(origin);
contextHolder.set(context);
}
return context;
}
每一个上下文问都会对应一个EntranceNode,他是调用的入口节点,不同调用方式不同的EntranceNode
- 构建核心拦截链路
ProcessorSlot<Object> lookProcessChain(ResourceWrapper resourceWrapper) {
ProcessorSlotChain chain = chainMap.get(resourceWrapper);
if (chain == null) {
synchronized (LOCK) {
chain = chainMap.get(resourceWrapper);
if (chain == null) {
// Entry size limit.
if (chainMap.size() >= Constants.MAX_SLOT_CHAIN_SIZE) {
return null;
}
//构建过滤链
chain = SlotChainProvider.newSlotChain();
Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap<ResourceWrapper, ProcessorSlotChain>(
chainMap.size() + 1);
newMap.putAll(chainMap);
newMap.put(resourceWrapper, chain);
chainMap = newMap;
}
}
}
return chain;
}
public static ProcessorSlotChain newSlotChain() {
if (builder != null) {
return builder.build();
}
//获取请求链创建builder
resolveSlotChainBuilder();
if (builder == null) {
RecordLog.warn("[SlotChainProvider] Wrong state when resolving slot chain builder, using default");
builder = new DefaultSlotChainBuilder();
}
return builder.build();
}
private static final ServiceLoader<SlotChainBuilder> LOADER = ServiceLoader.load(SlotChainBuilder.class);
private static void resolveSlotChainBuilder() {
List<SlotChainBuilder> list = new ArrayList<SlotChainBuilder>();
boolean hasOther = false;
//通过SPI机制获取连接链builder
for (SlotChainBuilder builder : LOADER) {
if (builder.getClass() != DefaultSlotChainBuilder.class) {
hasOther = true;
list.add(builder);
}
}
if (hasOther) {
builder = list.get(0);
} else {
// No custom builder, using default.
builder = new DefaultSlotChainBuilder();
}
RecordLog.info("[SlotChainProvider] Global slot chain builder resolved: "
+ builder.getClass().getCanonicalName());
}
这里又是通过SPI机制获取所有SlotChainBuilder的实现类,查看META-INF.services下的com.alibaba.csp.sentinel.slotchain.SlotChainBuilder文件
# Default slot chain builder
com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder
通过DefaultSlotChainBuilder构建了整个核心拦截链
public class DefaultSlotChainBuilder implements SlotChainBuilder {
@Override
public ProcessorSlotChain build() {
ProcessorSlotChain chain = new DefaultProcessorSlotChain();
//收集资源的路径,将调用路径以树状结构存储起来,根据调用路径来限流降级
chain.addLast(new NodeSelectorSlot());
//负责调用来源的信息统计和ClusterNode某个资源的统计信息
chain.addLast(new ClusterBuilderSlot());
//在抛出BlockException的时候,会通过该类来输入一些日志信息
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;
}
}
到这里就构建了核心的拦截链
- 开启链路调用
//开启链路调用
chain.entry(context, resourceWrapper, null, count, prioritized, args);
开始执行拦截链逻辑,这个我们后续分析