美文网首页
sentinal源码2-初始化

sentinal源码2-初始化

作者: modou1618 | 来源:发表于2019-03-30 14:09 被阅读0次
    • 包含很多static的初始化块,并通过ServiceLoader的方式加载各种类

    一 static初始化块

    static初始化块.png

    二 CtSph

    • 提供资源请求entry初始化函数

    2.1 同步context

    • 1 超过可限流的context入口类型数,则不做限流
    • 2 未指定则使用默认名称的context入口节点
    • 3 全局限流开关Constants.ON,关闭则不做限流
    • 4 获取当前资源对应的处理链,每个资源对应一个处理链,名称活方法表示资源
    • 5 资源对应的资源节点处理链数达到上限,则后续资源请求不做处理
    • 6 实例化资源请求Entry,按资源节点处理链依次处理,进行统计,资源申请等操作
    • 7 资源申请失败,按处理链做失败统计等处理
    private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)
        throws BlockException {
        Context context = ContextUtil.getContext();
        if (context instanceof NullContext) { //1
            return new CtEntry(resourceWrapper, null, context);
        }
    
        if (context == null) {//2
            context = MyContextUtil.myEnter(Constants.CONTEXT_DEFAULT_NAME, "", resourceWrapper.getType());
        }
    
        if (!Constants.ON) {//3
            return new CtEntry(resourceWrapper, null, context);
        }
    
        ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);//4
    
        if (chain == null) {//5
            return new CtEntry(resourceWrapper, null, context);
        }
      
        Entry e = new CtEntry(resourceWrapper, chain, context);
        try {
            chain.entry(context, resourceWrapper, null, count, prioritized, args);//6
        } catch (BlockException e1) {
            e.exit(count, args);//7
            throw e1;
        } catch (Throwable e1) {
            RecordLog.info("Sentinel unexpected exception", e1);
        }
        return e;
    }
    

    2.1.1 lookProcessChain

    • 根据context名称获取处理链
    • 使用hashmap存储
      private static volatile Map<ResourceWrapper, ProcessorSlotChain> chainMap = new HashMap<ResourceWrapper, ProcessorSlotChain>();
    • 二次加锁校验方式初始化
    • 写拷贝更新的方式更新存储map
    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;
    }
    

    2.1.2 获取资源节点处理链

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

    2.2 异步context

    //todo

    三 Entry

    3.1 类结构图

    entry类.png

    3.2 CtEntry

    3.2.1 实例化

    • Entry实例化
    • 保存资源处理链,资源处理上下文context
    CtEntry(ResourceWrapper resourceWrapper, ProcessorSlot<Object> chain, Context context) {
        super(resourceWrapper);
        this.chain = chain;
        this.context = context;
    
        setUpEntryFor(context);
    }
    
    • 设置Entry父子关系,更新context.curEntry为本次新建的Entry
    private void setUpEntryFor(Context context) {
        // The entry should not be associated to NullContext.
        if (context instanceof NullContext) {
            return;
        }
        this.parent = context.getCurEntry();
        if (parent != null) {
            ((CtEntry)parent).child = this;
        }
        context.setCurEntry(this);
    }
    
    • 保存对应的context名称
    • 保存资源请求时间
    public Entry(ResourceWrapper resourceWrapper) {
        this.resourceWrapper = resourceWrapper;
        this.createTime = TimeUtil.currentTimeMillis();
    }
    

    3.2.2 资源请求失败处理

    • 1 失败的entry非context当前entry,则按entry父子关系依次向上调用所有entry的失败处理函数exit()
    • 2 失败entry是context的当前entry,
      调用资源处理链的exit函数
      更新context的curEntry为请求失败Entry的父节点Entry
      删除Entry的父子关系
      如Entry无父节点,则若是默认context则需要自动清理,手动配置的context则由用户手动退出。
      清理Entry的context属性
    protected 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;
            }
            if (context.getCurEntry() != this) {//1
                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 {//2
                if (chain != null) {
                    chain.exit(context, resourceWrapper, count, args);
                }
                context.setCurEntry(parent);
                if (parent != null) {
                    ((CtEntry)parent).child = null;
                }
                if (parent == null) {
                    if (ContextUtil.isDefaultContext(context)) {
                        ContextUtil.exit();
                    }
                }
                clearEntryContext();
            }
        }
    }
    
    • 清理线程变量缓存的context
    public static void exit() {
        Context context = contextHolder.get();
        if (context != null && context.getCurEntry() == null) {
            contextHolder.set(null);
        }
    }
    

    3.3 AsyncEntry

    //todo

    四 节点关系图

    image.png

    相关文章

      网友评论

          本文标题:sentinal源码2-初始化

          本文链接:https://www.haomeiwen.com/subject/ixjjbqtx.html