代码编织梦想

问题

gateway整合hystrix,测试熔断功能。

spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          # 开启负载均衡对网关的路由转发的支持
          enabled: true
      enabled: true    
      default-filters:
        # 熔断过滤器
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackuri: forward:/fallexecute
      # 负载均衡路由规则 开启路由后的服务swagger才能显示
      routes:
        - id: test-service
          uri: lb://test-service
          predicates:
            - Path=/gateway/test/**
          filters:
            - StripPrefix=2
          metadata:
            title: 测试系统
# Hystrix 配置
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true  
          thread:
            timeoutInMilliseconds: 6000
    fallbackcmd:
      execution:
        timeout:
          enabled: true
          timeoutInMilliseconds : 20000
          thread:
            timeoutInMilliseconds: 20000 # Hystrix 的 fallbackcmd 时间
  threadpool:
    default:
      coreSize: 300 # Hystrix 更改默认并发数配置

将线程池线程数设置为300,进行压测,发现并发数在10左右就会进入fallexecute熔断。

说明参数设置的不对,按照官网设置的参数配置也不对,只好进入源码分析。

定位到AbstractCommand#executeCommandWithSpecifiedIsolation

private Observable<R> executeCommandWithSpecifiedIsolation(final AbstractCommand<R> _cmd) {
    if (properties.executionIsolationStrategy().get() == ExecutionIsolationStrategy.THREAD) {
        // mark that we are executing in a thread (even if we end up being rejected we still were a THREAD execution and not SEMAPHORE)
        // 执行线程池的方式
    } else {
        // 执行信号量的方式
    }
}

发现隔离策略是SEMAPHORE(默认的并发数就是10),但默认的策略应该是THREAD才对,只能接着来分析

分析流程

当服务启动时执行从HystrixGatewayFilterFactory#apply一直调佣到HystrixObservableCommand.Setter#Setter

HystrixObservableCommand.Setter#Setter

protected Setter(HystrixCommandGroupKey groupKey) {
    this.groupKey = groupKey;

    // default to using SEMAPHORE for ObservableCommand
    commandPropertiesDefaults = setDefaults(HystrixCommandProperties.Setter());
}
private HystrixCommandProperties.Setter setDefaults(HystrixCommandProperties.Setter commandPropertiesDefaults) {
    if (commandPropertiesDefaults.getExecutionIsolationStrategy() == null) {
        // default to using SEMAPHORE for ObservableCommand if the user didn't set it
        commandPropertiesDefaults.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE);
    }
    return commandPropertiesDefaults;
}
public Setter withExecutionIsolationStrategy(ExecutionIsolationStrategy value) {
    this.executionIsolationStrategy = value;
    return this;
}

可以看到如果没有配置的话,默认的策略为SEMAPHORE

HystrixCommandProperties

当服务启动后,第一次调用gateway服务后,会进行加载HystrixCommandProperties

protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder, String propertyPrefix) {

        this.executionIsolationStrategy = getProperty(propertyPrefix, key, "execution.isolation.strategy", builder.getExecutionIsolationStrategy(), default_executionIsolationStrategy);        
}

注意builder.getExecutionIsolationStrategy()的值为SEMAPHORE(上面分析过了),default_executionIsolationStrategy为THREAD

HystrixCommandProperties#getProperty

private static HystrixProperty<ExecutionIsolationStrategy> getProperty(final String propertyPrefix, final HystrixCommandKey key, final String instanceProperty, final ExecutionIsolationStrategy builderOverrideValue, final ExecutionIsolationStrategy defaultValue) {
    return new ExecutionIsolationStrategyHystrixProperty(builderOverrideValue, key, propertyPrefix, defaultValue, instanceProperty);

}

new ExecutionIsolationStrategyHystrixProperty

private static final class ExecutionIsolationStrategyHystrixProperty implements HystrixProperty<ExecutionIsolationStrategy> {
    private final HystrixDynamicProperty<String> property;
    private volatile ExecutionIsolationStrategy value;
    private final ExecutionIsolationStrategy defaultValue;

    private ExecutionIsolationStrategyHystrixProperty(ExecutionIsolationStrategy builderOverrideValue, HystrixCommandKey key, String propertyPrefix, ExecutionIsolationStrategy defaultValue, String instanceProperty) {
        //defaultValue为THREAD
        this.defaultValue = defaultValue;
        String overrideValue = null;
        //builderOverrideValue为SEMAPHORE,上面分析过的
        if (builderOverrideValue != null) {
            overrideValue = builderOverrideValue.name();
        }
        //如果不配置则默认值为SEMAPHORE,如果配置则为配置中的值。
        //进行熔断器的配置:
        //hystrix.command.fallbackcmd.execution.isolation.strategy = THREAD
        property = forString()
                .add(propertyPrefix + ".command." + key.name() + "." + instanceProperty, overrideValue)
                .add(propertyPrefix + ".command.default." + instanceProperty, defaultValue.name())
                .build();

        // initialize the enum value from the property
        // 将property的值赋值给value,用于后续判断隔离策略        
        parseProperty();

        // use a callback to handle changes so we only handle the parse cost on updates rather than every fetch
        property.addCallback(new Runnable() {

            @Override
            public void run() {
                // when the property value changes we'll update the value
                parseProperty();
            }

        });
    }

    @Override
    public ExecutionIsolationStrategy get() {
        return value;
    }

    private void parseProperty() {
        try {
            value = ExecutionIsolationStrategy.valueOf(property.get());
        } catch (Exception e) {
            logger.error("Unable to derive ExecutionIsolationStrategy from property value: " + property.get(), e);
            // use the default value
            value = defaultValue;
        }
    }
}

gateway调用方式时,选择hystrix的隔离策略

上面分析了隔离策略的赋值方式,然后就到了隔离策略的判断逻辑

AbstractCommand#executeCommandWithSpecifiedIsolation

private Observable<R> executeCommandWithSpecifiedIsolation(final AbstractCommand<R> _cmd) {
    if (properties.executionIsolationStrategy().get() == ExecutionIsolationStrategy.THREAD) {
        // mark that we are executing in a thread (even if we end up being rejected we still were a THREAD execution and not SEMAPHORE)
        // 执行线程池的方式
    } else {
        // 执行信号量的方式
    }
}

上述分析后,我们知道了要将熔断器的名字来显示的设置为THREAD模式,添加配置参数hystrix.command.fallbackcmd.execution.isolation.strategy = THREAD

spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          # 开启负载均衡对网关的路由转发的支持
          enabled: true
      enabled: true    
      default-filters:
        # 熔断过滤器
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackuri: forward:/fallexecute
      # 负载均衡路由规则 开启路由后的服务swagger才能显示
      routes:
        - id: test-service
          uri: lb://test-service
          predicates:
            - Path=/gateway/test/**
          filters:
            - StripPrefix=2
          metadata:
            title: 测试系统
# Hystrix 配置
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true  
          thread:
            timeoutInMilliseconds: 6000
    fallbackcmd:
      execution:
        timeout:
          enabled: true
          timeoutInMilliseconds : 20000
          thread:
            timeoutInMilliseconds: 20000 # Hystrix 的 fallbackcmd 时间
        isolation:
          strategy: THREAD    
  threadpool:
    default:
      coreSize: 300 # Hystrix 更改默认并发数配置

经过测试后,执行了线程的隔离策略,压测正常

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/guntun8987/article/details/130887689