NodeSelectorSlot 负责为资源的首次访问创建 DefaultNode,以及维护 Context.curNode 和调用树,
一次调用链路上出现多次调用SphU#entry,则每次调用生成的CEntry最终会变成双向链表,存储在Context中。
NodeSelectorSlot 被放在 ProcessorSlotChain 链表的第一个位置,这是因为后续的 ProcessorSlot 都需要依赖这个 ProcessorSlot。
public class NodeSelectorSlot extends AbstractLinkedProcessorSlot<Object> { // Context 的 name -> 资源的 DefaultNode private volatile Map<String, DefaultNode> map = new HashMap<>(10); // 入口方法 @Override public void entry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args) throws Throwable { // 使用 Context 的名称作为 key 缓存资源的 DefaultNode DefaultNode node = map.get(context.getName()); if (node == null) { synchronized (this) { node = map.get(context.getName()); if (node == null) { // 为资源创建 DefaultNode node = new DefaultNode(resourceWrapper, null); // 替换 map HashMap<String, DefaultNode> cacheMap = new HashMap<>(map.size()); cacheMap.putAll(map); cacheMap.put(context.getName(), node); map = cacheMap; // 绑定调用树 ((DefaultNode) context.getLastNode()).addChild(node); } } } // 替换 Context 的 curNode 为当前 DefaultNode context.setCurNode(node); fireEntry(context, resourceWrapper, node, count, prioritized, args); } // 出口方法什么也不做 @Override public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) { fireExit(context, resourceWrapper, count, args); } }
NodeSelectorSlot#map的作用:
一个资源对应一个slotchain,一个slotchain下记录不同的context创建的DefaultNode.
Sentinel 会为同一资源 ID 创建多少个 DefaultNode 取决于有多少个调用链使用其作为入口资源,直白点就是同一资源存在多少个 DefaultNode 取决于 Context.name 有多少种不同取值,这就是为什么说一个资源可能有多个 DefaultNode 的原因。
举个例子,
对同一支付接口,我们需要使用 Spring MVC 暴露给前端访问,同时也可能会使用 Dubbo 暴露给其它内部服务调用。Sentinel 的 Web MVC 适配器在调用链路入口创建名为“sentinel_spring_web_context”的 Context,与 Sentinel 的 Dubbo 适配器调用 ContextUtil#enter 方法创建的 Context 名称不同。针对这种情况,我们可以实现只限制 Spring MVC 进来的流量,也就是限制前端发起接口调用的 QPS、并行占用的线程数等。
spring-webmvc默认拦截使用的context是由类com.alibaba.csp.sentinel.adapter.spring.webmvc.AbstractSentinelInterceptor来实现的,默认值是sentinel_spring_web_context 。
context+resource确认唯一的DeafultNode。
一个context对应一个EntranceNode,
一个Resouce对应一个ClusterNode,并且对应一个ProcessorSlotChain, ,
每个ProcessorSlotChain包含一个Map, 存储本resource下,context与DefaultNode的关系。
同一个context下存储一个Entry调用链, 每个Entry执行接受后调用entry.exit(1),目的是退出本Node,并且返回Parent CEntry,
每个StatisticsNode还有Map,包含Node的origin信息,用来对不同来源的Node做区分统计。
node关系表