美文网首页
spring-cloud-gateway 降级熔断 Hystri

spring-cloud-gateway 降级熔断 Hystri

作者: virtual灬zzZ | 来源:发表于2021-10-31 17:33 被阅读0次

HystrixGatewayFilterFactory,定位到该类,看注释得知,它需要引入spring-cloud-starter-netflix-hystrix。

/**
 * Depends on `spring-cloud-starter-netflix-hystrix`,
 * {@see https://cloud.spring.io/spring-cloud-netflix/}.
 *
 * @author Spencer Gibb
 * @author Michele Mancioppi
 * @author Olga Maciaszek-Sharma
 */
public class HystrixGatewayFilterFactory
        extends AbstractGatewayFilterFactory<HystrixGatewayFilterFactory.Config> {

    private final ObjectProvider<DispatcherHandler> dispatcherHandlerProvider;

    // do not use this dispatcherHandler directly, use getDispatcherHandler() instead.
    private volatile DispatcherHandler dispatcherHandler;

    public HystrixGatewayFilterFactory(
            ObjectProvider<DispatcherHandler> dispatcherHandlerProvider) {
        super(Config.class);
        this.dispatcherHandlerProvider = dispatcherHandlerProvider;
    }

...后续略

引入maven depend

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

applicaiton.yml配置:
name必须要有,它是用来创造hystrixCommand的,fallbackUri必须要有forward:/,源码详看后面,因为里面有这要求:

Assert.notNull(config.name,  "A name must be supplied for the Hystrix Command Key");

public void setFallbackUri(URI fallbackUri) {
    if (fallbackUri != null && !"forward".equals(fallbackUri.getScheme())) {
        throw new IllegalArgumentException(
            "Hystrix Filter currently only supports 'forward' URIs, found "
                    + fallbackUri);
    }
    this.fallbackUri = fallbackUri;
}
spring:
  cloud:
    gateway:
      routes:
      - id: user-service
        uri: lb://user-service
        order: 10000
        predicates:
        - Path=/user/**
        filters:
        - RewritePath=/user/(?<path>.*), /$\{path}
        # 指定使用HystrixGatewayFilterFactory生成filter
        - name: Hystrix
          args:
            # 指定hystrix command的名称,一般不配置setter,因为涉及线程池,没有setter所以必须设置name,不然报错
            name: hystrixCmd
            # 注意fallbackUri要以forward开头
            fallbackUri: forward:/fallback

熔断返回示例:

@RestController
@RequestMapping("/fallback")
public class FallbackController {

    @RequestMapping("")
    public String fallback(){
        return "error";
    }
}

这里引用官网,说首选方案是放在内部这么一个应用里,直接放gateway的controller,但是,你仍然可以用一个外部应用的链接来处理,如以下配置,http://localhost:9994 就是外部的应用

Example 22. application.yml
spring:
  cloud:
    gateway:
      routes:
      - id: ingredients
        uri: lb://ingredients
        predicates:
        - Path=//ingredients/**
        filters:
        - name: Hystrix
          args:
            name: fetchIngredients
            fallbackUri: forward:/fallback
      - id: ingredients-fallback
        uri: http://localhost:9994
        predicates:
        - Path=/fallback

源代码:

public GatewayFilter apply(Config config) {
    // 1.第一次创建 filter config时,是没有这个setter字段的,它是用于构造HystrixCommand
    if (config.setter == null) {
        // 这里的name实际是我们在yml配置的filter的args参数中的name,比如:hystrixCmd
        Assert.notNull(config.name,
            "A name must be supplied for the Hystrix Command Key");
        // 这里是把HystrixGatewayFilterFactory这个类名作为HystrixCommandGroup的key
        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory
            .asKey(getClass().getSimpleName());
        // 通过我们配置的hystrix命令名作为HystrixCommand的key
        HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(config.name);
        // groupKey和commandKey为参数来构造一个setter
        config.setter = Setter.withGroupKey(groupKey).andCommandKey(commandKey);
    }

    // 真正开始生产熔断功能的GatewayFilter
    return new GatewayFilter() {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange,
                GatewayFilterChain chain) {
            return Mono.deferWithContext(context -> {
                // 1.用config里的参数构造一个RouteHystrixCommand
                RouteHystrixCommand command = new RouteHystrixCommand(
                // 这里的createCommandSetter实际直接返回了config.setter
                // 估计是打算以后扩展这个方法,加些额外的操作
                createCommandSetter(config, exchange), config.fallbackUri,
                        exchange, chain, context);

        return Mono.create(s -> {
                    // 2.使用Observable<HystrixCommand>订阅
                    //   订阅的三项内容分别是onNext、onError、onComplete
                    Subscription sub = command.toObservable().subscribe(s::success,
                            s::error, s::success);
                    // 3.Mono取消时,取消Observable<HystrixCommand>的订阅,结束HystrixCommand的执行
                    s.onCancel(sub::unsubscribe);
                    // 4.对异常情况的处理
                }).onErrorResume((Function<Throwable, Mono<Void>>) throwable -> {
                    // a.Hystrix自己的运行时异常
                    if (throwable instanceof HystrixRuntimeException) {
                        HystrixRuntimeException e = (HystrixRuntimeException) throwable;
                        HystrixRuntimeException.FailureType failureType = e
                .getFailureType();
                        // 根据异常类型的不同,返回不同的错误内容
            switch (failureType) {
                // I.超时
                case TIMEOUT:
                    return Mono.error(new TimeoutException());
                // II.服务不可用
                case SHORTCIRCUIT:
                return Mono.error(new ServiceUnavailableException());
                            // III.执行HystrixCommand发生异常
                            case COMMAND_EXCEPTION: {
                                Throwable cause = e.getCause();
                                if (cause instanceof ResponseStatusException
                                    || AnnotatedElementUtils.findMergedAnnotation(
                                                cause.getClass(), ResponseStatus.class) != null) {
                    return Mono.error(cause);
                }
                            }
                            // 这三种异常情况以外,则break,走默认的异常返回逻辑
                            default:break;
            }
                }
                    // b.异常的默认返回
                    return Mono.error(throwable);
                // Mono.then()参数为空,返回空Mono,不再向后发射数据
                }).then();
            });
        }
}

实测 ,

分权重,low是小,用简写;high是大,用全写,

注意:

  • low:- Hystrix=hystrixConsumer,forward:/fallback/port
  • hign:
- name: Hystrix
              args:
                name: hystrixConsumer
                fallbackUri: forward:/fallback/port #官网写了,以forward:开头
routes: #配置路由
        - id: consumer_low
          uri: http://192.168.1.106:8000
          predicates:
            - Path=/cs/** #路径
            - Weight=group1,2 #权重
          filters: # 网关过滤器
            - StripPrefix=1
            - name: RequestRateLimiter #不能简写,因为factory没有shortcut方法,key-resolver使用自己的bean
              args:
                key-resolver: '#{@uriKeyResolver}'
                redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充速率
                redis-rate-limiter.burstCapacity: 5 #令牌桶容量
                redis-rate-limiter.requestedTokens: 1 #每次消耗令牌个数
            - Hystrix=hystrixConsumer,forward:/fallback/port
- id: consumer_high
          uri: http://192.168.1.106:8001
          predicates:
            - name: Path
              args:
                patterns: /cs/**
            - name: Weight
              args:
                weight.group: group1
                weight.weight: 8
          filters:
            - name: StripPrefix
              args:
                parts: 1
            - name: RequestRateLimiter #不能简写,因为factory没有shortcut方法,key-resolver使用自己的bean
              args:
                key-resolver: '#{@uriKeyResolver}'
                redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充速率
                redis-rate-limiter.burstCapacity: 5 #令牌桶容量
                redis-rate-limiter.requestedTokens: 1 #每次消耗令牌个数
            - name: Hystrix
              args:
                name: hystrixConsumer
                fallbackUri: forward:/fallback/port #官网写了,以forward:开头

结果:


low的配置后面只有一个参数,正如源码HystrixGatewayFilterFactory这方法:

@Override
    public List<String> shortcutFieldOrder() {
        return singletonList(NAME_KEY);
    }

所以low这种配置Hystrix=hystrixConsumer,forward:/fallback/port是不对的,如果要fallback,一定要全配。还有就是gateway归gateway,无论跳转方是多少处理时间都无关,一旦大于gateway的默认1s超时,必然降级。熔断也是如此,但是不能用局部hystrixCommadnKey配置熔断,不起效,大概是因为service接口不是在gateway这边。

想要自定义hystrix的超时时间,按照hystrix那样在application配置文件中配置就行了

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000 # 设置hystrix的超时时间,默认1s
      circuitBreaker:
        #在当10秒的时间内,最近20次调用请求,请求错误率超过60%,则触发熔断5秒,期间快速失败,以下都是默认值
        requestVolumeThreshold: 20
        errorThresholdPercentage: 50
        sleepWindowInMilliseconds: 5000
      #设置统计的时间窗口值的毫秒值,circuit break 的打开会根据1个rolling window的统计来计算。
      #若rolling window被设为10000毫秒,则rolling window会被分成n个buckets,
      #每个bucket包含success,failure,timeout,rejection的次数的统计信息。默认10000。
      metrics:
        rollingStats:
          timeInMilliseconds: 10000

参考:
spring-cloud-gateway 10 熔断 HystrixGatewayFilterFactory

官网

相关文章

网友评论

      本文标题:spring-cloud-gateway 降级熔断 Hystri

      本文链接:https://www.haomeiwen.com/subject/tgvwaltx.html