sentinel源码分析-03构建执行链

本文详细解析了Sentinel中的限流处理逻辑,涉及CtSph类的entry方法,核心方法entryWithPriority中创建上下文、构建拦截链路的过程,以及如何通过SPI机制获取和使用SlotChainBuilder构建核心拦截链,包括限流、降级等策略。
摘要由CSDN通过智能技术生成

构建执行链

上文中我们分析了核心逻辑入口是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);

开始执行拦截链逻辑,这个我们后续分析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值