Coding skills - Sentinel's blockHandler and fallback

This article introduces the difference between Sentinel's blockHandler and fallback. The background is: when current limiting occurs, the configured sentinel's blockhandler does not take effect and fallback takes effect; check the cause, and then give the code writing method for Sentinel configuration abnormal downgrade and current limit downgrade;

Before viewing the source code, I consulted relevant technical posts ( 1. The difference between Sentinel's blockHandler and fallback  2. Sentinel service fuse [fallBack/blockHandler] ), for the scenario where fallback and blockHandler are configured at the same time, the conclusions are inconsistent, so I decided to practice by yourself;

1. Fallback and blockHandler are not configured

The code is as follows, only configure the value of SentinelResource, and go to the sentinel console to configure the single-machine current limit to 1;

Current limiting method:

    /**
     * 测试sentinel的降级方法
     */
    @SentinelResource(value = "testSentinelFallback")
    public String testSentinelFallback() {
        return "返回成功ok";
    }

Test code:

    @Override
    public String mock() {
        // 异步调用 模拟并发情况
        for (int i = 0; i < 5; i++) {
            CompletableFuture.runAsync(() -> {
                try {
                    final String result = testSentinelService.testSentinelFallback();
                    log.info("调用返回结果 [result={}]", result);
                } catch (Throwable e) {
                    log.warn("调用抛出异常", e);
                }
            });
        }
        return null;
    }

Sentinel background configuration:

Results of the:

调用返回结果 [result=返回成功ok]

调用抛出异常
java.lang.reflect.UndeclaredThrowableException: null
Caused by: com.alibaba.csp.sentinel.slots.block.flow.FlowException: null

调用抛出异常
java.lang.reflect.UndeclaredThrowableException: null
Caused by: com.alibaba.csp.sentinel.slots.block.flow.FlowException: null
...

2. Only configure blockHandler

2.1 BlockException without additional parameters when configuring blockHandler
    @SentinelResource(value = "testSentinelFallback", blockHandler = "myBlockHandler")
    public String testSentinelFallback() {
        return "返回成功ok";
    }

    public String myBlockHandler() {
        return "进入myBlockHandler逻辑";
    }

Execution result: did not enter the current limit downgrading method ;

调用返回结果 [result=返回成功ok]

调用抛出异常
java.lang.reflect.UndeclaredThrowableException: null
Caused by: com.alibaba.csp.sentinel.slots.block.flow.FlowException: null

调用抛出异常
java.lang.reflect.UndeclaredThrowableException: null
Caused by: com.alibaba.csp.sentinel.slots.block.flow.FlowException: null
...
2.2 Correctly configure blockHandler
    @SentinelResource(value = "testSentinelFallback", blockHandler = "myBlockHandler")
    public String testSentinelFallback() {
        return "返回成功ok";
    }

    public String myBlockHandler(BlockException blockException) {
        return "进入myBlockHandler逻辑";
    }

Execution result: successfully enter the current limit downgrading method ;

调用返回结果 [result=返回成功ok]

调用返回结果 [result=进入myBlockHandler逻辑]

调用返回结果 [result=进入myBlockHandler逻辑]
...
2.3 blockHandler can capture business exceptions
    @SentinelResource(value = "testSentinelFallback", blockHandler = "myBlockHandler")
    public String testSentinelFallback() {
        if (Boolean.TRUE) {
            throw new BusinessException(FacadeResultCodeEnum.BAD_PARAMS);
        }
        return "返回成功ok";
    }

    public String myBlockHandler(BlockException blockException) {
        return "进入myBlockHandler逻辑";
    }

Execution result: When the interface is limited, it successfully enters the current limiting downgrade method ; when the interface has a business exception, it will be thrown to the outer layer ;

调用抛出异常
BusinessException

调用返回结果 [result=进入myBlockHandler逻辑]

调用返回结果 [result=进入myBlockHandler逻辑]
...

3. Only configure fallback

3.1 The additional parameter Throwable is not included when configuring fallback
    @SentinelResource(value = "testSentinelFallback", fallback = "myFallback")
    public String testSentinelFallback() {
        if (Boolean.TRUE) {
            throw new BusinessException(FacadeResultCodeEnum.BAD_PARAMS);
        }
        return "返回成功ok";
    }

    public String myFallback() {
        return "进入myFallback逻辑";
    }

Execution result: When the interface is limited, or when the interface has a business exception, it will enter the fallback downgrade method ;

调用返回结果 [result=进入myFallback逻辑]

调用返回结果 [result=进入myFallback逻辑]

调用返回结果 [result=进入myFallback逻辑]
...

3.2 Bring additional parameter Throwable when configuring fallback

    @SentinelResource(value = "testSentinelFallback", fallback = "myFallback")
    public String testSentinelFallback() {
        if (Boolean.TRUE) {
            throw new BusinessException(FacadeResultCodeEnum.BAD_PARAMS);
        }
        return "返回成功ok";
    }

    public String myFallback(Throwable throwable) {
        if (throwable instanceof BlockException) {
            return "进入myFallback逻辑 限流异常";
        }
        return "进入myFallback逻辑 业务异常";
    }

Execution result: When the interface is limited or the interface has a business exception, it will enter the fallback downgrade method ; and the exception type can be used to distinguish between the current limit exception and the business exception ;

调用返回结果 [result=进入myFallback逻辑 业务异常]

调用返回结果 [result=进入myFallback逻辑 限流异常]
调用返回结果 [result=进入myFallback逻辑 限流异常]
...

4. Configure fallback and blockHandler at the same time

    @SentinelResource(value = "testSentinelFallback", fallback = "myFallback", blockHandler = "myBlockHandler")
    public String testSentinelFallback() {
        if (Boolean.TRUE) {
            throw new BusinessException(FacadeResultCodeEnum.BAD_PARAMS);
        }
        return "返回成功ok";
    }

    public String myFallback(Throwable throwable) {
        if (throwable instanceof BlockException) {
            return "进入myFallback逻辑 限流异常";
        }
        return "进入myFallback逻辑 业务异常";
    }

    public String myBlockHandler(BlockException blockException) {
        return "进入myBlockHandler逻辑";
    }

Execution result: If both blockHandler and fallback are configured, when the flow limit is not triggered and the method logic throws a business exception, it will enter the fallback method; when the flow limit is triggered, the method logic cannot be entered, and BlockException is directly thrown into the blockHandler method ;

5 Conclusion

5.1 Exception capture logic

1. blockHandler

  • blockHandler only handles current-limit exceptions;
  • When using blockHandler, the method signature parameter is consistent with the original method, and the BlockException parameter must be added at the last position of the parameter;
  • If the BlockException parameter is not added, it will not take effect;

2. fallback

  • fallback can handle all types of exceptions, including current limit exceptions and business exceptions;
  • When using fallback, the method signature parameter can be exactly the same as the original method, or it is also acceptable to add the Throwable parameter at the last position of the parameter;
  • Distinguish whether it is a current-limiting exception or other exceptions by the type of the Throwable parameter;
  • When blockHandler and fallback are in effect at the same time, the current limit exception will be processed by blockHandler first and will not enter the fallback logic;
5.2 Reasonable code writing

(1) Configure effective blockHandler and fallback at the same time to handle current limit exceptions and business exceptions respectively

    @SentinelResource(value = "testSentinelFallback", fallback = "myFallback", blockHandler = "myBlockHandler")
    public String testSentinelFallback() {
        // ...
        return "返回成功ok";
    }

    public String myFallback(Throwable throwable) {
        return "进入myFallback逻辑 业务异常";
    }

    public String myBlockHandler(BlockException blockException) {
        return "进入myBlockHandler逻辑";
    }

(2) Only configure fallback and distinguish between current limiting exception and business exception by Throwable type

    @SentinelResource(value = "testSentinelFallback", fallback = "myFallback")
    public String testSentinelFallback() {
        // ...
        return "返回成功ok";
    }

    public String myFallback(Throwable throwable) {
        if (throwable instanceof com.alibaba.csp.sentinel.slots.block.flow.FlowException) {
            final FlowRule rule = ((FlowException) throwable).getRule();
            final double count = rule.getCount();
            final String resource = rule.getResource();
            // 打印限流规则信息
            log.warn("testSentinelFallback触发限流降级 [sentinelResource={} QpsLimit={}]]", resource, count);
            return null;
        } else {
            log.warn("testSentinelFallback触发异常降级 抛出异常", throwable);
            throw new RuntimeException("testSentinelFallback业务异常");
        }
    }
5.3 Annotation parameter interpretation and precautions

1. @SentinelResource annotation parameter description

Attributes Defaults illustrate
blockHandler

It is used to degrade processing logic when exceptions such as current limit/fuse/system protection are thrown, blockHandler is aimed at BlockException type exceptions, and has a higher priority than fallback

The access scope of the blockHandler function needs to be public, the return type needs to match the original method, the parameter type needs to match the original method and an additional parameter is added at the end, the type is BlockException;

The blockHandler function needs to be in the same class as the original method by default;

blockHandlerClass If you want to use functions of other classes, you can specify blockHandlerClass as the Class object of the corresponding class. Note that the corresponding function must be a static function, otherwise it cannot be parsed;
defaultFallback Default fallback function name, optional, usually used for general fallback logic (that is, it can be used for many services or methods);

The default fallback function can handle all types of exceptions (except the exception types excluded in exceptionsToIgnore);

If both fallback and defaultFallback are configured, only fallback will take effect

entryType EntryType.OUT The traffic type of the resource call, whether it is ingress traffic (EntryType.IN) or egress traffic (EntryType.OUT). Note that the system protection rules are only valid for IN
exceptionsToIgnore It is used to specify which exceptions are excluded, and will not be included in the exception statistics, nor will they enter the fallback logic, but will be thrown as they are; the priority is higher than exceptionsToTrace
exceptionsToTrace Throwable.class It is used to specify which exceptions are not excluded; if it belongs to this type, it will be included in the exception statistics, and will also enter the fallback logic, and will not be thrown as it is; it is not recommended to modify the default value;
fallback

It is used to provide fallback processing logic when an exception is thrown; fallback is for all types of exceptions (except the exception types excluded in exceptionsToIgnore)

The method parameter list needs to be consistent with the original function, or an additional Throwable type parameter can be added to receive the corresponding exception (note that it is different from the BlockException added by blockHandler)

fallbackClass Similar to blockHandlerClass parameter
resourceType resource type, default 0
value resource name, required

2. Distinguish current limit abnormality and fusing abnormality

An exception will be thrown in the current limiting state: FlowException (inherited from BlockException)

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.alibaba.csp.sentinel.slots.block.flow.FlowException] with root cause
 
com.alibaba.csp.sentinel.slots.block.flow.FlowException: null

The fuse state will throw an exception: DegradeException (inherited from BlockException)

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.alibaba.csp.sentinel.slots.block.degrade.DegradeException] with root cause
 
com.alibaba.csp.sentinel.slots.block.degrade.DegradeException: null

 

Reference: annotation-support | Sentinel

Guess you like

Origin blog.csdn.net/minghao0508/article/details/132148320