Ратпак с Hystrix

1. Вступление

Ранее у нас была ссылка:/ratpack[показано], как создать высокопроизводительное и реактивное приложение с помощью Ratpack.

В этой статье мы рассмотрим, как интегрировать Netflix Hystrix с приложением Ratpack.

Netflix Hystrix помогает контролировать взаимодействие между распределенными сервисами, изолируя точки доступа, чтобы остановить каскадные сбои, и предоставляя варианты возврата для отказоустойчивости. Это может помочь нам создать более гибкое приложение. Посмотрите нашу ссылку:/Введение в Hystrix[Введение в Hystrix]для быстрого обзора.

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

2. Maven Dependency

Чтобы использовать Hystrix с Ratpack, нам нужна зависимость ratpack-hystrix в проекте pom.xml

<dependency>
    <groupId>io.ratpack</groupId>
    <artifactId>ratpack-hystrix</artifactId>
    <version>1.4.6</version>
</dependency>

Последнюю версию ratpack-hystrix можно найти https://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22ratpack-hystrix%22%20AND%20g%3A%22io.ratpack%22 .[Вот].

В состав ratpack-hystrix входит ratpack-core и hystrix-core .

Чтобы использовать реактивные возможности Ratpack, нам также понадобится ratpack-rx:

<dependency>
    <groupId>io.ratpack</groupId>
    <artifactId>ratpack-rx</artifactId>
    <version>1.4.6</version>
</dependency>

Последняя версия ratpack-rx может быть найдена Вот .

3. Обслуживание с помощью команды Hystrix

При использовании Hystrix базовые службы обычно заключаются в HystrixCommand или HystrixObservableCommand .

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

  • В следующих примерах мы создадим некоторые конечные точки, которые извлекают профиль из Github REST API . **

3.1. Реактивное выполнение команд

Во-первых, давайте создадим реактивный бэкэнд-сервис с Hystrix:

public class HystrixReactiveHttpCommand extends HystrixObservableCommand<String> {

   //...

    @Override
    protected Observable<String> construct() {
        return RxRatpack.observe(httpClient
          .get(uri, r -> r.headers(h -> h.add("User-Agent", "Baeldung HttpClient")))
          .map(res -> res.getBody().getText()));
    }

    @Override
    protected Observable<String> resumeWithFallback() {
        return Observable.just("eugenp's reactive fallback profile");
    }
}

Здесь реактивный Ratpack HttpClient используется для выполнения запроса GET. HystrixReactiveHttpCommand может работать как реактивный обработчик:

chain.get("rx", ctx ->
  new HystrixReactiveHttpCommand(
    ctx.get(HttpClient.class), eugenGithubProfileUri, timeout)
    .toObservable()
    .subscribe(ctx::render));

Конечная точка может быть проверена с помощью следующего теста:

@Test
public void whenFetchReactive__thenGotEugenProfile() {
    assertThat(appUnderTest.getHttpClient().getText("rx"),
      containsString("www.baeldung.com"));
}

3.2. Асинхронное выполнение команд

Асинхронное выполнение HystrixCommand ставит команду в очередь в пуле потоков и возвращает Future :

chain.get("async", ctx -> ctx.render(
  new HystrixAsyncHttpCommand(eugenGithubProfileUri, timeout)
    .queue()
    .get()));

HystrixAsyncHttpCommand выглядит так:

public class HystrixAsyncHttpCommand extends HystrixCommand<String> {

   //...

    @Override
    protected String run() throws Exception {
        return EntityUtils.toString(HttpClientBuilder.create()
          .setDefaultRequestConfig(requestConfig)
          .setDefaultHeaders(Collections.singleton(
            new BasicHeader("User-Agent", "Baeldung Blocking HttpClient")))
          .build().execute(new HttpGet(uri)).getEntity());
    }

    @Override
    protected String getFallback() {
        return "eugenp's async fallback profile";
    }

}

Здесь мы используем блокирующий HttpClient вместо неблокирующего, потому что мы хотим, чтобы Hystrix управлял время ожидания фактической команды, поэтому нам не нужно обрабатывать ее самостоятельно при получении ответа от Future . Это также позволяет Hystrix выполнять откат или кэшировать наш запрос.

Асинхронное выполнение также дает ожидаемый результат:

@Test
public void whenFetchAsync__thenGotEugenProfile() {
    assertThat(appUnderTest.getHttpClient().getText("async"),
      containsString("www.baeldung.com"));
}

3.3. Синхронное выполнение команд

Синхронное выполнение выполняет команду непосредственно в текущем потоке:

chain.get("sync", ctx -> ctx.render(
  new HystrixSyncHttpCommand(eugenGithubProfileUri, timeout).execute()));

Реализация HystrixSyncHttpCommand практически идентична HystrixAsyncHttpCommand за исключением того, что мы даем ему другой запасной результат. Когда он не отступает, он ведет себя так же, как реактивное и асинхронное выполнение:

@Test
public void whenFetchSync__thenGotEugenProfile() {
    assertThat(appUnderTest.getHttpClient().getText("sync"),
      containsString("www.baeldung.com"));
}

4. Метрики

Регистрируя ссылку:/ratpack-google-guice[Guice module]- HystrixModule в реестр Ratpack, мы можем направить запрос в объеме метрики и предоставляют потоки событий через конечную точку GET :

serverSpec.registry(
  Guice.registry(spec -> spec.module(new HystrixModule().sse())))
  .handlers(c -> c.get("hystrix", new HystrixMetricsEventStreamHandler()));

Https://ratpack.io/manual/current/api/ratpack/hystrix/HystrixMetricsEventStreamHandler.html[HystrixMetricsEventStreamHandler] помогает передавать метрики Hystrix в формате text/event-stream , так что мы можем отслеживать метрики в Hystrix Dashboard .

Мы можем настроить standalone панель инструментов Hystrix и добавить наш поток событий Hystrix в список мониторов, чтобы увидеть, как работает наше приложение Ratpack:

ссылка:/uploads/Snip20170815__1.png%20775w[]

После нескольких запросов к нашему приложению Ratpack мы можем увидеть связанные с Hystrix команды на панели инструментов.

4.1. Под капотом

В HystrixModule Hystrix Concurrency Strategy регистрируется в Hystrix через HystrixPlugin для управления контекстом запроса с помощью реестра Ratpack. Это устраняет необходимость инициализации контекста запроса Hystrix перед началом каждого запроса.

public class HystrixModule extends ConfigurableModule<HystrixModule.Config> {

   //...

    @Override
    protected void configure() {
      try {
        HystrixPlugins.getInstance().registerConcurrencyStrategy(
          new HystrixRegistryBackedConcurrencyStrategy());
      } catch (IllegalStateException e) {
       //...
      }
    }

   //...

}

5. Заключение

В этой быстрой статье мы показали, как Hystrix можно интегрировать в Ratpack и как перенести метрики нашего приложения Ratpack в Hystrix Dashboard для лучшего обзора производительности приложения.

Как всегда, полную реализацию можно найти по адресу the проект Github .