熔断与降级

熔断与降级

Sentinel:

支持的规则:流量控制规则熔断降级规则系统保护规则来源访问控制规则热点参数规则

一、流量控制:

设计理念:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  • 运行指标,例如 QPS、线程池、系统负载等;
  • 控制的效果,例如直接限流、冷启动、排队等。

二、熔断降级:

设计理念:

  • 通过并发线程数进行限制:

    ​ 当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。

  • 通过响应时间对资源进行降级:

    ​ 当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。

三、网关流控:Gateway + Sentinel + Nacos动态规则:

  1. 添加依赖:

    <!-- SpringCloud Ailibaba Sentinel -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!-- SpringCloud Ailibaba Sentinel Gateway -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
    </dependency>
    <!-- Sentinel Datasource Nacos -->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    
  2. 在配置文件添加配置:

    spring:
      cloud:
        nacos:
          discovery:
            # 服务注册地址
            server-addr: 127.0.0.1:8848
          config:
            # 配置中心地址
            server-addr: 127.0.0.1:8848
            # 配置文件格式
            file-extension: yml
            # 共享配置
            shared-configs:
              - ${spring.cloud.nacos.config.file-extension}
        sentinel:
          eager: true #控制台热加载,false为懒加载(第一次调用接口才会加载)
          transport:
            dashboard: 127.0.0.1:8858
          datasource:
            ds1:
              nacos:
                server-addr: ${spring.cloud.nacos.config.server-addr}
                dataId: ${spring.application.name}
                groupId: SENTINEL_GROUP
                data-type: json
                rule-type: gw-flow
                namespace: ${sentinel.nacos.namespace}
    

    关于rule-type的值:

    /**
    * flow 流控规则
    */
    FLOW("flow", FlowRule.class),
    /**
    * degrade 降级规则
    */
    DEGRADE("degrade", DegradeRule.class),
    /**
    * param flow 热点规则
    */
    PARAM_FLOW("param-flow", ParamFlowRule.class),
    /**
    * system 系统规则
    */
    SYSTEM("system", SystemRule.class),
    /**
    * authority 授权规则
    */
    AUTHORITY("authority", AuthorityRule.class),
    /**
    * gateway flow 网关限流规则
    */
    GW_FLOW("gw-flow","com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),
    /**
    * api 用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合
    */
    GW_API_GROUP("gw-api-group","com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
    
  3. Nacos上新增JSON文件添加网关流控规则:

    网关流控规则说明:

    Field说明默认值
    resource资源名称,网关route或自定义API分组名称(注:网关route这里的值不是route.id,可调试
    resourceMode限流资源类型,网关route【0】或自定义API分组【1】(详细查看GatewayFlowRuleSentinelGatewayConstants网关route
    grade限流阈值类型,QPS【1】或线程数【0】QPS
    count限流阈值,QPS阈值或线程数值
    intervalSec统计时间间隔,单位秒1秒
    controlBehavior流控效果,目前支持快速失败【0】和匀速排队【1】快速失败
    burst应对突发请求时额外允许的请求数目
    maxQueueingTimeoutMs匀速排队模式下的最长排队时间,单位毫秒,仅在匀速排队模式下生效
    paramItem参数属性配置,parseStrategy:提取参数策略(0:Clien IP,1:Remote HOST,2:Header,3:请求参数,4:Cookie);fieldName:若提取策略是Header模式或者URL参数模式,则需要指定header名称或URL参数名称;pattern:参数值的匹配模式;matchStrategy:参数值的匹配策略,支持精确匹配,子串匹配和正则匹配。

    json文件:

    [
        {
            "resource": "xxx-auth",
            "count": 1,
            "grade": 1,
            "limitApp": "default",
            "strategy": 0,
            "controlBehavior": 0
        }
    ]
    
  4. docker部署Sentinel Dashboard:

# 拉取镜像
docker pull bladex/sentinel-dashboard
# 启动容器
docker run --name sentinel -d -p 8858:8858 -d bladex/sentinel-dashboard

用户名/密码:sentinel/sentinel,可访问http://localhost:8858登录,在流控规则可以看到我们的Nacos添加的流控规则

注意事项:1. 启动网关服务时,记得添加网关流控客户端标识(JVM启动参数-Dcsp.sentinel.app.type=1)

​ 2. 遇到在Sentinel Dashboard读取不到Nacos配置的规则,原因是jdk版本的原因,原先是jdk1.8.0_162换成jdk1.8.0_291解决

  1. 自定义网关限流处理:

    法一:

    /**
     * 网关限流配置
     */
    @Configuration
    public class GatewayConfig {
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public SentinelFallbackHandler sentinelGatewayExceptionHandler() {
            return new SentinelFallbackHandler();
        }
    
        @Bean
        @Order(-1)
        public GlobalFilter sentinelGatewayFilter() {
            return new SentinelGatewayFilter();
        }
    }
    
    
    /**
     * 自定义限流异常处理
     */
    public class SentinelFallbackHandler implements WebExceptionHandler {
        private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
            ServerHttpResponse serverHttpResponse = exchange.getResponse();
            serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            byte[] datas = "{\"code\":429,\"msg\":\"请求超过最大数,请稍后再试\"}".getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(datas);
            return serverHttpResponse.writeWith(Mono.just(buffer));
        }
    
        @Override
        public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
            if (exchange.getResponse().isCommitted()) {
                return Mono.error(ex);
            }
            if (!BlockException.isBlockException(ex)) {
                return Mono.error(ex);
            }
            return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange));
        }
    
        private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
            return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
        }
    }
    

    法二:

    @Configuration
    public class GatewayConfig {
        @PostConstruct
    	private void initBlockHandler() {
        	BlockRequestHandler blockRequestHandler = (exchange, t) ->
            	ServerResponse.status(HttpStatus.OK)
            	.contentType(MediaType.APPLICATION_JSON)
            	.body(BodyInserters.fromValue(ResultCode.FLOW_LIMITING.toString()));
        	GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    	}
    }
    
    

四、普通流控:

规则说明:

Field说明默认值
resource资源名,资源名是限流规则的作用对象
count限流阈值
grade限流阈值类型,QPS 【1】或线程数模式【0】QPS 模式
limitApp流控针对的调用来源default,代表不区分调用来源
strategy判断的根据是资源自身,还是根据其它关联资源 (refResource),还是根据链路入口根据资源本身
controlBehavior流控效果(直接拒绝 / 排队等待 / 慢启动模式)直接拒绝

大致同网关流控一致,在服务配置文件的rule-type改成flow即可

自定义异常实现 BlockExceptionHandler接口即可:

@Component
public class DefaultBlockExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        response.setStatus(HttpStatus.ok().status());
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        if(e instanceof FlowException){
            // objectMapper.writeValue 用于将java对象转位JSON格式返回调用方
            new ObjectMapper().writeValue(response.getWriter(), Result.failed(ResultCode.FLOW_LIMITING));
        }
    }
}

五、整合OpenFeign熔断降级:

  1. Sentinel提供了三种熔断策略:
  • 慢调用比例: 请求响应时间大于设置的RT(即最大的响应时间)则统计为慢调用。触发此熔断策略的条件需要满足两个条件,一是单位统计时长(statIntervalMs)内请求数大于设置的最小请求数,二是慢调用的比例大于阈值,接下来在熔断时长的范围内请求会自动的被熔断。过了熔断时长后,熔断器进入探测恢复状态(HALF-OPEN状态),若接下来的一个请求响应时间小于设置的慢调用RT则结束熔断,若大于设置的慢调用RT则会再次被熔断。
  • 异常比例:当单位统计时长请求数大于设置的最小请求数,并且异常的比例大于阈值,则接下来的熔断时长内请求会被自动熔断。
  • 异常数:当单位统计时长内的异常数目超过阈值之后会自动进行熔断。
  1. 熔断降级规则(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 引入)
  1. 整合步骤:

    (1)添加依赖:

    <!--引入sentinel-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        <!--去除jackson-dataformat-xml,否则会返回xml文件,而不是JSON-->
        <exclusions>
            <exclusion>
                <groupId>com.fasterxml.jackson.dataformat</groupId>
                <artifactId>jackson-dataformat-xml</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- Sentinel规则持久化至Nacos配置 -->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    

    (2)开启Feign对Sentinel支持:

    spring:
      application:
        name: xxx-xxx
      cloud:
        sentinel:
          enabled: true
          eager: true # 取消控制台懒加载,项目启动即连接Sentinel
          transport:
            dashboard: localhost:8080
          datasource:
            # 降级规则
            degrade:
              nacos:
                server-addr: ${spring.cloud.nacos.discovery.server-addr}
                dataId: ${spring.application.name}-degrade-rules
                groupId: SENTINEL_GROUP
                data-type: json
                rule-type: degrade
    feign:
      sentinel:
        enabled: true
    

    (3) 添加降级规则:

    [
    	{
    		"resource": "GET:http://服务名/api.admin/v1/users/username/{username}",
    		"grade": 2,
    		"count": 1,
    		"timeWindow": 5
    	}
    ]
    

    (4)创建容错类:

    @Service
    // 准备 兜底数据,提高用户体验
    public class VideoServiceFallBack implements VideoService {
        @Override
        public Video findById(int videoId) {
            Video video = new Video();
            video.setTitle("这个是Fallback里面的视频");
            return video;
        }
        @Override
        public int save(Video video) {
            return 0;
        }
    }
    

    (5)配置feign容错类:

    @FeignClient(value = "服务名", fallback = VideoServiceFallBack.class)
    
Hystrix:

一、熔断降级:

设计理念:

  1. ​ 线程池隔离:针对不同的资源分别创建不同的线程池,不同服务调用都发生在不同的线程池中,在线程池排队、超时等阻塞情况时可以快速失败,并可以提供 fallback 机制。
  2. ​ 信号量隔离:限制对某个资源调用的并发数。
总结:

​ 在熔断降级方面,Sentinel 和 Hystrix 的本质上都是基于熔断器模式(Circuit Breaker Pattern)。Sentinel 与 Hystrix 都支持基于失败比率(异常比率)的熔断降级,在调用达到一定量级并且失败比率达到设定的阈值时自动进行熔断,此时所有对该资源的调用都会被 block,直到过了指定的时间窗口后才启发性地恢复。

​ 在隔离设计上,Sentinel采取的是信号量隔离,而Hystrix提供了线程池隔离和信号量隔离。

​ Sentinel相比Hystrix提供更多的功能,用户可以根据系统需求,灵活制定策略,从多个维度上保护服务的稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值