Sentinel之插槽链的设计分析
一、Overview
在 Sentinel 里面,所有的资源都对应一个资源名称以及一个 Entry,Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 API 显式创建;每一个 Entry 创建的时候,同时也会创建一系列功能插槽(slot chain)。
总体框架如图:
二、源码分析
资源获取对应Entry会在CtSph类中完成,在CtSph中也完成了对SlotChain的初始化。
chain
主要看lookProcessChain方法。
ProcessorSlot<Object> lookProcessChain(ResourceWrapper resourceWrapper) {
//1、先从chainMap获取,若是存在,则直接返回
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;
}
//2、通过SlotChainProvider获取slotChain
chain = SlotChainProvider.newSlotChain();
Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap<ResourceWrapper, ProcessorSlotChain>(
chainMap.size() + 1);
newMap.putAll(chainMap);
//3、添加到map中
newMap.put(resourceWrapper, chain);
chainMap = newMap;
}
}
}
return chain;
}
接着看SlotChainProvider
private static volatile SlotChainBuilder builder = null;
//SPI机制获取实现了SlotChainBuilder的类
private static final ServiceLoader<SlotChainBuilder> LOADER = ServiceLoader.load(SlotChainBuilder.class);
public static ProcessorSlotChain newSlotChain() {
//1、首次加载时builder为空
if (builder != null) {
return builder.build();
}
//2、调用resolveSlotChainBuilder
resolveSlotChainBuilder();
if (builder == null) {
RecordLog.warn("[SlotChainProvider] Wrong state when resolving slot chain builder, using default");
builder = new DefaultSlotChainBuilder();
}
return builder.build();
}
private static void resolveSlotChainBuilder() {
List<SlotChainBuilder> list = new ArrayList<SlotChainBuilder>();
boolean hasOther = false;
//循环加载
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());
}
实现SlotChainBuilder的类有两个:DefaultSlotChainBuilder和HotParamSlotChainBuilder,DefaultSlotChainBuilder是默认SlotChainBuilder,
HotParamSlotChainBuilder是热点参数Builder,比DefaultSlotChainBuilder多了一个ParamFlowSlot插槽,如果使用热点参数即使用这个插槽。
Sentinel 将 SlotChainBuilder 作为 SPI 接口进行扩展,使得 Slot Chain 具备了扩展的能力。用户可以自行加入自定义的 slot 并编排 slot 间的顺序,从而可以给 Sentinel 添加自定义的功能。
SlotChainProvider是用来获取ProcessorSlotChain的,是通过SlotChainBuilder的build方法实现的。
HotParamSlotChainBuilder
image.png下面具体分析:
第一步
初始化DefaultProcessorSlotChain的类。
public class DefaultProcessorSlotChain extends ProcessorSlotChain {
//初始化一个first节点,AbstractLinkedProcessorSlot有个next节点属性
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);
}
};
//赋值end节点
AbstractLinkedProcessorSlot<?> end = first;
//下面代码省略
}
这个时候slotChain的构造如下:
soltChain
first和end都为DefaultProcessorSlotChain,next为空。
第二步
chain.addLast(new NodeSelectorSlot());
调用的addLast方法
@Override
public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
//设置next链
end.setNext(protocolProcessor);
//重新设置end
end = protocolProcessor;
}
这个时候slotChain的构造如下:
slotchain
接下来继续构建,最后SoltChain链如下:
soltChain
这就是整个插槽链的构造过程了。
三、SoltChain介绍
- NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结-构存储起来,用于根据调用路径来限流降级;
- ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;
- StatisticSlot 则用于记录、统计不同纬度的 runtime 指标监控信息;
- LogSlot 则用于记录blockException信息的日志信息,会写入的日志文件中;
- ParamFlowSlot 则用于根据热点参数进行限流控制的;
- SystemSlot 则通过系统的状态,例如 load1 等,来控制总的入口流量;
- AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
- FlowSlot 则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;
- DegradeSlot 则通过统计信息以及预设的规则,来做熔断降级;
后续会详细介绍每个插槽的功能。
四、我的总结
1、本文介绍的插槽的初始化过程链的构造过程;
2、插槽链的构造中用到的是设计模式中的责任链模式;
3、sentinel默认实现了两个SlotChainBuilder,通常情况下使用的默认的DefaultSlotChainBuilder;
以上内容,如有不当之处,请指正