zoukankan      html  css  js  c++  java
  • Sentinel-DegradeSlot

    概述

    DegradeSlot是用于服务降级熔断。

    在执行entry的过程中,对于处于熔断open状态的情况则判断是否已经过了熔断期且设置半开成功,那么就通过.否则不通过报DegradeException

    对于处于降级状态即half-open的时候,则直接抛出DegradeException.

    熔断器

    Sentinel的熔断器一共有两种ExceptionCircuitBreaker 和  ResponseTimeCircuitBreaker 都 extends  AbstractCircuitBreaker  implements CircuitBreaker

    在上一个之前slot执行过程中,如果发生了非BlockException即一些未知的throw,那么在exit内会判断error是否达到配置的erro数量或者错误比例。

    如果整个调用过程超过了配置的超时时间 则也会触发熔断。

    熔断的目的是将熔断器的状态设置到半开或者全开,这样在tryPass校验的时候就可以返回通过或者异常了。

    配置面板如下:

    根据配置项,可以具体看一下熔断器的接口 CircuitBreaker

    public interface CircuitBreaker {
    
        /**
         *  降级熔断规则
         */
        DegradeRule getRule();
    
        /**
         * true  判断需要降级
         */
        boolean tryPass(Context context);
    
        /**
         * 当前熔断器的状态
         */
        State currentState();
    
        /**
         * 回调方法   当请求pass通过后触发
         */
        void onRequestComplete(Context context);
    
        /**
         * Circuit breaker state.
         */
        enum State {
          
            OPEN,
            
            HALF_OPEN,
           
            CLOSED
        }
    }

    了解了熔断规则以后,下面将具体阐述熔断流程。

    熔断器校验

    先看一下这整个熔断器的状态转化图,其中open到half-open的状态只发生在熔断器检验过程

    在DegradeSlot#entry#performChecking中,先根据资源名称获取到所有的熔断器列表,然后逐个校验。

    void performChecking(Context context, ResourceWrapper r) throws BlockException {
            // 根据资源名  获取该资源的熔断器列表
            List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(r.getName());
            if (circuitBreakers == null || circuitBreakers.isEmpty()) {
                return;
            }
            for (CircuitBreaker cb : circuitBreakers) {
                //逐次校验
                if (!cb.tryPass(context)) {
                    throw new DegradeException(cb.getRule().getLimitApp(), cb.getRule());
                }
            }
        }

    这里面怎么获取到熔断配置,后续在控制台这章会详细讲解,关于页面上的配置如何在服务中生效。接下来重点看一下tryPass

    @Override
        public boolean tryPass(Context context) {
            // Template implementation.
            if (currentState.get() == State.CLOSED) {
                return true;
            }
            // 若下次时间窗到达,且状态由open-> halfopen  则返回true
            if (currentState.get() == State.OPEN) {
                // For half-open state we allow a request for probing.
                // 校验是否通过的时候  有可能放开
                return retryTimeoutArrived() && fromOpenToHalfOpen(context);
            }
            return false;
        }

    很好理解,如果熔断没开,直接return,如果发现正处于熔断状态,这个时候回试图去判断熔断当前时间是否已经过了熔断期,如果过了熔断器,那么尝试性的将open状态设置成half_open,如果设置成功,那么就通过。

    熔断器状态调整

    在statisticSlot中对于一些非BlockException会设置error,然后在调用exit的时候,传递到DegradeSlot#exit的时候,根据情况将会对熔断器的状态设置成open。

    这边以ExceptionCircuitBreaker举例,

    1 如果当前资源的熔断器已经是open,则不做调整。

    2 如果是half-open状态,根据本地调用情况,是否有error来决定设置成close还是升级到熔断open状态

    3 如果是close状态,则开始检验降级配置,计算异常数或者异常比例,如果超过阈值则将熔断器状态设置到open

    注意:对异常数或者慢调用时间都是以滑动时间窗的数据结构来统计的,可参考滑动时间窗算法

    private final LeapArray<SimpleErrorCounter> stat;
    private final LeapArray<SlowRequestCounter> slidingCounter;

    实现代码如下:

     @Override
        public void (Context context) {
            Entry entry = context.getCurEntry();
            if (entry == null) {
                return;
            }
            // 非blockException
            Throwable error = entry.getError();
            // 这边也是使用滑动窗口统计
            SimpleErrorCounter counter = stat.currentWindow().value();
            if (error != null) {
                counter.getErrorCount().add(1);
            }
            counter.getTotalCount().add(1);
    
            handleStateChangeWhenThresholdExceeded(error);
        }
    
        private void handleStateChangeWhenThresholdExceeded(Throwable error) {
            if (currentState.get() == State.OPEN) {
                return;
            }
            
            if (currentState.get() == State.HALF_OPEN) {
                // In detecting request
                if (error == null) {
                    fromHalfOpenToClose();
                } else {
                    fromHalfOpenToOpen(1.0d);
                }
                return;
            }
            
            List<SimpleErrorCounter> counters = stat.values();
            long errCount = 0;
            long totalCount = 0;
            for (SimpleErrorCounter counter : counters) {
                errCount += counter.errorCount.sum();
                totalCount += counter.totalCount.sum();
            }
            if (totalCount < minRequestAmount) {
                return;
            }
            double curCount = errCount;
            if (strategy == DEGRADE_GRADE_EXCEPTION_RATIO) {
                // Use errorRatio
                curCount = errCount * 1.0d / totalCount;
            }
            if (curCount > threshold) {
                transformToOpen(curCount);
            }
        }
  • 相关阅读:
    XSS的原理分析与解剖
    js多少时间之前
    倒计时代码
    js data日期初始化的5种方法
    js日期格式化函数
    删除 Windows Azure 网站上的标准服务器头
    Windows Azure 社区新闻综述(#77 版)
    android 获取本机号码需要root吗?
    宣布正式发布 Biz Talk Services、Azure Active Directory 和 Traffic Manager, 同时发布 Azure Active Directory 高级版预览
    Android 下使用tcpdump网络抓包方法
  • 原文地址:https://www.cnblogs.com/gaojy/p/15302779.html
Copyright © 2011-2022 走看看