美文网首页
sentinel设计思想

sentinel设计思想

作者: 自由人_ded7 | 来源:发表于2020-03-06 16:06 被阅读0次

    首先我们看一下Sentinel项目的整个结构:version:1.6.0
    * sentinel-core 核心模块,限流、降级、系统保护等都在这里实现
    * sentinel-dashboard 控制台模块,可以对连接上的sentinel客户端实现可视化的管理
    * sentinel-transport 传输模块,提供了基本的监控服务端和客户端的API接口,以及一些基于不同库的实现
    * sentinel-extension 扩展模块,主要对DataSource进行了部分扩展实现
    * sentinel-adapter 适配器模块,主要实现了对一些常见框架的适配
    * sentinel-demo 样例模块,可参考怎么使用sentinel进行限流、降级等
    * sentinel-benchmark 基准测试模块,对核心代码的精确性提供基准测试

    底层原理:sentinel 入口是 SphU.entry创建

    private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)
    
        throws BlockException {
    
        Context context = ContextUtil.getContext();
    
        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.
    
            context = MyContextUtil.myEnter(Constants.CONTEXT\_DEFAULT\_NAME, "", resourceWrapper.getType());
    
        }
    
      
    
      
    
        // Global switch is close, no rule checking will do.
    
        if (!Constants.ON) {
    
            return new CtEntry(resourceWrapper, null, context);
    
        }
    
      
    
      
    
        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 {
    
            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;
    
    }
    

    这个方法可以分为以下几个部分:
    * 1.对参数和全局配置项做检测,如果不符合,不会再进行后面的限流检测,否则进入下面的检测流程。
    * 2.根据包装过的资源对象获取对应的SlotChain
    * 3.执行SlotChain的entry方法

        * 3.1.如果SlotChain的entry方法抛出了BlockException,则将该异常继续向上抛出
        * 3.2.如果SlotChain的entry方法正常执行了,则最后会将该entry对象返回
    * 4.如果上层方法捕获了BlockException,则说明请求被限流了,否则请求能正常执行
    

    其中比较重要的是第2、3两个步骤,我们来分解一下这两个步骤。创建SlotChain默认的实现类为 DefaultProcessorSlotChain:链表实现的责任链

    private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)
    
        throws BlockException {
    
        Context context = ContextUtil.getContext();
    
        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.
    
            context = MyContextUtil.myEnter(Constants.CONTEXT\_DEFAULT\_NAME, "", resourceWrapper.getType());
    
        }
    
      
    
      
    
        // Global switch is close, no rule checking will do.
    
        if (!Constants.ON) {
    
            return new CtEntry(resourceWrapper, null, context);
    
        }
    
      
    
      
    
        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 {
    
            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;
    
    }
    
    * NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;
    * ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;
    * StatistcSlot 则用于记录,统计不同纬度的 runtime 信息;
    * FlowSlot 则用于根据预设的限流规则,以及前面 slot 统计的状态,来进行限流;
    * AuthorizationSlot 则根据黑白名单,来做黑白名单控制;
    * DegradeSlot 则通过统计信息,以及预设的规则,来做熔断降级;
    * SystemSlot 则通过系统的状态,例如 load1 等,来控制总的入口流量;
    * 
    

    执行完业务逻辑处理后,调用了fireEntry()方法,由此触发了下一个节点的entry方法。此时我们就知道了sentinel的责任链就是这样传递的:每个Slot节点执行完自己的业务后,会调用fireEntry来触发下一个节点的entry方法。

    相关文章

      网友评论

          本文标题:sentinel设计思想

          本文链接:https://www.haomeiwen.com/subject/yjtwrhtx.html