Сводка проблем тайм-аута и повторных попыток SpringCloud Ribbon/Feign/Hystrix

Spring Cloud
Сводка проблем тайм-аута и повторных попыток SpringCloud Ribbon/Feign/Hystrix

Привет, у меня пустая ночь, и я не видел тебя уже неделю!

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

В Spring Cloud для вызовов службы обычно используется имитация или лента. Лента также поставляется с механизмом балансировки нагрузки и повторных попыток. И притворство основано на ленте.

Обычно, чтобы обеспечить высокую доступность сервисов и предотвратить такие проблемы, как лавины, вводят еще и hystrix. Предохранитель hystrix также связан с периодом тайм-аута.

Как рассмотреть взаимосвязь между лентой, фейком и гистриксом в целом, добавить соответствующую конфигурацию и заставить каждый компонент выполнять свои обязанности и координировать взаимодействие — хлопотная проблема.

Это лысый думать об этом.

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

Сначала есть следствие:

Feign объединяет ленту и hystrix, сам Feign не имеет ограничения по времени ожидания, и его время ожидания контролируется лентой и hystrix.

Поэтому нам просто нужно разобраться с тайм-аутом между лентой и hystrix.


Ниже в качестве примера используется лента для проверки тайм-аута по умолчанию и интегрированного использования с hystrix.

1. Конфигурация ленты по умолчанию

Конфигурация ленты по умолчанию находится в классе DefaultClientConfigImpl.

    public static final int DEFAULT_READ_TIMEOUT = 5000;

    public static final int DEFAULT_CONNECTION_MANAGER_TIMEOUT = 2000;

    public static final int DEFAULT_CONNECT_TIMEOUT = 2000;

Обратите внимание, что здесь появляется первая воронка: хотя класс DefaultClientConfigImpl указывает DEFAULT_READ_TIMEOUT как 5000 мс, отладка обнаружила, что это значение по умолчанию было заменено при создании ленты clientConfig.

детали следующим образом:

При использовании интерфейса запроса ленты в первый раз создается объект IClienConfig.Этот метод находится в классе RibbonClientConfiguration.В это время сбрасываются ConnectTimeout, ReadTimeout, GZipPayload.

public class RibbonClientConfiguration {

    /**
     * Ribbon client default connect timeout.
     */
    public static final int DEFAULT_CONNECT_TIMEOUT = 1000;

    /**
     * Ribbon client default read timeout.
     */
    public static final int DEFAULT_READ_TIMEOUT = 1000;

    /**
     * Ribbon client default Gzip Payload flag.
     */
    public static final boolean DEFAULT_GZIP_PAYLOAD = true;

    @RibbonClientName
    private String name = "client";

    @Autowired
    private PropertiesFactory propertiesFactory;

    @Bean
    @ConditionalOnMissingBean
    public IClientConfig ribbonClientConfig() {
        DefaultClientConfigImpl config = new DefaultClientConfigImpl();
        config.loadProperties(this.name);
        config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT);
        config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);
        config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD);
        return config;
    }
    
    //...
}

Таким образом, ConnectTimeout и ReadTimeout ленты по умолчанию равны 1000 мс.

Давайте посмотрим на пользовательскую конфигурацию.


2. Пользовательская конфигурация ленты

Давайте настроим конфигурацию через ленту.xxx, чтобы увидеть, может ли она подействовать:

ribbon:
  OkToRetryOnAllOperations: true #对所有操作请求都进行重试,默认false
  ReadTimeout: 1000   #负载均衡超时时间,默认值5000
  ConnectTimeout: 3000 #请求连接的超时时间,默认值2000
  MaxAutoRetries: 1    #对当前实例的重试次数,默认0
  MaxAutoRetriesNextServer: 0 #重试切换实例的次数,默认1

Обнаружение тестов не работает. Что за жир? Это то, что некоторые друзья программиста написали в Интернете.

Причина очень проста: необходимо добавить конфигурацию ленточки.http.client.enabled = true, и может вступить в силу конфигурация тайм-аута пользовательской ленты.

ribbon:
  http:
    client:
      enabled: true

Давайте проверим механизм тайм-аута и повторной попытки:

(Для интима я привел скриншот теста, надеюсь, вы меня любите, простите!)

Здесь я включил службу производителя, чтобы предоставить интерфейс, который, вероятно, выглядит следующим образом:

    @GetMapping(value = "hello/{name}")
    public String hello(@PathVariable("name") String name, Integer mills) {
        logger.info("开始执行请求,name: " + name + "要求暂停:" + mills + "毫秒");
        if (mills != null && mills > 0) {
            try {
                Thread.sleep(mills);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return "hello, [" + name + "], this is service producer by nacos.....";
    }

Обратите внимание, что существует параметр mills для указания времени ожидания интерфейса производителя, чтобы можно было проверить механизм тайм-аута и повторных попыток службы потребителя (то есть службы, которая использует ленту для вызова интерфейса производителя).

Потребитель, вероятно, таков:

    @GetMapping(value = "test")
    //@HystrixCommand(fallbackMethod = "testHystrix")
    public String test(String name, Integer mills) {
        logger.info("开始请求 producer,其暂停时间为:" + mills);
        String producerRes = restTemplate.getForObject(
                "http://" + service_producer_name + "/producer/hello/" + name + "?mills=" + mills, String.class);
        logger.info("请求获取成功,开始打印请求结果:");
        String res = "测试consumer/test接口,基于ribbon调取服务server-producer的hello接口,返回:" + producerRes;
        System.out.println(res);
        return res;
    }

Тестовый код готов, приступим к тестированию:

Во-первых, текущий экземпляр повторяет попытку один раз:

Запрошенный ReadTimeOut установлен на 5 с, 1 + MaxAutoRetries = 2, дважды, ровно 10 с

Посмотрим на сторону производителя:

Следующее устанавливает для MaxAutoRetries и MaxAutoRetriesNextServer значение 1:

Глядя на сторону производителя, запрос поступает каждые 5 секунд, всего 4:

Почему это запрашивается четыре раза?

Почему установка для MaxAutoRetriesNextServer значения 1 добавляет к запросу 2 попытки?

MaxAutoRetriesNextServer напрямую переводится как: максимальное количество повторных попыток для следующего сервиса.

Этот приземленный перевод звучит как количество повторных попыток для следующего сервиса. Это должно быть 1? Какая следующая услуга здесь?

Не паникуй, маленькая сцена. Давайте изменим конфигурацию, MaxAutoRetries установлено значение 2, MaxAutoRetriesNextServer установлено значение 3;

Здесь мы запускаем двух производителей с одинаковым именем, затем появляются два экземпляра этого сервиса;

есть тест:

(Интимно я отметила для вас результаты анализа на картинке, очень тепло?)

другой продюсер:

Согласно расчету времени в логе, реальное значение MaxAutoRetriesNextServer должно быть таким: в случае сбоя запроса максимальное количество экземпляров службы для переключения (независимо от того, сколько экземпляров, даже один экземпляр переключится обратно на сам экземпляр MaxAutoRetriesNextServer раз)

Ниже делаем вывод, что в ленте запросы будут выполняться максимум - 1 + maxAutoRetries + (maxAutoRetries + 1) * MaxAutoRetriesNextServer

То есть (1 + maxAutoRetries ) * (1 + MaxAutoRetriesNextServer) раз

Распорядок отморозка, ленты, нами тщательно проанализирован. Далее нам предстоит столкнуться с отморозком + теплым мальчиком, сочетание ленты + гистрикс.


3. Тайм-аут и повторная настройка после интеграции ленты с hystrix

Почему его называют теплым человеком hystrix? Конечно, есть причина.

hystrix — это компонент деградации сервиса, ограничения тока и фьюзинга. Это может эффективно обеспечить стабильность микросервисной платформы и избежать возникновения лавин и других явлений. Итак, hystrix еще очень теплый.

Интеграция hystrix с лентой проста:

Добавьте аннотацию @EnableHystrix в класс запуска.

Добавьте @HystrixCommand в интерфейс и настройте резервный метод:

    @GetMapping(value = "test")
    @HystrixCommand(fallbackMethod = "testHystrix")
    public String test(String name, Integer mills) {
        logger.info("开始请求 producer,其暂停时间为:" + mills);
        String producerRes = restTemplate.getForObject(
                "http://" + service_producer_name + "/producer/hello/" + name + "?mills=" + mills, String.class);
        logger.info("请求获取成功,开始打印请求结果:");
        String res = "测试consumer/test接口,基于ribbon调取服务server-producer的hello接口,返回:" + producerRes;
        System.out.println(res);
        return res;
    }

    /**
     * test接口的断路器
     * @param name
     * @return
     */
    private String testHystrix(String name, Integer mills) {
        return "sorry, " + name + ", this service is unavailable temporarily. We are returning the defaultValue by hystrix.";
    }

Проверьте это:

производитель делает паузу на 500 мс, нормально

Производитель делает паузу на 1000 мс, и запрос обрабатывается резервным методом, указанным @HystrixCommand:

Примечание. Если откат не настроен, тайм-аут hystrix не вступит в силу, но будет управляться лентой.

Тайм-аут hystrix по умолчанию составляет 1 с, который настраивается в классе HystrixCommandProperties:

private static final Integer default_executionTimeoutInMilliseconds = 1000; // default => executionTimeoutInMilliseconds: 1000 = 1 second

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

    // ...
    this.executionTimeoutEnabled = getProperty(propertyPrefix, key, "execution.timeout.enabled", builder.getExecutionTimeoutEnabled(), default_executionTimeoutEnabled);
    // ...
}

Продолжайте проверять взаимосвязь между временем ожидания ленты и hystrix.

После настройки отката hystrix измените файл конфигурации и установите время ожидания hystrix больше, чем время ожидания ленты:

ribbon:
  OkToRetryOnAllOperations: true #对所有操作请求都进行重试,默认false
  ReadTimeout: 2000   #负载均衡超时时间,默认值5000
  ConnectTimeout: 3000 #ribbon请求连接的超时时间,默认值2000
  MaxAutoRetries: 0     #对当前实例的重试次数,默认0
  MaxAutoRetriesNextServer: 0 #对切换实例的重试次数,默认1
  # 如果不添加 ribbon.http.client.enabled=true,那么 ribbon 的默认配置不会生效
  http:
    client:
      enabled: true


hystrix:
  command:
    default:  #default全局有效,service id指定应用有效
      execution:
        timeout:
          #如果enabled设置为false,则请求超时交给ribbon控制,为true,则超时作为熔断根据
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 10000 #断路器超时时间,默认1000ms

На этом этапе используйте postman для отправки сообщения:

Мы видим, что запрос возвращается примерно через 2 секунды, и это значение точно соответствует времени ленты.ReadTimeout. Указывает, что в это время инициируется тайм-аут ленты. Затем начался процесс слияния hystrix.


4. Вывод

В заключение:

  1. Если время запроса превышает конфигурацию тайм-аута ленты, будет инициирована повторная попытка;

  2. В случае настройки отката, если время запроса (включая время повтора ленты) превышает лимит времени ожидания ленты или лимит времени ожидания hystrix, он будет сброшен;

Вообще говоря, тайм-аут ленты установлен на

Поскольку connectionTime обычно короткое, его можно игнорировать. Затем установленное время ожидания должно удовлетворять:

(1 + MaxAutoRetries) * (1 + MaxAutoRetriesNextServer)ReadTimeOut timeoutInMilliseconds*


Это конец сегодняшнего обмена, не забудьте нажатьобрати внимание нанажмитеотличный! Мой официальный аккаунт:обезьяний язык(Я БЫ:JavaApes)