以编程方式更改 Hystrix 属性

Programmatically changing Hystrix properties

我设置了一个断路器,我想更改运行时的参数。线程和超时等需要在客户现场进行调整。

我这样创建 HystrixCommandProperties.Setter:

HystrixCommandProperties.Setter hystrixProps = 
    HystrixCommandProperties.defaultSetter()
        .withCircuitBreakerSleepWindowInMilliseconds(myconf.sleepWindow);
HystrixThreadPoolProperties.Setter threadPoolSettings = 
    HystrixThreadPoolProperties.Setter()
        .withCoreSize(myconf.threadPoolSize);

new MyCommand(HystrixCommand.Setter.withGroupKey("mygroup")
    .andCommandPropertiesDefaults(hystrixProps)
    .andThreadPoolPropertiesDefaults(threadPoolSettings));

MyCommand 实现标准的 HystrixCommand 并调用 super(hystrixProps)。

这第一次有效,但是当我尝试在运行时更改属性(相同的组名)时,没有任何反应。还有另一种方法可以以编程方式更改它吗?

我不想浏览 属性 文件或向 Archaius 指定 URL。

还有一些答案告诉我使用 ConfigurationManager.getConfigInstance().setProperty("...") 来检查 Archaius。但是肯定必须有一种类似于我创建的原始设置器的方法吗?完全不同,因为这是第二次,感觉很尴尬。

Hystrix properties can also be set in our service class inside @HystrixCommand annotation, for this we use the Hystrix-Javanica project which is used for implementing the annotations in our project. For that we need to add the dependency of hystrix-javanica into our classpath.

Maven 的依赖项:

<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-javanica</artifactId>
    <version>x.y.z</version>
</dependency>

在@HystrixCommand 注释中,我们可以使用@HystrixProperty 来设置hystrix 的属性。

示例@HystrixCommand 属性设置:

@HystrixCommand(groupKey = "StoreSubmission", commandKey = "StoreSubmission", threadPoolKey = "StoreSubmission", commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "30000"),
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "4"),
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "60000"),
        @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "180000") }, threadPoolProperties = {
        @HystrixProperty(name = "coreSize", value = "30"),
        @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "180000") })
public String storeSubmission(ReturnType returnType, InputStream is, String id) {
}

定义这些属性的最佳方式是在外部化 application.yaml 中,这样您可以更好地控制它并针对不同的环境更改它们。

这是我的 application.yaml

中的示例 hystrix 配置
hystrix:
   command.StoreSubmission.execution.isolation.thread.timeoutInMilliseconds: 30000
   command.StoreSubmission.circuitBreaker.requestVolumeThreshold: 4
   command.StoreSubmission.circuitBreaker.sleepWindowInMilliseconds: 60000
   command.StoreSubmission.metrics.rollingStats.timeInMilliseconds: 180000
   collapser.StoreSubmission.maxRequestsInBatch: 1
   collapser.StoreSubmission.requestCache.enabled: FALSE
   threadpool.StoreSubmission.coreSize: 30
   threadpool.StoreSubmission.metrics.rollingStats.timeInMilliseconds: 180000

application.yml 文件的确切格式是

hystrix:
    command:
        findAllProducts:
            execution:
                isolation:
                    thread:
                        timeoutInMilliseconds: 1000
            circuitBreaker:
                requestVolumeThreshold: 20
                errorThresholdPercentage: 50
            metrics:
                rollingStats:
                    timeInMilliseconds: 10000
                    numBuckets: 10
    threadpool:
        ProductService:
            coreSize: 10

有关 Hystrix-Javanica 的更多信息,请访问 here

供将来参考:我最终通过 ConfigurationManager 和字符串 属性 使用了设置。

ConfigurationManager.getConfigInstance().setProperty("...")

它让我改变了一些东西,但以一种比原始代码更不安全的方式。我确实为字符串中的拼写错误苦苦挣扎了一段时间,这就是为什么我想避免这种情况。

我现在将其用于更改运行时所需的所有属性。每次更改(新命令键)时创建一个新的 Hystrix 断路器也是一个选项,但稍后会使用属性文件中断。

迟到的答案,但今天我为同样的事情苦苦挣扎并找到了方法。

默认 属性 管理器的实现方式是根据您 运行 命令的名称使用 HystrixCommandProperties 的缓存。在第一次使用该命令时,它会缓存从 HystrixCommandProperties.Setter 传递给命令构造函数的内容,仅此而已。

但是,使用自定义 HystrixPropertiesStrategy 作为 Plugin 您可以覆盖缓存键(因此强制 Hystrix 重新评估传递给新命令实例的 Setter,因为缓存键是新的,所以它认为这是一个新的命令)。

代码将类似于:

public HystrixCommandFactory(....) {
    HystrixPlugins.getInstance().registerPropertiesStrategy(new HystrixPropertiesStrategyWithReloadableCache());
    updateHystrixSettings();        
}

//configurable attributes
private volatile int commandTimeoutMillis;
private volatile long lastSettingsUpdatedTimestamp;
private volatile HystrixCommand.Setter setterForNewCommands;

private void updateHystrixSettings() {
    lastSettingsUpdatedTimestamp = LocalDateTime.now().toDateTime().getMillis();
    HystrixCommandProperties.Setter propertiesSetter = HystrixCommandProperties.Setter()
        .withExecutionTimeoutInMilliseconds(commandTimeoutMillis)
        .withExecutionTimeoutEnabled(true);

    this.setterForNewCommands = HystrixCommand.Setter
        .withGroupKey(HystrixCommandGroupKey.Factory.asKey(GROUP_NAME))
        .andCommandPropertiesDefaults(propertiesSetter);

}

public void setCommandTimeoutMillis(int commandTimeoutMillis) {     
    this.commandTimeoutMillis = commandTimeoutMillis;
    updateHystrixSettings();        
}

private class HystrixPropertiesStrategyWithReloadableCache extends HystrixPropertiesStrategy {

    @Override
    public String getCommandPropertiesCacheKey(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) {
        return String.format("%s-%d", commandKey.name(), lastSettingsUpdatedTimestamp);
    }
}

或者,您总是可以从 getCommandPropertiesCacheKey 方法(完全关闭缓存)中 return null,但是这样您就有了 Hystrix 必须重建 HystrixCommandProperties 每次调用命令时

PS:确保使用适当的线程同步来读取和更新这些属性,因为这些属性将从不同的线程调用。为简单起见,我在此示例中省略了它,但实际上我在代码中使用 ReentrantReadWriteLock 来保护对这些变量的访问

有一种非常简单的方法可以做到这一点。它只需要2个步骤: 一种。注册正确的插件 b.添加具有所需覆盖的正确策略。

用例:将 ExecutionTimeoutInMilliseconds 从 1000 毫秒覆盖为 30000 毫秒

HystrixPlugins.getInstance().registerPropertiesStrategy(new HystrixPropertiesStrategy() {
            @Override
            public HystrixCommandProperties getCommandProperties(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) {
                HystrixCommandProperties.Setter timeout
                        = HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(30000);
                return super.getCommandProperties(commandKey, timeout);
            }
        });

这里我只是覆盖了必需的属性。当您 运行 您的应用程序时,您可以在 DEBUG 模式下看到:

2018-06-08 23:18:32 [main] DEBUG c.n.h.s.p.HystrixPropertiesChainedProperty - Flipping property: hystrix.command.Client#getAllData().execution.isolation.thread.timeoutInMilliseconds to use its current value: 30000

对我来说 HystrixPropertiesStrategyConfigurationManager.getConfigInstance().setProperty(..) 没有帮助,我最终创建了自己的 HystrixDynamic属性 实现如下,

public CustomHystrixDynamicProperty extends HystrixDynamicPropertiesArchaius {

    @Override
    public HystrixDynamicProperty<Integer> getInteger(final String name, final Integer fallback) {
         if(name.equals("Your hystrix Property")){
            return new HystrixDynamicProperty<Integer>() {
            public Integer get() {
               // Place your logic here...
              return yourValue;
             }
           public String getName(){ return name;};
           public void addCallback(Runnable callback) {};

              }
           } else {
                return super.getInteger(name,fallback);
                 }


    }
}

并在启动 spring 引导应用程序之前在下面添加 属性。

System.setProperty("hystrix.plugin.HystrixDynamicProperties.implementation","YourPackage.CustomHystrixDynamicProperty");

对于好奇的开发人员: : HystrixPropertiesChained属性 中的 getDynamic属性 方法正在通过 HystrixPropertiesStrategy[=22 覆盖覆盖的值=],每次在设置要执行的 HystrixCommand 之前都会被 "AbstractCommand" 调用, 所以 HystrixPropertiesStrategy 的想法对我不起作用。