1. 引言

之前我们展示过如何用 Ratpack 构建高性能响应式应用。本文将探讨如何在 Ratpack 应用中集成 Netflix Hystrix。

Netflix Hystrix 通过隔离访问点来控制分布式服务间的交互,防止级联故障并提供容错降级选项。它能帮助我们构建更健壮的应用。快速回顾可参考我们的Hystrix 入门指南

我们将利用这些特性增强 Ratpack 应用。⚠️ 注意:ratpack-hystrix 模块已被移除(参考),本文代码不再维护

2. Maven 依赖

pom.xml 中添加 ratpack-hystrix 依赖:

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

最新版本可在这里查看。该模块已包含 ratpack-corehystrix-core

为使用 Ratpack 响应式特性,还需添加 ratpack-rx

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

最新版本可在这里查看。

3. 使用 Hystrix 命令提供服务

使用 Hystrix 时,底层服务通常被包装在 HystrixCommandHystrixObservableCommand 中。Hystrix 支持同步、异步和响应式三种执行方式,其中响应式是唯一非阻塞且官方推荐的方式

以下示例将构建从 GitHub REST API 获取用户信息的接口。

3.1. 响应式命令执行

首先构建响应式后端服务:

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. 监控指标

通过注册 Guice 模块 HystrixModule 到 Ratpack 注册中心,可流式传输请求级指标,并通过 GET 接口暴露事件流:

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

HystrixMetricsEventStreamHandlertext/event-stream 格式流式传输 Hystrix 指标,便于在 Hystrix Dashboard 中监控。

可部署独立 Hystrix Dashboard,将事件流地址加入监控列表查看应用性能:

Hystrix Dashboard 示例

多次请求后,可在 Dashboard 中看到 Hystrix 命令相关指标。

4.1. 实现原理

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. 总结

本文展示了如何在 Ratpack 中集成 Hystrix,以及如何将应用指标推送到 Hystrix Dashboard 以便监控性能。

完整实现代码请参考 GitHub 项目


原始标题:Ratpack with Hystrix | Baeldung