1. 简介
之前,我们已经展示了如何使用Ratpack构建高性能、响应灵敏的应用程序。
在本文中,我们将研究如何将Netflix Hystrix与Ratpack应用程序集成。
Netflix Hystrix通过隔离访问点来阻止级联故障并提供容错回退选项,从而帮助控制分布式服务之间的交互,它可以帮助我们构建更具弹性的应用程序。请参阅我们对Hystrix的介绍以进行快速回顾。
这就是我们的使用方法-利用Hystrix提供的这些有用功能来增强我们的Ratpack应用程序。
注意:ratpack-hystrix模块已被删除:https://github.com/ratpack/ratpack/blob/master/release-notes.md?plain=1,因此本文中的代码不再维护。
2. Maven依赖
要将Hystrix与Ratpack一起使用,我们需要项目pom.xml中的ratpack-hystrix依赖:
<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获取Profile的端点。
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", "Tuyucheng HttpClient")))
.map(res -> res.getBody().getText()));
}
@Override
protected Observable<String> resumeWithFallback() {
return Observable.just("tuyucheng'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.tuyucheng.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", "Tuyucheng Blocking HttpClient")))
.build().execute(new HttpGet(uri)).getEntity());
}
@Override
protected String getFallback() {
return "tuyucheng's async fallback profile";
}
}
这里我们使用阻塞HttpClient而不是非阻塞HttpClient,因为我们希望Hystrix控制实际命令的执行超时,这样我们在从Future获取响应时就不需要自己处理它;这也允许Hystrix回退或缓存我们的请求。
异步执行也产生预期的结果:
@Test
public void whenFetchAsync_thenGotEugenProfile() {
assertThat(appUnderTest.getHttpClient().getText("async"), containsString("www.tuyucheng.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.tuyucheng.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并发策略通过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. 总结
在这篇简短的文章中,我们展示了如何将Hystrix集成到Ratpack中,以及如何将Ratpack应用程序的指标推送到Hystrix仪表板,以便更好地查看应用程序的性能。
Post Directory
