gateway整合hystrix参数配置踩坑-爱代码爱编程
问题
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 更改默认并发数配置
经过测试后,执行了线程的隔离策略,压测正常