Spring Cloud Alibaba Sentinel Entry的具体创建逻辑

上一篇讲到entry的创建,这里看一下具体怎么创建的。
创建优先级的entry 上面设置的是false

//com.alibaba.csp.sentinel.CtSph
private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)
    throws BlockException {
    //获取上下文 ContextUtil里面会保存一个每个线程的上下文
    //private static ThreadLocal<Context> contextHolder = new ThreadLocal<>();
    Context context = ContextUtil.getContext();
    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.
        //context的数量溢出,只是初始化一个entry
        return new CtEntry(resourceWrapper, null, context);
    }
	//使用默认的context,初始化一个默认的context
    if (context == null) {
        // Using default context.
        context = InternalContextUtil.internalEnter(Constants.CONTEXT_DEFAULT_NAME);
    }

    // Global switch is close, no rule checking will do.
    if (!Constants.ON) {
        return new CtEntry(resourceWrapper, null, context);
    }
	//查找ProcessorSlot,查找不到就创建一个chain
    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;
}

1、获取context

//com.alibaba.csp.sentinel.context.ContextUtil
private static ThreadLocal<Context> contextHolder = new ThreadLocal<>();
public static Context getContext() {
    return contextHolder.get();
}

每个线程会绑定一个context。

ContextUtil用一个静态块进行初始化。当调用ContextUtil类时会先执行静态块初始化context。

//com.alibaba.csp.sentinel.context.ContextUtil
private static volatile Map<String, DefaultNode> contextNameNodeMap = new HashMap<>();
static {
    // Cache the entrance node for default context.
    //初始化context
    initDefaultContext();
}

private static void initDefaultContext() {
    //CONTEXT_DEFAULT_NAME = "sentinel_default_context"
    String defaultContextName = Constants.CONTEXT_DEFAULT_NAME;
    //生成一个Node
    //EntranceNode继承了DefaultNode,DefaultNode中有ClusterNode成员变量
    EntranceNode node = new EntranceNode(new StringResourceWrapper(defaultContextName, EntryType.IN), null);
    //添加节点
    Constants.ROOT.addChild(node);
    contextNameNodeMap.put(defaultContextName, node);
}

用contextNameNodeMap做了一层缓存

Constants.ROOT

//ROOT_ID = "machine-root"
//EntryType只有 IN 和 OUT
public final static DefaultNode ROOT = new EntranceNode(new StringResourceWrapper(ROOT_ID, EntryType.IN),
    new ClusterNode(ROOT_ID, ResourceTypeConstants.COMMON));
public final class ResourceTypeConstants {

    public static final int COMMON = 0;
    public static final int COMMON_WEB = 1;
    public static final int COMMON_RPC = 2;
    public static final int COMMON_API_GATEWAY = 3;
    public static final int COMMON_DB_SQL = 4;

    private ResourceTypeConstants() {}
}

创建Node。

//EntranceNode extends DefaultNode
public EntranceNode(ResourceWrapper id, ClusterNode clusterNode) {
    super(id, clusterNode);
}

EntranceNode继承了DefaultNode

//DefaultNode extends StatisticNode
private ClusterNode clusterNode;
public DefaultNode(ResourceWrapper id, ClusterNode clusterNode) {
    this.id = id;
    this.clusterNode = clusterNode;
}

DefaultNode 继承了StatisticNode。StatisticNode是Sentinel监控指标的处理Node。之后讲。

这里创建了一个clusterNode。

//ClusterNode extends StatisticNode
private final String name;
private final int resourceType;
public ClusterNode(String name, int resourceType) {
    AssertUtil.notEmpty(name, "name cannot be empty");
    this.name = name;
    this.resourceType = resourceType;
}

clusterNode有两个属性,资源名称和资源类型。也继承了 StatisticNode ,这个是个装饰器吧。

再来看Constants.ROOT的添加方法。

//com.alibaba.csp.sentinel.node.DefaultNode#addChild
private volatile Set<Node> childList = new HashSet<>();
public void addChild(Node node) {
    if (node == null) {
        RecordLog.warn("Trying to add null child to node <{}>, ignored", id.getName());
        return;
    }
    if (!childList.contains(node)) {
        synchronized (this) {
            if (!childList.contains(node)) {
                Set<Node> newSet = new HashSet<>(childList.size() + 1);
                newSet.addAll(childList);
                newSet.add(node);
                childList = newSet;
            }
        }
        RecordLog.info("Add child <{}> to node <{}>", ((DefaultNode)node).id.getName(), id.getName());
    }
}

这里因为是静态块,只会执行一次,所以在Constants.ROOT中只会添加一个node。

2、创建默认的context

private final static class InternalContextUtil extends ContextUtil {
    static Context internalEnter(String name) {
        return trueEnter(name, "");
    }

    static Context internalEnter(String name, String origin) {
        return trueEnter(name, origin);
    }
}
//com.alibaba.csp.sentinel.context.ContextUtil#trueEnter
private static final ReentrantLock LOCK = new ReentrantLock();
private static final Context NULL_CONTEXT = new NullContext();
protected static Context trueEnter(String name, String origin) {
    Context context = contextHolder.get();
    //当前线程的context不存在,创建
    if (context == null) {
        //做一个方法内缓存
        Map<String, DefaultNode> localCacheNameMap = contextNameNodeMap;
        //判断有没有Node存在
        DefaultNode node = localCacheNameMap.get(name);
        if (node == null) {
            //MAX_CONTEXT_NAME_SIZE = 2000	当前缓存Node太多,设置空context
            if (localCacheNameMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) {
                setNullContext();
                return NULL_CONTEXT;
            } else {
                //获得锁
                LOCK.lock();
                try {
                    //再次检查是否缓存了Node
                    node = contextNameNodeMap.get(name);
                    if (node == null) {
                        if (contextNameNodeMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) {
                            setNullContext();
                            return NULL_CONTEXT;
                        } else {
                            //创建新的node并添加到缓存中
                            node = new EntranceNode(new StringResourceWrapper(name, EntryType.IN), null);
                            // Add entrance node.
                            Constants.ROOT.addChild(node);

                            Map<String, DefaultNode> newMap = new HashMap<>(contextNameNodeMap.size() + 1);
                            newMap.putAll(contextNameNodeMap);
                            newMap.put(name, node);
                            contextNameNodeMap = newMap;
                        }
                    }
                } finally {
                    LOCK.unlock();
                }
            }
        }
        //创建context
        context = new Context(node, name);
        //服务名或源ip
        context.setOrigin(origin);
        contextHolder.set(context);
    }

    return context;
}

创建context

private final String name;
//当前context的Node
private DefaultNode entranceNode;
//当前的entry
private Entry curEntry;
//来源ip,默认空
private String origin = "";
//是否异步
private final boolean async;
public Context(DefaultNode entranceNode, String name) {
    this(name, entranceNode, false);
}
public Context(String name, DefaultNode entranceNode, boolean async) {
    this.name = name;
    this.entranceNode = entranceNode;
    this.async = async;
}

3、查找ProcessorSlot

//com.alibaba.csp.sentinel.CtSph#lookProcessChain
private static volatile Map<ResourceWrapper, ProcessorSlotChain> chainMap
        = new HashMap<ResourceWrapper, ProcessorSlotChain>();
ProcessorSlot<Object> lookProcessChain(ResourceWrapper resourceWrapper) {
    //从缓存中获取ProcessorSlotChain,一个资源一个ProcessorSlotChain
    ProcessorSlotChain chain = chainMap.get(resourceWrapper);
    if (chain == null) {
        synchronized (LOCK) {
            chain = chainMap.get(resourceWrapper);
            if (chain == null) {
                // Entry size limit.
                //MAX_SLOT_CHAIN_SIZE = 6000	
                //缓存的ProcessorSlotChain超出限制,这里为了保护系统
                if (chainMap.size() >= Constants.MAX_SLOT_CHAIN_SIZE) {
                    return null;
                }
				//创建ProcessorSlotChain
                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;
}

创建新的ProcessorSlotChain,这是一个处理链。

//com.alibaba.csp.sentinel.slotchain.SlotChainProvider#newSlotChain
public static ProcessorSlotChain newSlotChain() {
    //如果slotChainBuilder初始化过,直接创建ProcessorSlotChain
    if (slotChainBuilder != null) {
        return slotChainBuilder.build();
    }

    // Resolve the slot chain builder SPI.
    //根据spi机制去加载扩展
    //com\alibaba\csp\sentinel-core\1.8.1\sentinel-core-1.8.1.jar!\META-INF\services\com.alibaba.csp.sentinel.slotchain.SlotChainBuilder
    slotChainBuilder = SpiLoader.of(SlotChainBuilder.class).loadFirstInstanceOrDefault();

    if (slotChainBuilder == null) {
        // Should not go through here.
        RecordLog.warn("[SlotChainProvider] Wrong state when resolving slot chain builder, using default");
        //没有扩展slotChainBuilder,则设置为DefaultSlotChainBuilder
        slotChainBuilder = new DefaultSlotChainBuilder();
    } else {
        RecordLog.info("[SlotChainProvider] Global slot chain builder resolved: {}",
            slotChainBuilder.getClass().getCanonicalName());
    }
    return slotChainBuilder.build();
}

DefaultSlotChainBuilder

@Spi(isDefault = true)
public class DefaultSlotChainBuilder implements SlotChainBuilder {

    @Override
    public ProcessorSlotChain build() {
        //创建一个DefaultProcessorSlotChain
        ProcessorSlotChain chain = new DefaultProcessorSlotChain();
		//获取spi扩展的ProcessorSlot	获取到10个slot
        //com\alibaba\csp\sentinel-core\1.8.1\sentinel-core-1.8.1.jar!\META-INF\services\com.alibaba.csp.sentinel.slotchain.ProcessorSlot
        List<ProcessorSlot> sortedSlotList = SpiLoader.of(ProcessorSlot.class).loadInstanceListSorted();
        for (ProcessorSlot slot : sortedSlotList) {
            if (!(slot instanceof AbstractLinkedProcessorSlot)) {
                RecordLog.warn("The ProcessorSlot(" + slot.getClass().getCanonicalName() + ") is not an instance of AbstractLinkedProcessorSlot, can't be added into ProcessorSlotChain");
                continue;
            }

            chain.addLast((AbstractLinkedProcessorSlot<?>) slot);
        }

        return chain;
    }
}

这里将所有的slot组成了一个链。
各slot的order

public static final int ORDER_NODE_SELECTOR_SLOT = -10000;
public static final int ORDER_CLUSTER_BUILDER_SLOT = -9000;
public static final int ORDER_LOG_SLOT = -8000;
public static final int ORDER_STATISTIC_SLOT = -7000;
public static final int ORDER_AUTHORITY_SLOT = -6000;
public static final int ORDER_SYSTEM_SLOT = -5000;
public static final int ORDER_FLOW_SLOT = -2000;
public static final int ORDER_DEGRADE_SLOT = -1000;

DefaultProcessorSlotChain

//这里创建了一个链表的头节点
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);
    }
};
//刚开始头尾节点是同一个
AbstractLinkedProcessorSlot<?> end = first;
public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
    end.setNext(protocolProcessor);
    end = protocolProcessor;
}
public void setNext(AbstractLinkedProcessorSlot<?> next) {
    this.next = next;
}

这里维护了一个AbstractLinkedProcessorSlot链表。每个资源一个处理链。

4、创建entry

protected Entry parent = null;
protected Entry child = null;

protected ProcessorSlot<Object> chain;
protected Context context;
protected LinkedList<BiConsumer<Context, Entry>> exitHandlers;

CtEntry(ResourceWrapper resourceWrapper, ProcessorSlot<Object> chain, Context context) {
    super(resourceWrapper);
    this.chain = chain;
    this.context = context;
	//为context创建entry
    setUpEntryFor(context);
}

private void setUpEntryFor(Context context) {
    // The entry should not be associated to NullContext.
    if (context instanceof NullContext) {
        return;
    }
    //父节点,entry是一个树形结构
    this.parent = context.getCurEntry();
    if (parent != null) {
        ((CtEntry) parent).child = this;
    }
    context.setCurEntry(this);
}

下面是chain的处理。放下一篇。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值