Sentinel DegradeSlot fuse source code analysis

This article mainly analyzes the core source code of Sentinel fuse, which is based on the latest release version 1.8.0

1. The processing flow of the Sentinel fusing mechanism

When the fuse trigger condition is reached (assuming the trigger condition is that when the interface is processed more than 20% per second, an exception occurs, the specific fuse rule is configured by the user), the fuse will be turned on. In the fuse state, all access to the interface within X seconds will be Blocked Fail fast (service degradation)

X seconds later, the next time the interface is requested, it is half-open at this time

  • If the request interface is successful, return to the normal state
  • If the request interface fails, return to the fuse state and continue Blocked for X seconds

2. Source code analysis

Sentinel's fusing is implemented by the last DegradeSlot in the chain of responsibility

@SpiOrder(-1000)
public class DegradeSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
    
    

    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                      boolean prioritized, Object... args) throws Throwable {
    
    
        //在触发后续slot前执行熔断的检查
        performChecking(context, resourceWrapper);

        fireEntry(context, resourceWrapper, node, count, prioritized, args);
    }

    void performChecking(Context context, ResourceWrapper r) throws BlockException {
    
    
      	//通过资源名称获取所有的熔断CircuitBreaker
        List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(r.getName());
        if (circuitBreakers == null || circuitBreakers.isEmpty()) {
    
    
            return;
        }
        for (CircuitBreaker cb : circuitBreakers) {
    
    
              //cb.tryPass里面只做了状态检查,熔断是否关闭或者打开
            if (!cb.tryPass(context)) {
    
    
                throw new DegradeException(cb.getRule().getLimitApp(), cb.getRule());
            }
        }
    }

    @Override
    public void exit(Context context, ResourceWrapper r, int count, Object... args) {
    
    
        Entry curEntry = context.getCurEntry();
      	//如果当前其他solt已经有了BlockException直接调用fireExit,不用继续走熔断逻辑了
        if (curEntry.getBlockError() != null) {
    
    
            fireExit(context, r, count, args);
            return;
        }
      	//通过资源名称获取所有的熔断CircuitBreaker
        List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(r.getName());
        if (circuitBreakers == null || circuitBreakers.isEmpty()) {
    
    
            fireExit(context, r, count, args);
            return;
        }

        if (curEntry.getBlockError() == null) {
    
    
            //调用CircuitBreaker的onRequestComplete()方法
            for (CircuitBreaker circuitBreaker : circuitBreakers) {
    
    
                circuitBreaker.onRequestComplete(context);
            }
        }

        fireExit(context, r, count, args);
    }
}

When entering DegradeSlot, it only checks whether the circuit breaker has been opened, and then turns on the half-open state according to whether the retry time has expired, and then directly returns whether it passed. The place to really judge whether the circuit breaker needs to be opened is in the exit()method, because this method is called after the execution of the business method, the circuit breaker needs to collect business exceptions or the execution time of the business method to determine whether to open the circuit breaker

Let's first look at the entry()method of entering DegradeSlot . Here the tryPass()method of CircuitBreaker is called . CircuitBreaker has two types of circuit breakers: ExceptionCircuitBreaker and ResponseTimeCircuitBreaker. The inheritance diagram of CircuitBreaker is as follows:

Insert picture description here

entry()The method actually calls the AbstractCircuitBreaker tryPass()method, and only one processing is done here. If the circuit breaker is turned on, but the last request has passed the retry interval, the half-started state will be turned on

public abstract class AbstractCircuitBreaker implements CircuitBreaker {
    
        

		@Override
    public boolean tryPass(Context context) {
    
    
        if (currentState.get() == State.CLOSED) {
    
    
            return true;
        }
        if (currentState.get() == State.OPEN) {
    
    
            //如果断路器开启,但是上一个请求距离现在已经过了重试间隔时间就开启半启动状态
            return retryTimeoutArrived() && fromOpenToHalfOpen(context);
        }
        return false;
    } 

exit()Method calls ExceptionCircuitBreaker and ResponseTimeCircuitBreaker of onRequestComplete()methods

The following analysis of the relatively simple ExceptionCircuitBreaker, its corresponding fusing strategy is abnormal proportion and abnormal number:

Insert picture description here

The detailed code is as follows:

public class ExceptionCircuitBreaker extends AbstractCircuitBreaker {
    
    

		@Override
    public void onRequestComplete(Context context) {
    
    
        Entry entry = context.getCurEntry();
        if (entry == null) {
    
    
            return;
        }
        Throwable error = entry.getError();
        //异常时间窗口计数器
        SimpleErrorCounter counter = stat.currentWindow().value();
        //异常数加1
        if (error != null) {
    
    
            counter.getErrorCount().add(1);
        }
        //总数加1
        counter.getTotalCount().add(1);

        handleStateChangeWhenThresholdExceeded(error);
    }

    private void handleStateChangeWhenThresholdExceeded(Throwable error) {
    
    
        //断路器已开直接返回
        if (currentState.get() == State.OPEN) {
    
    
            return;
        }

        //断路器处于半开状态
        if (currentState.get() == State.HALF_OPEN) {
    
    
            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();
        }
        //请求总数小于minRequestAmount时不做熔断处理 minRequestAmount时配置在熔断规则里面的
        if (totalCount < minRequestAmount) {
    
    
            return;
        }
        double curCount = errCount;
        if (strategy == DEGRADE_GRADE_EXCEPTION_RATIO) {
    
    
            //如果熔断策略配置的是窗口时间内错误率就需要做百分比的计算
            curCount = errCount * 1.0d / totalCount;
        }
        //错误率或者错误数大于阈值就开启断路器
        if (curCount > threshold) {
    
    
            transformToOpen(curCount);
        }
    }

ExceptionCircuitBreaker is called after the business method is executed, and the main processing is as follows:

1) The circuit breaker is half open

  • There is no abnormality in this request, turn off the circuit breaker
  • There is an exception in this request, open the circuit breaker

2) The minimum number of requests will be configured in the Sentinel Dashboard downgrade rule. If the total number of requests is less than the minimum number of requests, no circuit breaker will be performed

3) Turn on the circuit breaker if the error rate or the number of errors is greater than the threshold

Reference :

Source code analysis Sentinel DegradeSlot fuse

Guess you like

Origin blog.csdn.net/qq_40378034/article/details/113089075