美文网首页sentinel
sentinel-限流篇

sentinel-限流篇

作者: Audience0 | 来源:发表于2019-08-01 16:53 被阅读0次

官方文档:https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5
开发五步骤:
1.依赖

<!--sentinel核心包,从1.5.0开始仅支持JDK1.7以上版本,1.5.0之前的版本最低支持JDK1.6-->
       <dependency>
           <groupId>com.alibaba.csp</groupId>
           <artifactId>sentinel-core</artifactId>
           <version>1.6.2</version>
       </dependency>

       <!--sentinel Annotation AspectJ  扩展-->
       <dependency>
           <groupId>com.alibaba.csp</groupId>
           <artifactId>sentinel-annotation-aspectj</artifactId>
           <version>1.6.2</version>
       </dependency>
       <!--客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信-->
       <dependency>
           <groupId>com.alibaba.csp</groupId>
           <artifactId>sentinel-transport-simple-http</artifactId>
           <version>1.6.2</version>
       </dependency>

2.XML 配置

<!--sentinel 切面-->
<bean id="sentinelResourceAspect" class="com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect"></bean>
<!--使sentinel中的 aspectJ注解生效-->
<aop:aspectj-autoproxy proxy-target-class="false"/><!--声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面,true使用CGLib动态代理技术织入增强,false表示使用jdk动态代理织入增强-->

3.定义资源

@SentinelResource(value = "annotationHandlerMethod" , blockHandler = "annotationHandlerMethod",blockHandlerClass = HandlerFallUtils.class)

4.定义规则

FlowRuleManager.loadRules(Arrays.asList(new FlowRule("annotationHandlerMethod")));

5.定义降级方法

/**
     * 需要public static 参数需要多一个BlockException
     * @param i
     * @param d
     * @return
     */
    public static String annotationHandlerMethod(int i,BlockException d){
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return i + "=execute annotationHandlerMethod--fall:"+d.getMessage();
    

限流方式(流控控制效果)
1.直接拒绝
默然是直接拒绝,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,抛出FlowException.
2.Warm up

FlowRule rule = new FlowRule();
rule.setResource(resourceName);
rule.setCount(20);
rule.setGrade(RuleConstant.GRADE_QPS);
rule.setLimitApp("default");
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
//warm up方式需要制定,表示经过WarmUpPeriodSec 秒的时间将使QPS达到设定的count值
rule.setWarmUpPeriodSec(10);
图片.png

3.均匀排队

rule.setGrade(RuleConstant.GRADE_QPS);
/ /流控效果:匀速排队模式
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER); 
//表示一秒内均匀通过10个请求
rule.setCount(10);
rule.setMaxQueueingTimeMs(20 * 1000); // 最长排队等待时间:20s

以固定的间隔时间让请求通过。当请求到来的时候,如果当前请求距离上个通过的请求通过的时间间隔不小于预设值,则让当前请求通过;否则,计算当前请求的预期通过时间,如果该请求的预期通过时间小于规则预设的 timeout 时间,则该请求会等待直到预设时间到来通过;反之,则马上抛出阻塞异常。


限流过程
1.规则刷新 --> FlowRuleManager.loadRules
涉及FlowRuleManager,FlowRuleUtil,DynamicSentinelProperty

public class FlowRuleManager {
    //规则存放Map
   private static final Map<String, List<FlowRule>> flowRules = new ConcurrentHashMap<String, List<FlowRule>>();

    private static final FlowPropertyListener LISTENER = new FlowPropertyListener();
    private static SentinelProperty<List<FlowRule>> currentProperty = new DynamicSentinelProperty<List<FlowRule>>();
  
    static {
        currentProperty.addListener(LISTENER);
        SCHEDULER.scheduleAtFixedRate(new MetricTimerListener(), 0, 1, TimeUnit.SECONDS);
    }
  //更新规则
  public static void loadRules(List<FlowRule> rules) {
        currentProperty.updateValue(rules);
    }
  //获取限流规则
  static Map<String, List<FlowRule>> getFlowRuleMap() {
        return flowRules;
    }
  //规则加载主要逻辑
  private static final class FlowPropertyListener implements PropertyListener<List<FlowRule>> {

        @Override
        //更新规则
        public void configUpdate(List<FlowRule> value) {
            //校验FlowRule
            //赋值rule.setRater(TrafficShapingController) 限流处理类
            //按key 资源名称,value 规则列表封装Map返回
            Map<String, List<FlowRule>> rules = FlowRuleUtil.buildFlowRuleMap(value);
            if (rules != null) {
                //更新规则列表前,清楚原列表所有规则
                flowRules.clear();
                flowRules.putAll(rules);
            }
            RecordLog.info("[FlowRuleManager] Flow rules received: " + flowRules);
        }

        @Override
        //初始化时执行
        public void configLoad(List<FlowRule> conf) {
            Map<String, List<FlowRule>> rules = FlowRuleUtil.buildFlowRuleMap(conf);
            if (rules != null) {
                flowRules.clear();
                flowRules.putAll(rules);
            }
            RecordLog.info("[FlowRuleManager] Flow rules loaded: " + flowRules);
        }
    }
}
  

2.处理资源请求 -->SentinelResourceAspect

@Aspect
public class SentinelResourceAspect extends AbstractSentinelAspectSupport {

    @Pointcut("@annotation(com.alibaba.csp.sentinel.annotation.SentinelResource)")
    public void sentinelResourceAnnotationPointcut() {
    }

    @Around("sentinelResourceAnnotationPointcut()")
    public Object invokeResourceWithSentinel(ProceedingJoinPoint pjp) throws Throwable {
        //获取当前资源方法
        Method originMethod = resolveMethod(pjp);
        //获取资源注解配置
        SentinelResource annotation = originMethod.getAnnotation(SentinelResource.class);
        if (annotation == null) {
            // Should not go through here.
            throw new IllegalStateException("Wrong state for SentinelResource annotation");
        }
        //获取资源名
        String resourceName = getResourceName(annotation.value(), originMethod);
        EntryType entryType = annotation.entryType();
        Entry entry = null;
        try {
            //如果限流则抛出 FlowException 异常
            entry = SphU.entry(resourceName, entryType, 1, pjp.getArgs());
            //调用资源方法
            Object result = pjp.proceed();
            return result;
        } catch (BlockException ex) {
            //降级的handlerBlock方法
            return handleBlockException(pjp, annotation, ex);
        } catch (Throwable ex) {
            //获取配置的忽略异常,即改异常不会被降级,会直接抛出
            Class<? extends Throwable>[] exceptionsToIgnore = annotation.exceptionsToIgnore();
            //判断当前异常是否为exceptionsToIgnore中的异常或exceptionsToIgnore异常的子类,是的话直接抛出
            if (exceptionsToIgnore.length > 0 && exceptionBelongsTo(ex, exceptionsToIgnore)) {
                throw ex;
            }
            // annotation.exceptionsToTrace()  默认值Throwable.class
            // 非exceptionsToIgnore中,但在exceptionsToTrace中的异常才会进行fallback降级
            if (exceptionBelongsTo(ex, annotation.exceptionsToTrace())) {
                //统计异常信息
                traceException(ex, annotation);
                //fallback方法
                return handleFallback(pjp, annotation, ex);
            }

            // No fallback function can handle the exception, so throw it out.
            throw ex;
        } finally {
            if (entry != null) {
                entry.exit(1, pjp.getArgs());
            }
        }
    }
}

handlerblock方法 和 fallback方法调用实现如下:

public abstract class AbstractSentinelAspectSupport {

  /**
     * 1.blockHandlerMethod 方法 必须更加一个 BlockException类型的参数
     * 2.根据是否为静态方法来区分调用的是本类的降级方法,还是指定类的,所以指定类的降级方法必须要是static类型
     * 3.如果未配置blockHandlerMethod方法,兜底fallback方法
     */
    protected Object handleBlockException(ProceedingJoinPoint pjp, SentinelResource annotation, BlockException ex)
        throws Throwable {

        // Execute block handler if configured.
        //获取降级方法
        Method blockHandlerMethod = extractBlockHandlerMethod(pjp, annotation.blockHandler(),
            annotation.blockHandlerClass());
        if (blockHandlerMethod != null) {
            Object[] originArgs = pjp.getArgs();
            // Construct args.
            Object[] args = Arrays.copyOf(originArgs, originArgs.length + 1);
            //所以handler方法必须加上BlockException 参数
            args[args.length - 1] = ex;
            //是否是静态的
            if (isStatic(blockHandlerMethod)) {
                return blockHandlerMethod.invoke(null, args);
            }
            return blockHandlerMethod.invoke(pjp.getTarget(), args);
        }

        // If no block handler is present, then go to fallback.
        return handleFallback(pjp, annotation, ex);
    }
       /**
     * 1.Fallback 方法 可以增加一个 Throwable类型的参数,也可以不加
     * 2.根据是否为静态方法来区分调用的是本类的降级方法,还是指定类的,所以指定类的降级方法必须要是static类型
     * 3.如果未配置fallback方法,兜底defaultFallback方法
     */
    protected Object handleFallback(ProceedingJoinPoint pjp, String fallback, String defaultFallback,
                                    Class<?>[] fallbackClass, Throwable ex) throws Throwable {
        //资源方法参数
        Object[] originArgs = pjp.getArgs();

        // 获取配置的fallback方法
        Method fallbackMethod = extractFallbackMethod(pjp, fallback, fallbackClass);
        if (fallbackMethod != null) {
            // 降级方法参数
            int paramCount = fallbackMethod.getParameterTypes().length;
            Object[] args;

            if (paramCount == originArgs.length) {
                //降级方法参数 和 资源方法参数长度一致
                args = originArgs;
            } else {
                //降级方法参数 和 资源方法参数长度不一致,则降级方法增加一个Throwable 类型的参数
                args = Arrays.copyOf(originArgs, originArgs.length + 1);
                args[args.length - 1] = ex;
            }
            //是否是静态方法
            if (isStatic(fallbackMethod)) {
                return fallbackMethod.invoke(null, args);
            }
            return fallbackMethod.invoke(pjp.getTarget(), args);
        }
        // 如果fallback方法未配置,则尝试调用defaultFallback方法,如果配置了的话
        return handleDefaultFallback(pjp, defaultFallback, fallbackClass, ex);
    }
    /**
     * 1.defaultFallback 方法  参数为  无参数 或一个Throwable的参数
     * 2.根据是否为静态方法来区分调用的是本类的降级方法,还是指定类的,所以指定类的降级方法必须要是static类型
     * 3.如果未配置defaultFallback方法,则抛出异常
     */
    protected Object handleDefaultFallback(ProceedingJoinPoint pjp, String defaultFallback,
                                           Class<?>[] fallbackClass, Throwable ex) throws Throwable {
        // Execute the default fallback function if configured.
        Method fallbackMethod = extractDefaultFallbackMethod(pjp, defaultFallback, fallbackClass);
        if (fallbackMethod != null) {
            // Construct args.
            Object[] args = fallbackMethod.getParameterTypes().length == 0 ? new Object[0] : new Object[] {ex};
            if (isStatic(fallbackMethod)) {
                return fallbackMethod.invoke(null, args);
            }
            return fallbackMethod.invoke(pjp.getTarget(), args);
        }

        // If no any fallback is present, then directly throw the exception.
        throw ex;
    }
}

3.限流过程 StatisticSlot
StatisticSlot 系统流程--判断是否降级,数据统计

public class StatisticSlot extends AbstractLinkedProcessorSlot<DefaultNode> {

    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                      boolean prioritized, Object... args) throws Throwable {
        try {
            // 去校验限流,系统保护,黑白名单,熔断
            fireEntry(context, resourceWrapper, node, count, prioritized, args);

            // 校验通过 统计数据  DefaultNode
            node.increaseThreadNum();
            node.addPassRequest(count);
            //只有配置了指定context的来源时才会StatisticNode不为null
            if (context.getCurEntry().getOriginNode() != null) {
                // 统计数据  StatisticNode
                context.getCurEntry().getOriginNode().increaseThreadNum();
                context.getCurEntry().getOriginNode().addPassRequest(count);
            }
            //EntryType.IN 入口流量
            if (resourceWrapper.getType() == 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.getType() == 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().setError(e);

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

            if (resourceWrapper.getType() == 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 error, set error to current entry.
            context.getCurEntry().setError(e);

            // This should not happen.
            node.increaseExceptionQps(count);
            if (context.getCurEntry().getOriginNode() != null) {
                context.getCurEntry().getOriginNode().increaseExceptionQps(count);
            }

            if (resourceWrapper.getType() == EntryType.IN) {
                Constants.ENTRY_NODE.increaseExceptionQps(count);
            }
            throw e;
        }
    }
}

4.限流判断 FlowSlot ,FlowRuleChecker
校验过程
1)获取该资源配置的规则

public class FlowRuleChecker {
  //判断是否限流。如果限流抛出FlowException异常
  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;
        }
        //获取对应资源的规则,通过 FlowRuleManager.getFlowRuleMap()获取
        Collection<FlowRule> rules = ruleProvider.apply(resource.getName());
        if (rules != null) {
            //遍历每条规则,所以,每个资源可以配置多个规则,进行多次校验,有一个规则不通过,则进行限流
            for (FlowRule rule : rules) {
                if (!canPassCheck(rule, context, node, count, prioritized)) {
                    //限流抛出的异常未FlowException
                    throw new FlowException(rule.getLimitApp(), rule);
                }
            }
        }
    }
}

2)未做集群配置,则进行本地限流校验

public class FlowRuleChecker {
  //本地限流校验,prioritized :false ,acquireCount:1
  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;
        }
        //FlowRuleUtil.buildFlowRuleMap   rule.getRater() 赋值   DefaultController
        return rule.getRater().canPass(selectedNode, acquireCount, prioritized);
    }
}

3)进行限流校验

public class DefaultController implements TrafficShapingController {
    
     public boolean canPass(Node node, int acquireCount, boolean prioritized) {
        //QPS  or ThreadNum
        //获取当前时间窗体调用次数
        int curCount = avgUsedTokens(node);
        //count  规则配置QPS,acquireCount 本次调用量 1次,curCount当前时间窗体里已经有的调用次数
        if (curCount + acquireCount > count) {
            //prioritized  写死为false
            if (prioritized && grade == RuleConstant.FLOW_GRADE_QPS) {
                 ......
                }
            }
            return false;
        }
        return true;
    }
    //获取当前时间窗体调用次数
    private int avgUsedTokens(Node node) {
        if (node == null) {
            return DEFAULT_AVG_USED_TOKENS;
        }
        return grade == RuleConstant.FLOW_GRADE_THREAD ? node.curThreadNum() : (int)(node.passQps());
    }
}

4)获取当前秒的调用次数 StatisticNode,ArrayMetric,LeapArray

public class StatisticNode implements Node {
      //SAMPLE_COUNT 2   INTERVAL 1000MS
    private transient volatile Metric rollingCounterInSecond = new ArrayMetric(SampleCountProperty.SAMPLE_COUNT,
        IntervalProperty.INTERVAL);

    @Override
    //获取当前秒调用次数
    public double passQps() {
        return rollingCounterInSecond.pass() / rollingCounterInSecond.getWindowIntervalInSec();
    }
}
public class ArrayMetric implements Metric {
    //统计数据
    private final LeapArray<MetricBucket> data;
    //创建ArrayMetric 赋值data   OccupiableBucketLeapArray类型
    public ArrayMetric(int sampleCount, int intervalInMs) {
        this.data = new OccupiableBucketLeapArray(sampleCount, intervalInMs);
    }

    //当前秒 调用次数
    public long pass() {
        //获取当前时间段
        data.currentWindow();
        long pass = 0;
        List<MetricBucket> list = data.values();
        for (MetricBucket window : list) {
            //计算总调用次数
            pass += window.pass();
        }
        return pass;
    }

    //1000ms 转换为1s
    public double getWindowIntervalInSec() {
        return data.getIntervalInSecond();
    }
}
public abstract class LeapArray<T> {
     //时间段长度
    protected int windowLengthInMs; 
    //intervalInMs 时间段个数
    protected int sampleCount;
    protected int intervalInMs;
    //存储窗体数据
    protected final AtomicReferenceArray<WindowWrap<T>> array;
    
    public LeapArray(int sampleCount, int intervalInMs) {
        this.windowLengthInMs = intervalInMs / sampleCount;
        this.intervalInMs = intervalInMs;
        this.sampleCount = sampleCount;
        this.array = new AtomicReferenceArray<>(sampleCount);
    }
    //根据当前时间获取当前秒的时间窗体数据
    public WindowWrap<T> currentWindow(long timeMillis) {//timeMillis 当前时间
        if (timeMillis < 0) {
            return null;
        }
        //计算时间段数组的下标
        int idx = calculateTimeIdx(timeMillis);
        //获取当前时间段的开始时间
        long windowStart = calculateWindowStart(timeMillis);
        while (true) {
            //从数组中获取时间窗体
            WindowWrap<T> old = array.get(idx);
            if (old == null) {
                //当前时间窗不存在,根据时间长度,开始时间初始化窗体,并赋值到数据idx处
                WindowWrap<T> window = new WindowWrap<T>(windowLengthInMs, windowStart, newEmptyBucket(timeMillis));
                if (array.compareAndSet(idx, null, window)) {
                    // 更新窗体并返回
                    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 {
                        return resetWindowTo(old, windowStart);
                    } finally {
                        updateLock.unlock();
                    }
                } else {
                    Thread.yield();
                }
            } else if (windowStart < old.windowStart()) {//不存在的情况
                return new WindowWrap<T>(windowLengthInMs, windowStart, newEmptyBucket(timeMillis));
            }
        }
    }
}

Context 上线文对象的初始化

1.Context的创建

// 自动创建
context = MyContextUtil.myEnter(Constants.CONTEXT_DEFAULT_NAME, "", resourceWrapper.getType());
 //手动创建
ContextUtil.enter(String name , String origin)

实际是调用以下方法创建context

public class ContextUtil {
    protected static Context trueEnter(String name, String origin) {
        Context context = contextHolder.get();//contextHolder  ThreadLocal
        if (context == null) {
            Map<String, DefaultNode> localCacheNameMap = contextNameNodeMap;
            DefaultNode node = localCacheNameMap.get(name);
            if (node == null) {
                if (localCacheNameMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) {
                    setNullContext();
                    return NULL_CONTEXT;
                } else {
                    try {
                        LOCK.lock();
                        node = contextNameNodeMap.get(name);
                        if (node == null) {
                            if (contextNameNodeMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) {
                                setNullContext();
                                return NULL_CONTEXT;
                            } else {
                                node = new EntranceNode(new StringResourceWrapper(name, EntryType.IN), null);
                                // Add entrance node.
                                Constants.ROOT.addChild(node);

                                Map<String, DefaultNode> newMap = new HashMap<>(contextNameNodeMap.size() + 1);
                                newMap.putAll(contextNameNodeMap);
                                newMap.put(name, node);
                                contextNameNodeMap = newMap;
                            }
                        }
                    } finally {
                        LOCK.unlock();
                    }
                }
            }
            //conext 创建,初始化context APPName, EntranceNode入口节点
            context = new Context(node, name);
            context.setOrigin(origin);
            contextHolder.set(context);
        }
        return context;
    }
}

2.context 的Entry初始化

   Entry e = new CtEntry(resourceWrapper, chain, context);

context 的entry初始化

class CtEntry extends Entry {
     CtEntry(ResourceWrapper resourceWrapper, ProcessorSlot<Object> chain, Context context) {
        super(resourceWrapper);
        this.chain = chain;
        this.context = context;

        setUpEntryFor(context);
    }
    //context 的entry初始化
    private void setUpEntryFor(Context context) {
        // The entry should not be associated to NullContext.
        if (context instanceof NullContext) {
            return;
        }
        this.parent = context.getCurEntry();
        if (parent != null) {
            ((CtEntry)parent).child = this;
        }
        context.setCurEntry(this);
    }
}

ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);初始化

public ProcessorSlotChain build() {
        ProcessorSlotChain chain = new DefaultProcessorSlotChain();
        //Context的DefaultNode初始化
        chain.addLast(new NodeSelectorSlot());
        //context中的Entry的CurNode中挂的clusterNode 赋值,originNode赋值
        chain.addLast(new ClusterBuilderSlot());
        //BlockException异常日志
        chain.addLast(new LogSlot());
        //流程
        chain.addLast(new StatisticSlot());
        //系统保护
        chain.addLast(new SystemSlot());
        //黑白名单
        chain.addLast(new AuthoritySlot());
        //限流
        chain.addLast(new FlowSlot());
        //熔断
        chain.addLast(new DegradeSlot());
        return chain;
    }

chain初始化结构如下: 每一个资源对应一个chainSlot


image.png

接下来,会依次执行next节点类的entry方法.
1)NodeSelectorSlot : Context的DefaultNode初始化
以context name 为key 保存DefaultNode,即DefaultNode保存着某个resource在某个context中的实时指标,每个DefaultNode都指向一个ClusterNode

public class NodeSelectorSlot extends AbstractLinkedProcessorSlot<Object> {

    private volatile Map<String, DefaultNode> map = new HashMap<String, DefaultNode>(10);

    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)
        throws Throwable {
       
        //以context name 为key  保存DefaultNode
        DefaultNode node = map.get(context.getName());
        if (node == null) {
            synchronized (this) {
                node = map.get(context.getName());
                if (node == null) {
                    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
                ((DefaultNode)context.getLastNode()).addChild(node);
            }
        }
        //初始化context 中Entry 的curNode值 DefaultNode
        context.setCurNode(node);
        //下一个entry
        fireEntry(context, resourceWrapper, node, count, prioritized, args);
    }
}

2)ClusterBuilderSlot :context中的Entry的CurNode中挂的clusterNode 赋值,originNode赋值
ClusterNode 以资源来key保存在map中.
ClusterNode:保存着某个resource在所有的context中实时指标的总和,同样的resource会共享同一个ClusterNode,不管他在哪个context中

public class ClusterBuilderSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
    //同样的资源获取同样的clusterNode  ResourceWrapper 重写hashCode equal方法,所以资源名一致则表示同一个资源
    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 = new ClusterNode();
                    HashMap<ResourceWrapper, ClusterNode> newMap = new HashMap<>(Math.max(clusterNodeMap.size(), 16));
                    newMap.putAll(clusterNodeMap);
                    // DefaultNode的资源为map的key
                    newMap.put(node.getId(), clusterNode);
                    clusterNodeMap = newMap;
                }
            }
        }
        //context中的Entry的CurNode中挂的clusterNode 赋值
        node.setClusterNode(clusterNode);
        if (!"".equals(context.getOrigin())) {
            //通过origin创建 OriginNode即StatisticNode,以origin为key存储在map中
            Node originNode = node.getClusterNode().getOrCreateOriginNode(context.getOrigin());
            context.getCurEntry().setOriginNode(originNode);
        }
        //下一个entry方法
        fireEntry(context, resourceWrapper, node, count, prioritized, args);
    }
}

至此Context初始化完成

相关文章

  • sentinel-限流篇

    官方文档:https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E...

  • sentinel-熔断篇

    1.规则定义: 2.规则加载 DegradeRuleManager.loadRules 3.熔断校验Degrade...

  • 聊聊高并发系统之限流特技-2

    摘要:上一篇《聊聊高并发系统限流特技-1》讲了限流算法、应用级限流、分布式限流;本篇将介绍接入层限流实现。 接入层...

  • 聊聊高并发系统限流特技-2

    转载来自开涛的聊聊高并发系统限流特技-2 上一篇《聊聊高并发系统限流特技-1》讲了限流算法、应用级限流、分布式限流...

  • Alibaba Sentinel 限流与滑动时间窗口

    之前发过一篇文章,介绍了alibaba Sentinel限流功能。Alibaba Sentinel限流功能[htt...

  • 来谈谈限流-RateLimiter源码分析

    前一篇文章提到了限流的几种常见算法,本文将分析guava限流类RateLimiter的实现。 RateLimite...

  • RPC(十二:Sentinel )

    上一篇我们简单介绍了Sentinel如何使用,并演示如何限流,这篇继续其他功能的介绍吧。Sentinel限流 关联...

  • Sentinel 实战-限流篇

    逅弈 转载请注明原创出处,谢谢! 系列文章 Sentinel 原理-全解析Sentinel 原理-调用链Senti...

  • 高并发环境下的限流策略

    本文将从以下几个方面分析限流策略: 什么是限流限流算法限流算法的应用 什么是限流 在开发高并发系统时,有很多手段来...

  • 限流框架系列之常见限流算法

    四种常见的限流算法 固定时间窗口限流算法 滑动时间窗口限流算法 令牌桶限流算法 漏桶限流算法 算法比较 算法确定参...

网友评论

    本文标题:sentinel-限流篇

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