1. Введение
Ранее мы показали , как создать высокопроизводительное реактивное приложение с помощью Ratpack.
В этой статье мы рассмотрим, как интегрировать Netflix Hystrix с приложением Ratpack.
Netflix Hystrix помогает контролировать взаимодействие между распределенными службами, изолируя точки доступа для предотвращения каскадных сбоев и предоставляя резервные варианты для обеспечения отказоустойчивости. Это может помочь нам создать более отказоустойчивое приложение. См. наше введение в Hystrix для краткого обзора.
Итак, вот как мы будем его использовать — мы собираемся улучшить наше приложение Ratpack с помощью этих полезных функций, предоставленных Hystrix.
2. Зависимость от Maven
Чтобы использовать Hystrix с Ratpack, нам нужна зависимость ratpack-hystrix в проекте pom.xml
:
<dependency>
<groupId>io.ratpack</groupId>
<artifactId>ratpack-hystrix</artifactId>
<version>1.4.6</version>
</dependency>
Последнюю версию ratpack-hystrix можно найти здесь . В состав 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", "ForEach HttpClient")))
.map(res -> res.getBody().getText()));
}
@Override
protected Observable<String> resumeWithFallback() {
return Observable.just("foreach's reactive fallback profile");
}
}
Здесь реактивный HttpClient Ratpack
используется для выполнения запроса GET. HystrixReactiveHttpCommand может работать
как реактивный обработчик:
chain.get("rx", ctx ->
new HystrixReactiveHttpCommand(
ctx.get(HttpClient.class), foreachGithubProfileUri, timeout)
.toObservable()
.subscribe(ctx::render));
Конечная точка может быть проверена с помощью следующего теста:
@Test
public void whenFetchReactive_thenGotForEachProfile() {
assertThat(appUnderTest.getHttpClient().getText("rx"),
containsString("www.foreach.com"));
}
3.2. Асинхронное выполнение команд
Асинхронное выполнение HystrixCommand ставит
команду в очередь в пуле потоков и возвращает Future
:
chain.get("async", ctx -> ctx.render(
new HystrixAsyncHttpCommand(foreachGithubProfileUri, 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", "ForEach Blocking HttpClient")))
.build().execute(new HttpGet(uri)).getEntity());
}
@Override
protected String getFallback() {
return "foreach's async fallback profile";
}
}
Здесь мы используем блокирующий HttpClient
вместо неблокирующего, потому что мы хотим, чтобы Hystrix контролировал время ожидания выполнения фактической команды, чтобы нам не нужно было обрабатывать его самостоятельно при получении ответа от Future
. Это также позволяет Hystrix резервировать или кэшировать наш запрос.
Асинхронное выполнение также дает ожидаемый результат:
@Test
public void whenFetchAsync_thenGotForEachProfile() {
assertThat(appUnderTest.getHttpClient().getText("async"),
containsString("www.foreach.com"));
}
3.3. Синхронное выполнение команд
Синхронное выполнение выполняет команду непосредственно в текущем потоке:
chain.get("sync", ctx -> ctx.render(
new HystrixSyncHttpCommand(foreachGithubProfileUri, timeout).execute()));
Реализация HystrixSyncHttpCommand
почти идентична HystrixAsyncHttpCommand
, за исключением того, что мы даем ей другой резервный результат. Если не отступать, он ведет себя так же, как реактивное и асинхронное выполнение:
@Test
public void whenFetchSync_thenGotForEachProfile() {
assertThat(appUnderTest.getHttpClient().getText("sync"),
containsString("www.foreach.com"));
}
4. Метрики
Зарегистрировав модуль Guice — HystrixModule
в реестре Ratpack, мы можем передавать метрики области запроса и предоставлять потоки событий через конечную точку GET
:
serverSpec.registry(
Guice.registry(spec -> spec.module(new HystrixModule().sse())))
.handlers(c -> c.get("hystrix", new HystrixMetricsEventStreamHandler()));
HystrixMetricsEventStreamHandler помогает передавать метрики Hystrix в текстовом
формате /формате потока событий
, чтобы мы могли отслеживать метрики в Hystrix Dashboard
.
Мы можем настроить автономную панель инструментов Hystrix и добавить наш поток событий Hystrix в список мониторов, чтобы увидеть, как работает наше приложение Ratpack:
После нескольких запросов к нашему приложению Ratpack мы можем увидеть команды, связанные с Hystrix, на панели инструментов.
4.1. Под капотом
В HystrixModule
стратегия параллелизма Hystrix регистрируется в 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 для лучшего представления производительности приложения.
Как всегда, полную реализацию можно найти в проекте Github .