前言:
前面我们对 Sentinel 有了一个比较系统的认知,本篇我们正式开始分析 Sentinel 的源码,我们知道 Sentinel 使用了责任链模式,根据 Sentinel 官方提供的流程图,我们知道 NodeSelectorSlot 是整个链路的入口,下面我们开始分析 Sentinel 源码。
Sentinel 系列文章传送门:
Spring Cloud 整合 Nacos、Sentinel、OpenFigen 实战【微服务熔断降级实战】
Sentinel 源码分析入门【Entry、Chain、Context】
NodeSelectorSlot#entry 方法源码解析
NodeSelectorSlot#entry 方法会根据资源名称获取 DefaultNode 链路节点,DefaultNode 用于统计调用链路上某个资源的数据,维持树状结构,然后执行下一个 Slot,也就是 ClusterBuilderSlot,详细拆分的话 NodeSelectorSlot 做了一下几件事:
- 为当前资源创建 DefaultNode。
- 将 DefaultNode 放入缓存中,key 是 contextName,这样不同链路入口的请求,将会创建多个 DefaultNode,相同链路则只有一个DefaultNode。
- 将当前资源的 DefaultNode 设置为上一个资源的 ChildNode,构造树。
- 将当前资源的 DefaultNode 设置为 Context 中的 curNode,也就是当前节点。
//com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot#entry
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)
throws Throwable {
//获取当前资源的 DefaultNode
DefaultNode node = map.get(context.getName());
//DefaultNode 为空判断
if (node == null) {
//node 为空
//synchronized 加锁
synchronized (this) {
//再次获取 node
node = map.get(context.getName());
//再次为空判断
if (node == null) {
//创建一个 DefaultNode
node = new DefaultNode(resourceWrapper, null);
//创建 map 加入缓存
HashMap<String, DefaultNode> cacheMap = new HashMap<String, DefaultNode>(map.size());
cacheMap.putAll(map);
cacheMap.put(context.getName(), node);
map = cacheMap;
// Build invocation tree
//构建调用树
((DefaultNode) context.getLastNode()).addChild(node);
}
}
}
//设置当前 node
context.setCurNode(node);
//执行下一个 slot
fireEntry(context, resourceWrapper, node, count