技术干货

Sentinel之插槽链的设计分析

2018-12-16  本文已影响0人  橘子_好多灰

一、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介绍

后续会详细介绍每个插槽的功能。

四、我的总结

1、本文介绍的插槽的初始化过程链的构造过程;
2、插槽链的构造中用到的是设计模式中的责任链模式;
3、sentinel默认实现了两个SlotChainBuilder,通常情况下使用的默认的DefaultSlotChainBuilder;


以上内容,如有不当之处,请指正

上一篇下一篇

猜你喜欢

热点阅读