Ratpack with Hystrix – 有Hystrix的Ratpack

最后修改: 2017年 8月 22日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

Previously, we have shown how to build a high-performance and reactive application with Ratpack.

在此之前,我们已经展示了如何使用Ratpack构建一个高性能和反应式的应用程序。

In this article, we’ll look at how to integrate Netflix Hystrix with a Ratpack application.

在这篇文章中,我们将看看如何将Netflix Hystrix与Ratpack应用程序整合。

Netflix Hystrix helps control interactions between distributed services by isolating points of access to stop cascading failures and providing fallback options for fault tolerance. It can help us build a more resilient application. See our introduction to Hystrix for a quick review.

Netflix Hystrix通过隔离访问点来帮助控制分布式服务之间的互动,以阻止级联故障,并为容错提供回退选项。它可以帮助我们建立一个更有弹性的应用程序。请参阅我们的Hystrix简介以获得快速回顾。

And so, that’s how we’ll use it – we’re going to enhance our Ratpack application with these useful features out by Hystrix.

因此,这就是我们将如何使用它–我们将用Hystrix提供的这些有用的功能来增强我们的Ratpack应用程序。

2. Maven Dependency

2.Maven的依赖性

To use Hystrix with Ratpack, we need the ratpack-hystrix dependency in the project pom.xml:

为了将Hystrix与Ratpack一起使用,我们需要在项目pom.xml中加入ratpack-hystrix依赖。

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

The latest version of ratpack-hystrix can be found here. The ratpack-hystrix includes ratpack-core and hystrix-core.

最新版本的 ratpack-hystrix 可以在这里找到。ratpack-hystrix包括ratpack-core>和hystrix-core>。

To make use of reactive features of Ratpack, we would also need ratpack-rx:

为了利用Ratpack的反应性功能,我们还需要 ratpack-rx。

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

The latest version of ratpack-rx can be found here.

最新版本的 ratpack-rx 可以在这里找到。

3. Serving With Hystrix Command

3.用Hystrix命令服务

When using Hystrix, underlying services are typically wrapped in HystrixCommand or HystrixObservableCommand. Hystrix supports executing these Commands in ways of synchronous, asynchronous and reactive. Among these, only reactive is nonblocking and officially recommended.

在使用Hystrix时,底层服务通常被包裹在HystrixCommandHystrixObservableCommand。Hystrix支持以同步、异步和反应式的方式执行这些命令。在这些方式中,只有反应式是无阻塞的,官方推荐使用。

In the following examples, we’ll build some endpoints that fetch a profile from Github REST API.

在下面的例子中,我们将建立一些端点,从Github REST API中获取一个配置文件。

3.1. Reactive Command Execution

3.1.反应式命令的执行

First, let’s build a reactive backend service with Hystrix:

首先,让我们用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");
    }
}

Here a Ratpack reactive HttpClient is used to make a GET request. The HystrixReactiveHttpCommand can perform as a reactive handler:

这里,一个Ratpack的反应式HttpClient被用来做一个GET请求。HystrixReactiveHttpCommand可以作为一个反应式处理程序执行。

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

The endpoint can be verified with the following test:

可以通过以下测试来验证该端点。

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

3.2. Asynchronous Command Execution

3.2.异步命令的执行

An asynchronous execution of HystrixCommand queues up the command on the thread pool and returns a Future:

HystrixCommand的异步执行在线程池中排队,并返回一个Future

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

The HystrixAsyncHttpCommand looks like:

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

}

Here we use a blocking HttpClient instead of a nonblocking one because we want Hystrix to control the execution timeout of the actual command so that we won’t need to handle it on our own when getting a response from the Future. This also allows Hystrix to fallback or cache our request.

在这里,我们使用一个阻塞的HttpClient,而不是一个非阻塞的,因为我们希望Hystrix控制实际命令的执行超时,这样我们就不需要在从Future获得响应时自行处理。这也允许Hystrix回退或缓存我们的请求。

The async execution also yields expected outcome:

异步执行也产生了预期的结果。

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

3.3. Synchronous Command Execution

3.3.同步命令的执行

A synchronous execution executes the command directly in the current thread:

同步执行会直接在当前线程中执行命令。

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

The implementation of HystrixSyncHttpCommand is almost identical to HystrixAsyncHttpCommand except that we give it a different fall back result. When not falling back, it behaves the just the same as reactive and asynchronous execution:

HystrixSyncHttpCommand的实现与HystrixAsyncHttpCommand几乎相同,只是我们给它一个不同的回退结果。当不回退时,它的行为与反应式和异步执行是一样的。

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

4. Metrics

4.度量衡

By registering the Guice moduleHystrixModule into Ratpack registry, we can stream the request scoped metrics and expose the event streams via a GET endpoint:

通过将Guice模块HystrixModule注册到Ratpack注册表,我们可以将请求范围内的指标流化,并通过GET端点公开事件流。

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

The HystrixMetricsEventStreamHandler helps stream Hystrix metrics in text/event-stream format, such that we can monitor the metrics in Hystrix Dashboard.

HystrixMetricsEventStreamHandler有助于以text/event-stream格式流传Hystrix指标,这样我们就可以在Hystrix Dashboard中监控这些指标。

We can set up a standalone Hystrix dashboard, and add our Hystrix event-stream to the monitor list to see how our Ratpack application performs:

我们可以设置一个独立的Hystrix仪表板,并将我们的Hystrix事件流添加到监视器列表中,以查看我们的Ratpack应用程序的执行情况。

Snip20170815 1

After several requests to our Ratpack application, we can see the Hystrix related commands in the dashboard.

在向我们的Ratpack应用程序发出几个请求后,我们可以在仪表板上看到Hystrix的相关命令。

4.1. Under the Hood

4.1.引擎盖下

In HystrixModule, a Hystrix Concurrency Strategy is registered with Hystrix via HystrixPlugin to manage the request context with Ratpack registry. This removes the necessity for initializing Hystrix request context before each request begins.

HystrixModule中,通过HystrixPlugin向Hystrix注册,以便用Ratpack注册表管理请求上下文。这消除了在每个请求开始之前初始化Hystrix请求上下文的必要性。

public class HystrixModule extends ConfigurableModule<HystrixModule.Config> {

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

    //...

}

5. Conclusion

5.结论

In this quick article, we’ve shown how Hystrix can be integrated into Ratpack and how to push metrics of our Ratpack application to Hystrix Dashboard for a better view of the application performance.

在这篇快速文章中,我们展示了Hystrix如何集成到Ratpack中,以及如何将Ratpack应用程序的指标推送到Hystrix Dashboard,以便更好地查看应用程序的性能。

As always, the full implementation can be found over on the Github project.

一如既往,完整的实现可以在Github项目上找到。