AlibabaCloud-sentinel-getway circuit breaker (2)

AlibabaCloud-sentinel circuit breaker (2)

In the previous article, we introduced the use of sentinel to limit the interface current, but the function of Sentinel is of course not limited to interface pull. At this time, the @SentinelResource annotation comes out.

Let’s take a look at how he uses it

The first step: first start the sentinel console

java -Dserver.port=8889  -jar sentinel-dashboard-1.8.0.jar 

Step 2: Add configuration for annotation support:

    public static void main(String[] args) {
    
    
        new SpringApplicationBuilder(FebsServerTestApplication.class)
                .web(WebApplicationType.SERVLET)
                .run(args);
    }

    // 注解支持的配置Bean
    @Bean
    public SentinelResourceAspect sentinelResourceAspect(){
    
    
        return new SentinelResourceAspect();
    }

Step 2: Use @SentinelResourceannotations where you need to control traffic through Sentinel . For example, use a method to control the service logic layer as follows:

package cc.mrbird.febs.server.test.service.impl;

import cc.mrbird.febs.server.test.service.ITestService;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * @author: craywen
 * @date: 2020-09-07 10:22
 * @desc:
 */
@Service
@Slf4j
public class TestServerImpl implements ITestService {
    
    

    @Override
    @SentinelResource(value = "sentinelTest")
    public void sentinelTest() {
    
    
     log.info("----------------限流方法测试------------");
    }
}

Up to this point is the current limit for this method (referred to as the resource point). After the resource point is defined, different protection strategies can be implemented, including: current limit, downgrade, etc.

Let's take a look at the effect first: First, set the current limit on the console

[External link image transfer failed. The source site may have an anti-hotlinking mechanism. It is recommended to save the image and upload it directly (img-j818rsBf-1599451264306) (C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\ image-20200907105529843.png)]

In order to demonstrate the effect, set it twice a second.

Postman test effect chart:

1. Single-click rendering: [External link image transfer failed, the source site may have anti-leeching mechanism, it is recommended to save the image and upload it directly (img-rHDbxSmb-1599451264309)(C:\Users\Administrator\AppData\ Roaming\Typora\typora-user-images\image-20200907105730789.png)]

2. Quick click: [External link image transfer failed, the source site may have an anti-leech link mechanism, it is recommended to save the image and upload it directly (img-F41cp2ip-1599451264310)(C:\Users\Administrator\AppData\Roaming\Typora\typora -user-images)]

This is very obvious, the 500 exception returned directly, for this kind of we must sit and deal with it.

Realize current limit exception handling

By default, Sentinel directly throws exceptions for the current limit processing of control resources, but under normal circumstances, in order to better user business, some special processing after the current limit is implemented, we do not want to show a blunt error. Then only need to do some processing based on the above example, such as:


    @Override
    @SentinelResource(value = "sentinelTest",blockHandler = "exceptionHandler")
    public void sentinelTest() {
     log.info("----------------限流方法测试------------");
    }

    // 阻塞处理
    private  void exceptionHandler(BlockException ex){
        log.error( "blockHandler:" , ex);
    }
  • Develop specific processing functions through the @SentinelResourceannotated blockHandlerattributes (implement custom exceptions)
  • To implement the processing function, the parameter passing of the function must be the same as that of the resource point, and the BlockExceptionexception parameter must be added at the end ; at the same time, the return type must also be the same.

Achieve fuse downgrade

@SentinelResourceNote that the release can be used for current limiting control, and it can also implement a fuse downgrade strategy similar to Hystrix.

  1. First transform the method sentinelTest2

     // 熔断与降级处理
        @Override
        @SentinelResource(value = "sentinelTest2",fallback = "fallback")
        public void sentinelTest2() {
          
          
            log.info("sentinelTest2-------",new Date());
            throw new RuntimeException("发生异常");
        }
    
        public void fallback(){
          
          
            log.error("fallbackHandler:" +new Date());
        }
    

2. Configure the fuse strategy [The external link image transfer fails, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-UHhSQdmt-1599451264312)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images)]
to make the effect more obvious, set the fuse time to 10S, which means that the abnormal proportion of this method is requested More than 50% will trigger the fuse mechanism, and the minimum request can be understood as a cycle of five requests.

After completing the above transformation, restart the application, and set the fuse downgrade strategy of sentinelTest2 resources (using abnormal percentage), and then frequently request the /sentinelTest2接口。在QPS>=5之后,由于这个接口一直在抛出异常,所以一定会满足熔断降级条件,这时候就会执行fallbackHandler` method, and continuously print the following logs:

3. In order to be effective, we use Apache jmeter to test: prepare 20 requests

First look at the effect of setting the fuse:

[External link image transfer failed. The source site may have an anti-hotlinking mechanism. It is recommended to save the image and upload it directly (img-LLbsqybk-1599451264313) (C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images) ]

Fuse effect:

[External link image transfer failed. The source site may have an anti-hotlinking mechanism. It is recommended to save the image and upload it directly (img-ahWDJfvd-1599451264314) (C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images) ]

Not much to say, obviously, call the fallback method directly.

More annotation attribute description

@SentinelResourceThe two main usages of annotations: the specific use cases of current limit control and fuse degradation are introduced. In addition, this annotation also has some other more refined configurations, such as ignoring certain abnormal configurations, default degrading functions, etc., for details, see the following description:

  • value: Resource name, required item (cannot be empty)

  • entryType:Entry type, optional (default is EntryType.OUT)

  • blockHandler/ blockHandlerClass: blockHandlerCorrespondence processing BlockExceptionfunction name, options. The access scope of the blockHandler function needs to be publicthat 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. If you want to use other types of functions, you can specify blockHandlerClassthe class of the corresponding Classobjects, pay attention to the corresponding function is necessary for the static function, it can not be resolved otherwise.

  • fallback
    

    : Fallback function name, optional, used to provide fallback processing logic when an exception is thrown. The fallback function can target all types of exceptions (except

    exceptionsToIgnore
    

    The exception types excluded inside) are processed. Fallback function signature and location requirements:

    • The return value type must be consistent with the return value type of the original function;
    • The method requires a list of parameters and functions consistent with the original, or may be an additional Throwabletype of abnormality corresponding to the received parameter.
    • The fallback function needs to be in the same class as the original method by default. If you want to use other types of functions, you can specify fallbackClassthe class of the corresponding Classobjects, pay attention to the corresponding function is necessary for the static function, it can not be resolved otherwise.
  • defaultFallback
    

    (Since 1.6.0): The 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 target all types of exceptions (except

    exceptionsToIgnore
    

    The exception types excluded inside) are processed. If both fallback and defaultFallback are configured, only fallback will take effect. The defaultFallback function signature requirements:

    • The return value type must be consistent with the return value type of the original function;
    • The method requires the parameter list is empty, or may be an additional Throwabletype of abnormality corresponding to the received parameter.
    • The defaultFallback function needs to be in the same class as the original method by default. If you want to use other types of functions, you can specify fallbackClassthe class of the corresponding Classobjects, pay attention to the corresponding function is necessary for the static function, it can not be resolved otherwise.
  • exceptionsToIgnore(Since 1.6.0): Used to specify which exceptions are excluded, not included in the exception statistics, and will not enter the fallback logic, but will be thrown as-is.

Note: The fallback function of versions before 1.6.0 only deals with downgrade exceptions ( DegradeException), and cannot deal with business exceptions .

In particular, if blockHandler and fallback are configured, they were thrown limiting downgrade BlockExceptionwill only enter when blockHandlerprocessing logic. If no configuration blockHandler, fallbackand defaultFallback, will downgrade were limiting BlockException direct throw .

What's the problem:

Because the sentinel console, current limiting or fuse rules are not persistent, all can be persisted in the database.

You can refer to the following configuration:

package cc.mrbird.febs.gateway.common.configure;

import cc.mrbird.febs.common.core.entity.FebsResponse;
import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * @author: craywen
 * @date: 2020-09-04 11:10
 * @desc:  Sentinel 配置
 * 使用时只需注入对应的 SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例即可。
 */
@Configuration
public class FebsGatewaySentinelConfiguration {
    
    

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public FebsGatewaySentinelConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                            ServerCodecConfigurer serverCodecConfigurer) {
    
    
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    /**
     * 异常处理模块
     * @return
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
    
    
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    /**
     * 过滤器
     * @return
     */
    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
    
    
        return new SentinelGatewayFilter();
    }

    @PostConstruct
    public void doInit() {
    
    
        //初始化规则
        initGatewayLimitRules();
        //熔断规则
        initFuseRules();
        //自定义限流异常处理
        initBlockHandler();
    }

    /**
     * 熔断规则 DegradeRule
     * resource	资源名,即规则的作用对象
     * grade	熔断策略,支持慢调用比例/异常比例/异常数策略	慢调用比例
     * count	慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
     * timeWindow	熔断时长,单位为 s
     * minRequestAmount	熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入)	5
     * statIntervalMs	统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)	1000 ms
     * slowRatioThreshold	慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)
     */
    private void initFuseRules(){
    
    
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule();
        rule.setResource("FEBS-Server-System");
        // set threshold RT, 10 ms
        rule.setCount(10);
        rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
        rule.setTimeWindow(10);
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }

    /**
     * 初始化规则
     */
    private void initGatewayLimitRules() {
    
    
        /**  Set<FlowRule> rules api 限流
         * resource	资源名,资源名是限流规则的作用对象
         * count	限流阈值
         * grade	限流阈值类型,QPS 模式(1)或并发线程数模式(0)	QPS 模式
         * limitApp	流控针对的调用来源	default,代表不区分调用来源
         * strategy	调用关系限流策略:直接、链路、关联	根据资源本身(直接)
         * controlBehavior	流控效果(直接拒绝/WarmUp/匀速+排队等待),不支持按调用关系限流	直接拒绝
         * clusterMode	是否集群限流
         */
        /*GatewayFlowRule:网关限流规则,针对 API Gateway 的场景定制的限流规则,
        可以针对不同 route 或自定义的 API 分组进行限流,
        支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
        */

        Set<GatewayFlowRule> rules = new HashSet<>();
        /*设置限流规则
        resource: 资源名称,这里为路由router的ID
        resourceMode: 路由模式
        count: QPS即每秒钟允许的调用次数
        intervalSec: 每隔多少时间统计一次汇总数据,统计时间窗口,单位是秒,默认是 1 秒。
        */
        rules.add(new GatewayFlowRule("FEBS-Server-test")
                .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID)
                .setCount(1).setIntervalSec(1));
        GatewayRuleManager.loadRules(rules);
    }

    /**
     * 自定义限流异常处理
     * ResultSupport 为自定义的消息封装类,代码略
     */
    private void initBlockHandler() {
    
    
        GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
    
    
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange,
                                                      Throwable throwable) {
    
    
                return ServerResponse.status(HttpStatus.OK)
                        .contentType(MediaType.APPLICATION_JSON_UTF8)
                        .body(BodyInserters.fromObject(new FebsResponse().put("data", "系统访问量过大,限流啦!")));
            }
        });
    }
}

The system will automatically load the configuration.

Reference : Sentinel official document

Reference materials http://blog.didispace.com/spring-cloud-alibaba-sentinel-2-5/

Guess you like

Origin blog.csdn.net/qq_38893133/article/details/108445493