2. Sentinel源码分析—Sentinel是如何进行流量统计的? (2)

ContextUtil

/** * Holds all {@link EntranceNode}. Each {@link EntranceNode} is associated with a distinct context name. */ private static volatile Map<String, DefaultNode> contextNameNodeMap = new HashMap<>(); static { // Cache the entrance node for default context. initDefaultContext(); } private static void initDefaultContext() { String defaultContextName = Constants.CONTEXT_DEFAULT_NAME; //初始化一个sentinel_default_context,type为in的队形 EntranceNode node = new EntranceNode(new StringResourceWrapper(defaultContextName, EntryType.IN), null); //Constants.ROOT会初始化一个name是machine-root,type=IN的对象 Constants.ROOT.addChild(node); //所以现在map里面有一个key=CONTEXT_DEFAULT_NAME的对象 contextNameNodeMap.put(defaultContextName, node); }

ContextUtil在初始化的时候会先调用initDefaultContext方法。通过Constants.ROOT创建一个root节点,然后将创建的node作为root的子节点入队,然后将node节点put到contextNameNodeMap中
结构如下:

Constants.ROOT: machine-root(EntryType#IN) / / sentinel_default_context(EntryType#IN)

现在我们再回到entryWithPriority方法中:

if (context == null) {//1 // Using default context. context = MyContextUtil.myEnter(Constants.CONTEXT_DEFAULT_NAME, "", resourceWrapper.getType()); }

如果context为空,那么会调用MyContextUtil.myEnter创建一个新的context,这个方法最后会调用到ContextUtil.trueEnter方法中进行创建。

protected static Context trueEnter(String name, String origin) { Context context = contextHolder.get(); if (context == null) { Map<String, DefaultNode> localCacheNameMap = contextNameNodeMap; DefaultNode node = localCacheNameMap.get(name); if (node == null) { //如果为null的话,检查contextNameNodeMap的size是不是超过2000 if (localCacheNameMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) { setNullContext(); return NULL_CONTEXT; } else { // 重复initDefaultContext方法的内容 try { LOCK.lock(); node = contextNameNodeMap.get(name); if (node == null) { if (contextNameNodeMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) { setNullContext(); return NULL_CONTEXT; } else { 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 = new Context(node, name); context.setOrigin(origin); contextHolder.set(context); } return context; }

在trueEnter方法中会做一个校验,如果contextNameNodeMap中的数量已经超过了2000,那么会返回一个NULL_CONTEXT。由于我们在initDefaultContext中已经初始化过了node节点,所以这个时候直接根据name获取node节点放入到contextHolder中。

创建完了context之后我们再回到entryWithPriority方法中继续往下走:

//创建一系列功能插槽 ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);

通过调用lookProcessChain方法会创建功能插槽

CtSph#lookProcessChain

ProcessorSlot<Object> lookProcessChain(ResourceWrapper resourceWrapper) { //根据resourceWrapper初始化插槽 ProcessorSlotChain chain = chainMap.get(resourceWrapper); if (chain == null) { synchronized (LOCK) { chain = chainMap.get(resourceWrapper); if (chain == null) { // Entry size limit.最大插槽数量为6000 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; }

这里会调用SlotChainProvider.newSlotChain进行插槽的初始化。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwfdp.html