Программное изменение свойств Hystrix

У меня есть автоматический выключатель, параметры которого я хотел бы изменить во время работы. Такие вещи, как потоки и время ожидания, должны быть настроены на сайте клиента.

Я создаю 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).

Это работает в первый раз, но когда я пытаюсь изменить свойства во время выполнения (то же имя группы), ничего не происходит. Есть ли другой способ программно изменить это?

Я не хочу просматривать файлы свойств или указывать URL-адрес Archaius.

Есть также ответы, которые говорят мне пройти через Archaius с помощью ConfigurationManager.getConfigInstance().setProperty("...") . Но наверняка должен быть способ, похожий на оригинальные сеттеры, которые я создаю? Делать это совершенно по-другому, потому что это второй раз, просто неудобно.


person Anders S    schedule 18.10.2016    source источник


Ответы (5)


Поздний ответ, но сегодня я боролся с тем же и нашел способ.

Способ реализации диспетчера свойств по умолчанию заключается в том, что он использует кэш HystrixCommandProperties на основе имени выполняемой вами команды. При первом использовании команды она кэширует то, что получает из HystrixCommandProperties.Setter, переданного конструктору команды, и все.

Однако, используя пользовательский HystrixPropertiesStrategy в качестве плагина, вы можете переопределить ключ кэша (и, следовательно, принудительно Hystrix для повторной оценки Setter, переданного новому экземпляру Command, поскольку ключ кэша новый, поэтому он считает, что это новая команда).

Тогда код будет выглядеть примерно так:

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);
    }
}

В качестве альтернативы вы всегда можете вернуть null из метода getCommandPropertiesCacheKey (который полностью отключает кеширование), но тогда у вас возникнут накладные расходы, связанные с тем, что Hystrix должен реконструировать HystrixCommandProperties каждый раз, когда вызывается команда.

PS: обязательно используйте правильную синхронизацию потоков для чтения и обновления этих свойств, потому что они будут вызываться из разных потоков. Я опустил это в этом примере для простоты, но на самом деле я использую ReentrantReadWriteLock в своем коде для защиты доступа к этим переменным.

person Michal Boska    schedule 22.05.2017

Для справки в будущем: в итоге я использовал настройки через ConfigurationManager и строковое свойство.

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

Это позволяет мне что-то менять, но менее безопасным способом, чем исходный код. Какое-то время я боролся с опечаткой в ​​​​строке, поэтому я хотел бы этого избежать.

Теперь я использую это для всех свойств, которые мне нужны для изменения среды выполнения. Создание нового автоматического выключателя Hystrix каждый раз, когда что-то меняется (новая командная клавиша), также может быть вариантом, но позже это приведет к поломке с использованием файлов свойств.

person Anders S    schedule 15.11.2016
comment
Я столкнулся с аналогичной проблемой: как только я создаю первый HystrixCommand с сеттером в определенной группе, я не могу позже изменить свойства, создав новый HystrixCommand с другим сеттером (в той же группе). Так действительно ли дело в том, что hystrix каким-то образом кэширует свойства из первого полученного сеттера, и, кроме использования ConfigurationManager, действительно нет способа изменить свойства? - person Michal Boska; 22.05.2017

Есть очень простой способ сделать это. Это просто нужно 2 шага: а. регистрация правильного плагина b. Добавление правильной стратегии с требуемым переопределением.

Вариант использования: переопределите ExecutionTimeoutInMilliseconds на 30000 мс с 1000 мс.

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
person Harry    schedule 08.06.2018

Свойства Hystrix также можно установить в нашем сервисном классе внутри аннотации @HystrixCommand, для этого мы используем ссылку Hystrix-Javanica, который используется для реализации аннотаций в нашем проекте. Для этого нам нужно добавить зависимость hystrix-javanica в наш путь к классам.

Зависимость от 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, чтобы вы могли лучше им управлять и изменять их для разных сред.

Вот пример конфигурации hystrix в моем application.yaml

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 посетите здесь

person Sumanth Duvvuru    schedule 01.11.2016
comment
Мне нужно программно изменить свойства во время выполнения, поэтому вы на самом деле не отвечаете на мой вопрос. Javanica хороша, но у нас нет людей, которые меняют параметры через файлы. Теоретически я мог бы писать в файл из кода, но это еще более хлопотно и косвенно, чем то, что я делаю сейчас: ConfigurationManager.getConfigInstance().setProperty(...) . Я просто хотел бы использовать строго типизированный API для изменения свойств после первой инициализации, как я это сделал в первую очередь. Строки и возможные опечатки/недоразумения только мешают. Как это было, когда я переключился на него... - person Anders S; 10.11.2016

Для меня HystrixPropertiesStrategy и ConfigurationManager.getConfigInstance().setProperty(..) не помогли, в итоге я создал свою собственную реализацию HystrixDynamicProperty следующим образом:

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);
                 }


    }
}

и добавьте ниже Свойство перед запуском приложения весенней загрузки.

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

Для любознательных разработчиков: метод getDynamicProperty из HystrixPropertiesChainedProperty переопределяет переопределенное значение с помощью HystrixPropertiesStrategy, которое вызывается "AbstractCommand" каждый раз перед настройкой HystrixCommand для выполнения, поэтому Идея HystrixPropertiesStrategy у меня не сработала.

person Peru    schedule 08.12.2019