sentinel执行流程

一,规则的创建

FlowRuleManager.loadRules(rules) 流控
DegradeRuleManager.loadRules(rules);降级
AuthorityRuleManager.loadRules(rules);校验
重点:
static {
        currentProperty.addListener(LISTENER);//注册规则监听器
        startMetricTimerListener();//开启定时任务
       }


private static void startMetricTimerListener() {
//获取任务的时间间隔
        long flushInterval = SentinelConfig.metricLogFlushIntervalSec();
        if (flushInterval <= 0) {
            RecordLog.info("[FlowRuleManager] The MetricTimerListener isn't started. If you want to start it, "
                    + "please change the value(current: {}) of config({}) more than 0 to start it.", flushInterval,
                SentinelConfig.METRIC_FLUSH_INTERVAL);
            return;
        }
        SCHEDULER.scheduleAtFixedRate(new MetricTimerListener(), 0, flushInterval, TimeUnit.SECONDS);
    }
MetricTimerListener :
public class MetricTimerListener implements Runnable {

    private static final MetricWriter metricWriter = new MetricWriter(SentinelConfig.singleMetricFileSize(),
        SentinelConfig.totalMetricFileCount());

    @Override
    public void run() {
        Map<Long, List<MetricNode>> maps = new TreeMap<>();
        for (Entry<ResourceWrapper, ClusterNode> e : ClusterBuilderSlot.getClusterNodeMap().entrySet()) {
            ClusterNode node = e.getValue();
            Map<Long, MetricNode> metrics = node.metrics();
            aggregate(maps, metrics, node);
        }
        aggregate(maps, Constants.ENTRY_NODE.metrics(), Constants.ENTRY_NODE);
        if (!maps.isEmpty()) {
            for (Entry<Long, List<MetricNode>> entry : maps.entrySet()) {
                try {
                    metricWriter.write(entry.getKey(), entry.getValue());
                } catch (Exception e) {
                    RecordLog.warn("[MetricTimerListener] Write metric error", e);
                }
            }
        }
    }

    private void aggregate(Map<Long, List<MetricNode>> maps, Map<Long, MetricNode> metrics, ClusterNode node) {
        for (Entry<Long, MetricNode> entry : metrics.entrySet()) {
            long time = entry.getKey();
            MetricNode metricNode = entry.getValue();
            metricNode.setResource(node.getName());
            metricNode.setClassification(node.getResourceType());
            maps.computeIfAbsent(time, k -> new ArrayList<MetricNode>());
            List<MetricNode> nodes = maps.get(time);
            nodes.add(entry.getValue());
        }
    }

}



二,核心业务的入口

 entry = SphU.entry(KEY);key  为资源名称

三,加载spi扩展接口,进行环境初始化逻辑

List<InitFunc> initFuncs = SpiLoader.of(InitFunc.class).//对InitFunc接口的封装以及spiloader的缓存
loadInstanceListSorted()//  1,  使用类加载器(可能是当前线程的上下文加载器,也可能是该接口的加载器 根据SentinelConfig中的属性配置决定)加载META-INF/services/+接口的全名  文件获取该文件的url  获取其中配置的所有类,
2,而后根据反射机制进行类的加载,将获取到的class进行缓存
3,根据是否是单例模式,使用反射技术进行对象的创建并返回
不同点:在1.7版本中还会加载诸如发送心跳包之类的组件,在1.8中已经移除

 for(InitFunc initFunc : initFuncs) insertSorted(initList, initFunc)//根据注解中配置的顺序,对spi中的接口实现进行排序
for (OrderWrapper w : initList) w.func.init()//对spi扩展的实现一次调用其方法
1,拓展点com.alibaba.csp.sentinel.init.InitFunc的实现类  ##源码注释
com.alibaba.csp.sentinel.metric.extension.MetricCallbackInit  ##Register callbacks for metric extension.
2,com.alibaba.csp.sentinel.slotchain.ProcessorSlot的实现类 ##A container of some process and ways of notification when the process is finished.(责任链模式)
com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot
com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot
com.alibaba.csp.sentinel.slots.logger.LogSlot
com.alibaba.csp.sentinel.slots.statistic.StatisticSlot
com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot
com.alibaba.csp.sentinel.slots.system.SystemSlot
com.alibaba.csp.sentinel.slots.block.flow.FlowSlot
com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot
3,com.alibaba.csp.sentinel.slotchain.SlotChainBuilder的实现类  ##The builder for processor slot chain.(简化版的构建者模式)
com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder
Env.sph.entry(name, EntryType.OUT, 1, OBJECTS0)
四,开始业务逻辑所需的上下文准备
Env.sph.entry(name, EntryType.OUT, 1, OBJECTS0)
 经过对资源的封装之后会进入到com.alibaba.csp.sentinel.CtSph
entryWithPriority(com.alibaba.csp.sentinel.slotchain.ResourceWrapper, int, boolean, java.lang.Object...) 方法 该部分源码如下

 Context context = ContextUtil.getContext();//在当前线程中获取上下文容器(ThreadLocal)
        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.
            return new CtEntry(resourceWrapper, null, context);
        }

        if (context == null) {
            // Using default context.
            //使用默认的名字创建一个上下文容器 sentinel_default_context
            //最终会调用到com.alibaba.csp.sentinel.context.ContextUtil#trueEnter(String name, String origin)在这里面做了如下几件事
            1,DefaultNode node = new EntranceNode(new StringResourceWrapper(name, EntryType.IN), null);//见附件
            2,Constants.ROOT.##new EntranceNode(new StringResourceWrapper(ROOT_ID, EntryType.IN),new ClusterNode(ROOT_ID, ResourceTypeConstants.COMMON));
            addChild(node)
            3,Map<String, DefaultNode> newMap = new HashMap<>(contextNameNodeMap.size()+1);
              newMap.putAll(contextNameNodeMap);
              newMap.put(name, node);//缓存 容器名与节点
              contextNameNodeMap = newMap;
            4,context = new Context(node, name)//对节点与名称的一个封装
            5,contextHolder.set(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);
        }
//形成处理器链,最新版本使用spi机制进行创建
        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 {
        //进入责任链模式,每个节点处理自己的业务逻辑

1,NodeSelectorSlot :DefaultNode node = new DefaultNode(resourceWrapper, null)
2,clusterNode = new ClusterNode(resourceWrapper.getName(),resourceWrapper.getResourceType());
node.setClusterNode(clusterNode)
if (!"".equals(context.getOrigin())) {
 //  statisticNode = new StatisticNode();
 Node originNode = node.getClusterNode().getOrCreateOriginNode(context.getOrigin());
 context.getCurEntry().setOriginNode(originNode);
        }
3,StatisticSlot :entry()  核心点 
{
try {
            // Do some checking.  继续调用后面的环节,检查是否超过规则的限制,如果没有超过,则进行数据统计,否则进入异常的处理环节
            fireEntry(context, resourceWrapper, node, count, prioritized, args);

            // Request passed, add thread count and pass count.时间窗口算法
            node.increaseThreadNum();
            node.addPassRequest(count);

            if (context.getCurEntry().getOriginNode() != null) {
                // Add count for origin 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.
            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.
            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;
        }
    }
            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;
    }



五:后续的处理环节
fireEntry(context, resourceWrapper, node, count, prioritized, args);
以流量控制为例:
checkFlow(resourceWrapper, context, node, count, prioritized)
{
	checker.checkFlow(ruleProvider, resource, context, node, count, prioritized);
}


ruleProvider:  private final Function<String, Collection<FlowRule>> ruleProvider = new Function<String, Collection<FlowRule>>() {
        @Override
        public Collection<FlowRule> apply(String resource) {
            // Flow rule map should not be null.
            Map<String, List<FlowRule>> flowRules = FlowRuleManager.getFlowRuleMap();
            return flowRules.get(resource);
        }
    };

public void checkFlow(Function<String, Collection<FlowRule>> ruleProvider, ResourceWrapper resource,
                          Context context, DefaultNode node, int count, boolean prioritized) throws BlockException {
        if (ruleProvider == null || resource == null) {
            return;
        }
        Collection<FlowRule> rules = ruleProvider.apply(resource.getName());
        if (rules != null) {
            for (FlowRule rule : rules) {
                if (!canPassCheck(rule, context, node, count, prioritized)) {
                    throw new FlowException(rule.getLimitApp(), rule);
                }
            }
        }
    }

 public boolean canPassCheck(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node, int acquireCount,
                                                    boolean prioritized) {
        String limitApp = rule.getLimitApp();
        if (limitApp == null) {
            return true;
        }

//集群模式
        if (rule.isClusterMode()) {
            return passClusterCheck(rule, context, node, acquireCount, prioritized);
        }
//单机模式
        return passLocalCheck(rule, context, node, acquireCount, prioritized);
    }

private static boolean passLocalCheck(FlowRule rule, Context context, DefaultNode node, int acquireCount,
                                          boolean prioritized) {
        Node selectedNode = selectNodeByRequesterAndStrategy(rule, context, node);
        if (selectedNode == null) {
            return true;
        }

        return rule.getRater().canPass(selectedNode, acquireCount, prioritized);
    }



六,异常的处理环节




七,时间滑动门窗口

Metric rollingCounterInSecond = new ArrayMetric(SampleCountProperty.SAMPLE_COUNT,//2
      IntervalProperty.INTERVAL);//1000

public class ArrayMetric implements Metric{      
private final LeapArray<MetricBucket> data;
    public ArrayMetric(int sampleCount, int intervalInMs) {
        this.data = new OccupiableBucketLeapArray(sampleCount, intervalInMs);
    }
....省略其他部分
}
//通过的请求数目加一
rollingCounterInSecond.pass();
源码注释:Get total pass count. not include {@link #occupiedPass()}
public long pass() {
                 ## Get the bucket at current timestamp.
                  public WindowWrap<T> currentWindow() {
                       return currentWindow(TimeUtil.currentTimeMillis());
                  }

                  public WindowWrap<T> currentWindow(long timeMillis) {
                       //当前窗口所在桶索引[0,1)
                       int idx = calculateTimeIdx(timeMillis);
                       // Calculate current bucket start time.
                       long windowStart = calculateWindowStart(timeMillis);
                               while (true) {
                WindowWrap<T> old = array.get(idx);
            if (old == null) {
            //新建一个桶,并原子性的更新
                       WindowWrap<T> window = new WindowWrap<T>(windowLengthInMs, 	        windowStart, newEmptyBucket(timeMillis));
                       if (array.compareAndSet(idx, null, window)) {
                      // Successfully updated, return the created bucket.
                       return window;
                      } else {
                    // Contention failed, the thread will yield its time slice to wait for bucket available.
                      Thread.yield();
                }
                }
                } else if (windowStart == old.windowStart()) {
                 return old;
                } else if (windowStart > old.windowStart()) {
if (updateLock.tryLock()) {
                    try {
                        // Successfully get the update lock, now we reset the bucket.  
                        //当前时间戳在当前窗口期,更新窗口信息
                        return resetWindowTo(old, windowStart);
                         //
protected WindowWrap<MetricBucket> resetWindowTo(WindowWrap<MetricBucket> w, long time) {
        // Update the start time and reset value.
        w.resetTo(time);
        MetricBucket borrowBucket = borrowArray.getWindowValue(time);
        if (borrowBucket != null) {
            w.value().reset();
            //通过的请求统计
            w.value().addPass((int)borrowBucket.pass());
        } else {
            w.value().reset();
        }

        return w;
    }


                    } finally {
                        updateLock.unlock();
                    }
                } else {
                    // Contention failed, the thread will yield its time slice to wait for bucket available.
                    Thread.yield();
                }
            } 
                 else if (windowStart < old.windowStart()) {
                // Should not go through here, as the provided time is already behind.
                return new WindowWrap<T>(windowLengthInMs, windowStart,newEmptyBucket(timeMillis));
            }
        }
    }
        data.currentWindow();

        long pass = 0;
        List<MetricBucket> list = data.values();

        for (MetricBucket window : list) {
            pass += window.pass();
        }
        return pass;
    }


附:EntranceNode
在这里插入图片描述
Context:
在这里插入图片描述
1.7中使用spi机制加载的InitFunc组件
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值