在Vert.x中使用Resilience4j

本文档将向您展示如何在Vert.x应用程序中使用Resilience4j。

Resilience4j 是一个流行的库,它实现了常见的容错策略

  • 舱壁模式(并发限制器)

  • 断路器

  • 限流器

  • 重试

  • 限时器(超时)

在本操作指南中,我们只演示了断路器的用法,但本操作指南的仓库中包含了上述所有策略的Vert.x适配器。

警告
我们在此使用的Resilience4j 2.0需要Java 17。

您将构建什么

您将使用一个带HTTP客户端的断路器,以防止向持续返回错误的服务器执行请求。这主要有两个目的

  • 避免在可能过载的服务器上产生更多负载,

  • 在故障很可能发生时快速失败。

应用程序由几个类组成

  1. CircuitBreakerVerticle

  2. VertxCircuitBreaker 适配器,包含在本操作指南的仓库中

您需要什么

  • 文本编辑器或 IDE

  • Java 17 或更高版本

  • Maven 或 Gradle

创建项目

此项目的代码包含功能等效的 Maven 和 Gradle 构建文件。

使用 Maven

首先,您的 pom.xml 文件应声明版本属性

Maven pom.xml:版本属性
<resilience4j.version>2.1.0</resilience4j.version>
<vertx.version>5.0.0.CR2</vertx.version>

接下来,导入Resilience4j和Vert.x BOM以管理依赖版本

Maven pom.xml:BOM导入
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>io.github.resilience4j</groupId>
      <artifactId>resilience4j-bom</artifactId>
      <version>${resilience4j.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-stack-depchain</artifactId>
      <version>${vertx.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

然后,添加对Resilience4j断路器库的依赖

Maven pom.xml:Resilience4j依赖
<dependency>
  <groupId>io.github.resilience4j</groupId>
  <artifactId>resilience4j-circuitbreaker</artifactId>
</dependency>

最后,添加对Vert.x Web和Vert.x Web Client库的依赖

Maven pom.xml:Vert.x依赖
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-web</artifactId>
</dependency>
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-web-client</artifactId>
</dependency>

使用 Gradle

您的 dependencies 块在 build.gradle.kts 文件中(假设您使用Kotlin DSL的Gradle)应首先导入Resilience4j和Vert.x BOM以管理依赖版本

Gradle build.gradle.kts:BOM导入
implementation(platform("io.github.resilience4j:resilience4j-bom:2.1.0"))
implementation(platform("io.vertx:vertx-stack-depchain:5.0.0.CR2"))

然后,添加对Resilience4j断路器库的依赖

Gradle build.gradle.kts:Resilience4j依赖
implementation("io.github.resilience4j:resilience4j-circuitbreaker")

最后,添加对Vert.x Web和Vert.x Web Client库的依赖

Gradle build.gradle.kts:Vert.x依赖
implementation("io.vertx:vertx-web")
implementation("io.vertx:vertx-web-client")

使用断路器保护Vert.x Web Client请求

首先,让我们创建主要的 CircuitBreakerVerticle

CircuitBreakerVerticle
public class CircuitBreakerVerticle extends VerticleBase {
}

该类将使用 VertxCircuitBreaker 类,该类包含在本操作指南的仓库中。

创建断路器

在Verticle的 start 方法中,我们创建一个断路器实例,该实例将共享给所有请求。为了演示目的,我们将断路器配置为仅在5个请求后开始计算故障率

创建断路器
CircuitBreaker cb = CircuitBreaker.of("my-circuit-breaker", CircuitBreakerConfig.custom()
  .minimumNumberOfCalls(5)
  .build());
提示
默认设置对于实际应用程序而言比我们的演示配置更有意义。

创建服务器

接下来,我们将使用Vert.x Web暴露一个简单的端点。该端点的唯一目的是执行HTTP请求并使用断路器保护它

创建端点
Router router = Router.router(vertx);
WebClient client = WebClient.create(vertx);

router.get("/").handler(ctx -> {
  VertxCircuitBreaker.executeFuture(cb, () -> {
    return client.get(8080, "localhost", "/does-not-exist")
      .as(BodyCodec.string())
      .send()
      .expecting(HttpResponseExpectation.SC_SUCCESS);
  })
    .onSuccess(response -> ctx.end("Got: " + response.body() + "\n"))
    .onFailure(error -> ctx.end("Failed with: " + error.toString() + "\n"));
});

这需要一些解释。

/ 上的端点使用 VertxCircuitBreaker 适配器,它将Resilience4j API和Vert.x Future 连接在一起。该适配器期望一个 Supplier<Future> 作为受保护的操作。

此处的 Future 来自Vert.x Web Client的 get(8080, "localhost", "/does-not-exist") 调用。

可以想象,我们在此发出的请求永远不会成功。因此,断路器将在5个请求后(如上所述配置)启动,并阻止对受保护操作的进一步调用。相反,由 executeFuture 返回的 Future 将立即失败并抛出 CallNotPermittedException 异常。

启动服务器

最后,我们将启动服务器

启动服务器
return vertx.createHttpServer()
  .requestHandler(router)
  .listen(8080)
  .onSuccess(server -> {
    System.out.println("HTTP server started on port " + server.actualPort());
  });

Verticle的整个 start 方法如下所示

Verticle的 start 方法
@Override
public Future<?> start() {
  CircuitBreaker cb = CircuitBreaker.of("my-circuit-breaker", CircuitBreakerConfig.custom()
    .minimumNumberOfCalls(5)
    .build());

  Router router = Router.router(vertx);
  WebClient client = WebClient.create(vertx);

  router.get("/").handler(ctx -> {
    VertxCircuitBreaker.executeFuture(cb, () -> {
      return client.get(8080, "localhost", "/does-not-exist")
        .as(BodyCodec.string())
        .send()
        .expecting(HttpResponseExpectation.SC_SUCCESS);
    })
      .onSuccess(response -> ctx.end("Got: " + response.body() + "\n"))
      .onFailure(error -> ctx.end("Failed with: " + error.toString() + "\n"));
  });

  return vertx.createHttpServer()
    .requestHandler(router)
    .listen(8080)
    .onSuccess(server -> {
      System.out.println("HTTP server started on port " + server.actualPort());
    });
}

运行应用程序

CircuitBreakerVerticle 也需要一个 main 方法

main 方法
public static void main(String[] args) {
  Vertx vertx = Vertx.vertx();
  vertx.deployVerticle(new CircuitBreakerVerticle());
}

然后您可以运行应用程序

  • 直接从您的IDE运行,或

  • 使用Maven:mvn clean compile exec:java,或

  • 使用 Gradle:./gradlew run (Linux, macOS) 或 gradlew run (Windows)。

以下示例使用 HTTPie 命令行 HTTP 客户端。如果您的系统尚未安装,请参阅其安装文档。

前5个请求

对于前5个请求,断路器不计算故障率,并将允许所有操作继续。如预期,它们都将失败

http localhost:8080
http localhost:8080
http localhost:8080
http localhost:8080
http localhost:8080

您应该看到以下输出5次

Failed with: io.vertx.core.impl.NoStackTraceThrowable: Response status code 404 is not between 200 and 300

接下来,断路器启动

http localhost:8080

第6个请求将以不同的消息失败

Failed with: io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'my-circuit-breaker' is OPEN and does not permit further calls

我们看到断路器阻止了对服务器的请求执行。

总结

本文档涵盖了

  1. 创建Resilience4j断路器实例,

  2. 使用断路器保护一个结果为Vert.x Future 的操作。

另请参阅


最后发布:2025-02-03 01:11:48 +0000。