Spring Cloud Alibaba Sentinel 处理链

构建slot链处理请求

//com.alibaba.csp.sentinel.slotchain.DefaultProcessorSlotChain#entry
public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args)
    throws Throwable {
    first.transformEntry(context, resourceWrapper, t, count, prioritized, args);
}
//com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot#transformEntry
//频繁调用
void transformEntry(Context context, ResourceWrapper resourceWrapper, Object o, int count, boolean prioritized, Object... args)
    throws Throwable {
    T t = (T)o;
    //调用上面first头节点的entry,因为匿名内部类里面重写了entry方法。
    entry(context, resourceWrapper, t, count, prioritized, args);
}
//com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot#fireEntry
//频繁调用
public void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)
    throws Throwable {
    //NodeSelectorSlot
    if (next != null) {
        //调的上面的transformEntry
        next.transformEntry(context, resourceWrapper, obj, count, prioritized, args);
    }
}

1、NodeSelectorSlot

//com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot#entry
//NodeSelectorSlot  order=-10000
private volatile Map<String, DefaultNode> map = new HashMap<String, DefaultNode>(10);
//进入entry方法,同一个资源名称会有不同的context,context的名称作为key,每个context有一个DefaultNode,不同context的DefaultNode共享一个ClusterNode
public void entry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)
    throws Throwable {
    DefaultNode node = map.get(context.getName());
    if (node == null) {
        synchronized (this) {
            node = map.get(context.getName());
            if (node == null) {
                //当前context没有DefaultNode,创建,然后加入缓存
                node = new DefaultNode(resourceWrapper, null);
                HashMap<String, DefaultNode> cacheMap = new HashMap<String, DefaultNode>(map.size());
                cacheMap.putAll(map);
                cacheMap.put(context.getName(), node);
                map = cacheMap;
                // Build invocation tree
                //创建Node树,获取
                ((DefaultNode) context.getLastNode()).addChild(node);
            }

        }
    }
	//设置当前处理的Node
    context.setCurNode(node);
    //调用上面的fireEntry
    fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
//com.alibaba.csp.sentinel.context.Context#getLastNode
//context的根Node
private DefaultNode entranceNode;
//context当前处理的Node
private Entry curEntry;
public Node getLastNode() {
    if (curEntry != null && curEntry.getLastNode() != null) {
        return curEntry.getLastNode();
    } else {
        return entranceNode;
    }
}
//com.alibaba.csp.sentinel.CtEntry#getLastNode
public Node getLastNode() {
    return parent == null ? null : parent.getCurNode();
}

2、ClusterBuilderSlot

//com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot#entry
//缓存
private static volatile Map<ResourceWrapper, ClusterNode> clusterNodeMap = new HashMap<>();
private static final Object lock = new Object();
private volatile ClusterNode clusterNode = null;
//如果clusterNode为空,则创建
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                  boolean prioritized, Object... args)
    throws Throwable {
    if (clusterNode == null) {
        synchronized (lock) {
            if (clusterNode == null) {
                // Create the cluster node.
                //创建clusterNode
                clusterNode = new ClusterNode(resourceWrapper.getName(), resourceWrapper.getResourceType());
                HashMap<ResourceWrapper, ClusterNode> newMap = new HashMap<>(Math.max(clusterNodeMap.size(), 16));
                newMap.putAll(clusterNodeMap);
                newMap.put(node.getId(), clusterNode);

                clusterNodeMap = newMap;
            }
        }
    }
    //给当前Node设置clusterNode
    node.setClusterNode(clusterNode);

    /*
     * if context origin is set, we should get or create a new {@link Node} of
     * the specific origin.
     */
    //如果源为空,则创建
    if (!"".equals(context.getOrigin())) {
        Node originNode = node.getClusterNode().getOrCreateOriginNode(context.getOrigin());
        context.getCurEntry().setOriginNode(originNode);
    }
	//调用上面的方法,执行下个slot
    fireEntry(context, resourceWrapper, node, count, prioritized, args);
}

获取或者创建源Node

//com.alibaba.csp.sentinel.node.ClusterNode#getOrCreateOriginNode
private Map<String, StatisticNode> originCountMap = new HashMap<>();
public Node getOrCreateOriginNode(String origin) {
    //缓存中没有则创建
    StatisticNode statisticNode = originCountMap.get(origin);
    if (statisticNode == null) {
        lock.lock();
        try {
            statisticNode = originCountMap.get(origin);
            if (statisticNode == null) {
                // The node is absent, create a new node for the origin.
                statisticNode = new StatisticNode();
                HashMap<String, StatisticNode> newMap = new HashMap<>(originCountMap.size() + 1);
                newMap.putAll(originCountMap);
                newMap.put(origin, statisticNode);
                originCountMap = newMap;
            }
        } finally {
            lock.unlock();
        }
    }
    return statisticNode;
}

3、LogSlot

//com.alibaba.csp.sentinel.slots.logger.LogSlot#entry
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode obj, int count, boolean prioritized, Object... args)
    throws Throwable {
    try {
        //调用上面的方法执行一个slot
        fireEntry(context, resourceWrapper, obj, count, prioritized, args);
    } catch (BlockException e) {
        EagleEyeLogUtil.log(resourceWrapper.getName(), e.getClass().getSimpleName(), e.getRuleLimitApp(),
            context.getOrigin(), count);
        throw e;
    } catch (Throwable e) {
        RecordLog.warn("Unexpected entry exception", e);
    }

}

4、StatisticSlot

//com.alibaba.csp.sentinel.slots.statistic.StatisticSlot#entry
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                  boolean prioritized, Object... args) throws Throwable {
    try {
        // Do some checking.	检查
        fireEntry(context, resourceWrapper, node, count, prioritized, args);

        // Request passed, add thread count and pass count.
        //规则都校验完了,增加线程数,
        node.increaseThreadNum();
        node.addPassRequest(count);
		//当前entry的源Node不为空
        if (context.getCurEntry().getOriginNode() != null) {
            // Add count for origin node.
            //增加源Node的线程数量和通过的请求数
            context.getCurEntry().getOriginNode().increaseThreadNum();
            context.getCurEntry().getOriginNode().addPassRequest(count);
        }
		//输入类型	增加线程数和通过的请求数  
        if (resourceWrapper.getEntryType() == EntryType.IN) {
            // Add count for global inbound entry node for global statistics.
            Constants.ENTRY_NODE.increaseThreadNum();
            Constants.ENTRY_NODE.addPassRequest(count);
        }

        // Handle pass event with registered entry callback handlers.
        //请求通过,handler处理
        for (ProcessorSlotEntryCallback<DefaultNode> handler : StatisticSlotCallbackRegistry.getEntryCallbacks()) {
            handler.onPass(context, resourceWrapper, node, count, args);
        }
    } catch (PriorityWaitException ex) {
        node.increaseThreadNum();
        if (context.getCurEntry().getOriginNode() != null) {
            // Add count for origin node.
            context.getCurEntry().getOriginNode().increaseThreadNum();
        }

        if (resourceWrapper.getEntryType() == EntryType.IN) {
            // Add count for global inbound entry node for global statistics.
            Constants.ENTRY_NODE.increaseThreadNum();
        }
        // Handle pass event with registered entry callback handlers.
        for (ProcessorSlotEntryCallback<DefaultNode> handler : StatisticSlotCallbackRegistry.getEntryCallbacks()) {
            handler.onPass(context, resourceWrapper, node, count, args);
        }
    } catch (BlockException e) {
        // Blocked, set block exception to current entry.
        context.getCurEntry().setBlockError(e);

        // Add block count.
        node.increaseBlockQps(count);
        if (context.getCurEntry().getOriginNode() != null) {
            context.getCurEntry().getOriginNode().increaseBlockQps(count);
        }

        if (resourceWrapper.getEntryType() == EntryType.IN) {
            // Add count for global inbound entry node for global statistics.
            Constants.ENTRY_NODE.increaseBlockQps(count);
        }

        // Handle block event with registered entry callback handlers.
        //StatisticSlotCallbackRegistry 添加 callback 在InitExecutor#doInit完成
        for (ProcessorSlotEntryCallback<DefaultNode> handler : StatisticSlotCallbackRegistry.getEntryCallbacks()) {
            handler.onBlocked(e, context, resourceWrapper, node, count, args);
        }

        throw e;
    } catch (Throwable e) {
        // Unexpected internal error, set error to current entry.
        context.getCurEntry().setError(e);

        throw e;
    }
}

4.1、执行slot链的剩下slot

4.1.1、AuthoritySlot
//com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot#entry
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args)
    throws Throwable {
    //检查黑白名单
    checkBlackWhiteAuthority(resourceWrapper, context);
    //执行下一个slot
    fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
4.1.2、SystemSlot
//com.alibaba.csp.sentinel.slots.system.SystemSlot#entry
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                  boolean prioritized, Object... args) throws Throwable {
    SystemRuleManager.checkSystem(resourceWrapper);
    //下一个节点
    fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
4.1.3、GatewayFlowSlot

和gateway集成后使用的限流slot

//com.alibaba.csp.sentinel.adapter.gateway.common.slot.GatewayFlowSlot#entry
public void entry(Context context, ResourceWrapper resource, DefaultNode node, int count,
                  boolean prioritized, Object... args) throws Throwable {
    //检查gatway的限流参数
    checkGatewayParamFlow(resource, count, args);
	//下一个节点
    fireEntry(context, resource, node, count, prioritized, args);
}
4.1.4、ParamFlowSlot
//com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowSlot#entry
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                  boolean prioritized, Object... args) throws Throwable {
    //该资源没有参数限流规则,直接进入下个节点
    if (!ParamFlowRuleManager.hasRules(resourceWrapper.getName())) {
        //下个节点
        fireEntry(context, resourceWrapper, node, count, prioritized, args);
        return;
    }
	//校验
    checkFlow(resourceWrapper, count, args);
    //下个节点
    fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
4.1.5、FlowSlot
//com.alibaba.csp.sentinel.slots.block.flow.FlowSlot#entry
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                  boolean prioritized, Object... args) throws Throwable {
    //校验
    checkFlow(resourceWrapper, context, node, count, prioritized);
	//下个节点
    fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
4.1.6、DegradeSlot 最后一个slot
//com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot#entry
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                  boolean prioritized, Object... args) throws Throwable {
    //校验
    performChecking(context, resourceWrapper);
	//下个节点
    fireEntry(context, resourceWrapper, node, count, prioritized, args);
}

这里通过了,又回到StatisticSlot#entry。

4.2、通过的线程数

//com.alibaba.csp.sentinel.node.DefaultNode#increaseThreadNum
public void increaseThreadNum() {
    super.increaseThreadNum();
    this.clusterNode.increaseThreadNum();
}
//com.alibaba.csp.sentinel.node.StatisticNode#increaseThreadNum
private LongAdder curThreadNum = new LongAdder();
public void increaseThreadNum() {
    curThreadNum.increment();
}

4.3、增加通过的请求数

public void addPassRequest(int count) {
    super.addPassRequest(count);
    this.clusterNode.addPassRequest(count);
}
//com.alibaba.csp.sentinel.node.StatisticNode#addPassRequest
//两个监控指标,秒和分钟
private transient volatile Metric rollingCounterInSecond = new ArrayMetric(SampleCountProperty.SAMPLE_COUNT,IntervalProperty.INTERVAL);
private transient Metric rollingCounterInMinute = new ArrayMetric(60, 60 * 1000, false);
public void addPassRequest(int count) {
    rollingCounterInSecond.addPass(count);
    rollingCounterInMinute.addPass(count);
}
//com.alibaba.csp.sentinel.slots.statistic.metric.ArrayMetric#addPass
//滑动窗口
private final LeapArray<MetricBucket> data;
public void addPass(int count) {
    //获取当前窗口
    WindowWrap<MetricBucket> wrap = data.currentWindow();
    wrap.value().addPass(count);
}

增加对应窗口的计数

//com.alibaba.csp.sentinel.slots.statistic.data.MetricBucket#addPass
public void addPass(int n) {
    add(MetricEvent.PASS, n);
}

每个滑动窗口中的计数是使用这样的数组做的,不同事件时不同的数组元素,可以增加并发读写

LongAdder是一个线程安全的long。

//com.alibaba.csp.sentinel.slots.statistic.data.MetricBucket#add
private final LongAdder[] counters;
public MetricBucket add(MetricEvent event, long n) {
    counters[event.ordinal()].add(n);
    return this;
}

4.4、callback

MetricEntryCallback

请求通过 handler

//com.alibaba.csp.sentinel.metric.extension.callback.MetricEntryCallback#onPass
public void onPass(Context context, ResourceWrapper rw, DefaultNode param, int count, Object... args)
    throws Exception {
    //MetricExtensionProvider.getMetricExtensions() 没有东西
    for (MetricExtension m : MetricExtensionProvider.getMetricExtensions()) {
        if (m instanceof AdvancedMetricExtension) {
            ((AdvancedMetricExtension) m).onPass(rw, count, args);
        } else {
            m.increaseThreadNum(rw.getName(), args);
            m.addPass(rw.getName(), count, args);
        }
    }
}

ParamFlowStatisticEntryCallback

//com.alibaba.csp.sentinel.slots.statistic.ParamFlowStatisticEntryCallback#onPass
public void onPass(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, Object... args) {
    // The "hot spot" parameter metric is present only if parameter flow rules for the resource exist.
    ParameterMetric parameterMetric = ParameterMetricStorage.getParamMetric(resourceWrapper);
	//parameterMetric 是 null
    if (parameterMetric != null) {
        parameterMetric.addThreadCount(args);
    }
}

5、处理链的顺序

sentinel processSlot链中slot的顺序:NodeSelectorSlot --> ClusterBuilderSlot --> LogSlot --> StatisticSlot --> AuthoritySlot --> SystemSlot --> GatewayFlowSlot(集成gatway) --> ParamFlowSlot --> FlowSlot --> DegradeSlot

从AuthoritySlot 开始,后面会根据规则校验当前请求。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值