美文网首页
Alibaba Sentinel DegradeRule 降级规

Alibaba Sentinel DegradeRule 降级规

作者: xiaolyuh | 来源:发表于2020-09-10 16:23 被阅读0次

    降级方式

    image.png

    Alibaba Sentinel 支持多种降级方式:

    1. 根据响应时间:判断单位时间内平均响应时间是否达到阈值;
    2. 根据异常比例:判断单位时间内,异常数量和异常比例是否达到阈值;
    3. 根据异常数量:判断单位时间内异常数量是否达到阈值;

    一旦触发熔断,熔断开关将会打开,这时将拒绝所有请求,拒绝时间为设置的降级时间间隔。通过源码我们可以发现,Sentinel直接使用的是ScheduledExecutorService开启的一个延迟任务来实现降级时间间隔。

    如:响应时间达到阈值,并且熔断时间间隔配置为5S,这时熔断开关会打开,并且在5S内拒绝所有请求,当5S后熔断开关再次关闭,这时会放行请求,如果放行请求后又触发了熔断,那么又需要等5S钟。

    熔断降级规则说明

    熔断降级规则(DegradeRule)包含下面几个重要的属性:

    Field 说明 默认值
    resource 资源名,即规则的作用对象
    grade 熔断策略,支持慢调用比例/异常比例/异常数策略 慢调用比例
    count 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
    timeWindow 熔断时长,单位为 s
    minRequestAmount 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) 5
    statIntervalMs 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) 1000 ms
    slowRatioThreshold 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)

    最新参数请看官网

    源码

    public class DegradeRule extends AbstractRule {
    
        @SuppressWarnings("PMD.ThreadPoolCreationRule")
        private static ScheduledExecutorService pool = Executors.newScheduledThreadPool(
            Runtime.getRuntime().availableProcessors(), new NamedThreadFactory("sentinel-degrade-reset-task", true));
    
        public DegradeRule() {}
    
        public DegradeRule(String resourceName) {
            setResource(resourceName);
        }
    
        /**
         * RT threshold or exception ratio threshold count.
         */
        private double count;
    
        /**
         * Degrade recover timeout (in seconds) when degradation occurs.
         */
        private int timeWindow;
    
        /**
         * Degrade strategy (0: average RT, 1: exception ratio, 2: exception count).
         */
        private int grade = RuleConstant.DEGRADE_GRADE_RT;
    
        /**
         * Minimum number of consecutive slow requests that can trigger RT circuit breaking.
         *
         * @since 1.7.0
         */
        private int rtSlowRequestAmount = RuleConstant.DEGRADE_DEFAULT_SLOW_REQUEST_AMOUNT;
    
        /**
         * Minimum number of requests (in an active statistic time span) that can trigger circuit breaking.
         *
         * @since 1.7.0
         */
        private int minRequestAmount = RuleConstant.DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT;
    
        ...
    
        // Internal implementation (will be deprecated and moved outside).
    
        private AtomicLong passCount = new AtomicLong(0);
        private final AtomicBoolean cut = new AtomicBoolean(false);
    
        @Override
        public boolean passCheck(Context context, DefaultNode node, int acquireCount, Object... args) {
            // 判断熔断开关的状态
            if (cut.get()) {
                return false;
            }
    
            ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(this.getResource());
            if (clusterNode == null) {
                return true;
            }
    
            if (grade == RuleConstant.DEGRADE_GRADE_RT) {  // 基于RT的熔断模式
                // 获取平均RT
                double rt = clusterNode.avgRt();
                // 判断平均RT是否达到阈值,如果没有就放行
                if (rt < this.count) {
                    passCount.set(0);
                    return true;
                }
    
                // 如果RT达到阈值,还需要判断单位时间内请求量是否达到阈值(默认是5)
                if (passCount.incrementAndGet() < rtSlowRequestAmount) {
                    return true;
                }
            } else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) { // 基于异常比例的熔断策略
                double exception = clusterNode.exceptionQps();
                double success = clusterNode.successQps();
                double total = clusterNode.totalQps();
                // If total amount is less than minRequestAmount, the request will pass.
                // 判断单位时间内请求数量是否发到熔断阈值(默认5)
                if (total < minRequestAmount) {
                    return true;
                }
    
                // In the same aligned statistic time window,
                // "success" (aka. completed count) = exception count + non-exception count (realSuccess)
                double realSuccess = success - exception;
                // 判断单位时间内异常请求数量是否达到阈值
                if (realSuccess <= 0 && exception < minRequestAmount) {
                    return true;
                }
                // 判断异常比例是否达到阈值
                if (exception / success < count) {
                    return true;
                }
            } else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) { // 基于异常数量的熔断策略
                double exception = clusterNode.totalException();
                // 判断异常数量是否达到阈值
                if (exception < count) {
                    return true;
                }
            }
    
            if (cut.compareAndSet(false, true)) {
                ResetTask resetTask = new ResetTask(this);
                pool.schedule(resetTask, timeWindow, TimeUnit.SECONDS);
            }
    
            return false;
        }
    
        private static final class ResetTask implements Runnable {
    
            private DegradeRule rule;
    
            ResetTask(DegradeRule rule) {
                this.rule = rule;
            }
    
            @Override
            public void run() {
                rule.passCount.set(0);
                rule.cut.set(false);
            }
        }
    }
    

    基于RT的熔断流程图:

    image.png

    总结

    1. 有一个值得借鉴的地方,使用ScheduledExecutorService来实现延迟任务的执行。
    2. 基于RT的熔断,框架是基于所有请求的平均响应时间来实现的,这种方式不会产生上下文切换。还有一种简单的方式,这种方式采用FutureTask机制,但是会产生上下文切换,如:
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    FutureTask<String> futureTask = new FutureTask<String>(() -> {
        // 业务逻辑
        return "处理结果";
    });
    executorService.submit(futureTask);
    futureTask.get(5, TimeUnit.SECONDS);
    

    相关文章

      网友评论

          本文标题:Alibaba Sentinel DegradeRule 降级规

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