编辑此页面

SmallRye 容错

微服务的分布式特性带来的挑战之一是与外部系统的通信本质上是不可靠的。 这增加了对应用程序弹性的需求。 为了简化更具弹性的应用程序的开发,Quarkus 提供了 SmallRye Fault Tolerance,它是 MicroProfile Fault Tolerance 规范的实现。

在本指南中,我们将演示 MicroProfile Fault Tolerance 注释的用法,例如 @Timeout@Fallback@Retry@CircuitBreaker@RateLimit

先决条件

要完成本指南,您需要

  • 大约 15 分钟

  • 一个 IDE

  • 已安装 JDK 17+ 并正确配置了 JAVA_HOME

  • Apache Maven 3.9.9

  • 如果您想使用它,可以选择 Quarkus CLI

  • 如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置

场景

本指南中构建的应用程序模拟了一个简单的美食咖啡网店后端。 它实现了一个 REST 端点,提供有关我们商店中咖啡样品的信息。

让我们假设,尽管它没有这样实现,但我们端点中的某些方法需要与外部服务(如数据库或外部微服务)通信,这引入了不可靠因素。

解决方案

我们建议您按照以下章节中的说明,逐步创建应用程序。但是,您可以直接转到完整的示例。

克隆 Git 存储库:git clone https://github.com/quarkusio/quarkus-quickstarts.git,或下载 存档

解决方案位于 microprofile-fault-tolerance-quickstart 目录中。

创建 Maven 项目

首先,我们需要一个新项目。使用以下命令创建一个新项目

CLI
quarkus create app org.acme:microprofile-fault-tolerance-quickstart \
    --extension='smallrye-fault-tolerance,rest-jackson' \
    --no-code
cd microprofile-fault-tolerance-quickstart

要创建 Gradle 项目,请添加 --gradle--gradle-kotlin-dsl 选项。

有关如何安装和使用 Quarkus CLI 的更多信息,请参阅 Quarkus CLI 指南。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.24.4:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=microprofile-fault-tolerance-quickstart \
    -Dextensions='smallrye-fault-tolerance,rest-jackson' \
    -DnoCode
cd microprofile-fault-tolerance-quickstart

要创建 Gradle 项目,请添加 -DbuildTool=gradle-DbuildTool=gradle-kotlin-dsl 选项。

对于 Windows 用户

  • 如果使用 cmd,(不要使用反斜杠 \ 并将所有内容放在同一行上)

  • 如果使用 Powershell,请将 -D 参数用双引号括起来,例如 "-DprojectArtifactId=microprofile-fault-tolerance-quickstart"

此命令生成一个项目,导入 Quarkus REST (以前的 RESTEasy Reactive)/Jakarta REST 和 SmallRye Fault Tolerance 的扩展。

如果您已经配置了 Quarkus 项目,则可以通过在项目基本目录中运行以下命令将 smallrye-fault-tolerance 扩展添加到您的项目中

CLI
quarkus extension add smallrye-fault-tolerance
Maven
./mvnw quarkus:add-extension -Dextensions='smallrye-fault-tolerance'
Gradle
./gradlew addExtension --extensions='smallrye-fault-tolerance'

这会将以下内容添加到您的构建文件中

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-smallrye-fault-tolerance</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-smallrye-fault-tolerance")

准备应用程序:REST 端点和 CDI Bean

在本节中,我们将创建应用程序的骨架,以便我们有一些可以扩展并在以后添加容错功能的东西。

首先,创建一个简单的实体来表示我们商店中的咖啡样品

package org.acme.microprofile.faulttolerance;

public class Coffee {

    public Integer id;
    public String name;
    public String countryOfOrigin;
    public Integer price;

    public Coffee() {
    }

    public Coffee(Integer id, String name, String countryOfOrigin, Integer price) {
        this.id = id;
        this.name = name;
        this.countryOfOrigin = countryOfOrigin;
        this.price = price;
    }
}

让我们继续使用一个简单的 CDI Bean,它将充当我们的咖啡样品的存储库。

package org.acme.microprofile.faulttolerance;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class CoffeeRepositoryService {

    private Map<Integer, Coffee> coffeeList = new HashMap<>();

    public CoffeeRepositoryService() {
        coffeeList.put(1, new Coffee(1, "Fernandez Espresso", "Colombia", 23));
        coffeeList.put(2, new Coffee(2, "La Scala Whole Beans", "Bolivia", 18));
        coffeeList.put(3, new Coffee(3, "Dak Lak Filter", "Vietnam", 25));
    }

    public List<Coffee> getAllCoffees() {
        return new ArrayList<>(coffeeList.values());
    }

    public Coffee getCoffeeById(Integer id) {
        return coffeeList.get(id);
    }

    public List<Coffee> getRecommendations(Integer id) {
        if (id == null) {
            return Collections.emptyList();
        }
        return coffeeList.values().stream()
                .filter(coffee -> !id.equals(coffee.id))
                .limit(2)
                .collect(Collectors.toList());
    }
}

最后,创建 org.acme.microprofile.faulttolerance.CoffeeResource 类,如下所示

package org.acme.microprofile.faulttolerance;

import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import org.jboss.logging.Logger;

@Path("/coffee")
public class CoffeeResource {

    private static final Logger LOGGER = Logger.getLogger(CoffeeResource.class);

    @Inject
    CoffeeRepositoryService coffeeRepository;

    private AtomicLong counter = new AtomicLong(0);

    @GET
    public List<Coffee> coffees() {
        final Long invocationNumber = counter.getAndIncrement();

        maybeFail(String.format("CoffeeResource#coffees() invocation #%d failed", invocationNumber));

        LOGGER.infof("CoffeeResource#coffees() invocation #%d returning successfully", invocationNumber);
        return coffeeRepository.getAllCoffees();
    }

    private void maybeFail(String failureLogMessage) {
        if (new Random().nextBoolean()) {
            LOGGER.error(failureLogMessage);
            throw new RuntimeException("Resource failure.");
        }
    }
}

此时,我们公开了一个 REST 方法,该方法将以 JSON 格式显示咖啡样品列表。 请注意,我们在 CoffeeResource#maybeFail() 方法中引入了一些错误代码,这将导致 CoffeeResource#coffees() 端点方法在大约 50% 的请求中失败。

为什么不检查我们的应用程序是否正常工作? 使用以下命令运行 Quarkus 开发服务器

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

并在浏览器中打开 https://:8080/coffee。 发出几个请求(请记住,预计其中一些请求会失败)。 至少一些请求应该以 JSON 格式向我们显示咖啡样品列表,其余请求将因 CoffeeResource#maybeFail() 中抛出的 RuntimeException 而失败。

恭喜,您刚刚制作了一个工作(尽管有点不可靠)的 Quarkus 应用程序!

增加弹性:重试

让 Quarkus 开发服务器运行,并在您的 IDE 中将 @Retry 注释添加到 CoffeeResource#coffees() 方法,如下所示,并保存文件

import org.eclipse.microprofile.faulttolerance.Retry;
...

public class CoffeeResource {
    ...
    @GET
    @Retry(maxRetries = 4)
    public List<Coffee> coffees() {
        ...
    }
    ...
}

点击浏览器中的刷新。 Quarkus 开发服务器将自动检测更改并为您重新编译应用程序,因此无需重新启动它。

您可以多次点击刷新。 实际上,现在所有请求都应该成功。 事实上,CoffeeResource#coffees() 方法仍然在大约 50% 的时间内失败,但是每次发生这种情况时,平台都会自动重试调用!

要查看失败仍然发生,请检查开发服务器的输出。 日志消息应类似于以下内容

2019-03-06 12:17:41,725 INFO  [org.acm.fau.CoffeeResource] (XNIO-1 task-1) CoffeeResource#coffees() invocation #5 returning successfully
2019-03-06 12:17:44,187 INFO  [org.acm.fau.CoffeeResource] (XNIO-1 task-1) CoffeeResource#coffees() invocation #6 returning successfully
2019-03-06 12:17:45,166 ERROR [org.acm.fau.CoffeeResource] (XNIO-1 task-1) CoffeeResource#coffees() invocation #7 failed
2019-03-06 12:17:45,172 ERROR [org.acm.fau.CoffeeResource] (XNIO-1 task-1) CoffeeResource#coffees() invocation #8 failed
2019-03-06 12:17:45,176 INFO  [org.acm.fau.CoffeeResource] (XNIO-1 task-1) CoffeeResource#coffees() invocation #9 returning successfully

您可以看到每次调用失败时,紧随其后的是另一次调用,直到一次成功为止。 由于我们允许 4 次重试,因此需要连续 5 次调用失败,用户才能真正暴露于失败。 这不太可能发生。

增加弹性:超时

那么我们在 MicroProfile Fault Tolerance 中还有什么? 让我们看看超时。

将以下两个方法添加到我们的 CoffeeResource 端点。 同样,无需重新启动服务器,只需粘贴代码并保存文件即可。

import org.eclipse.microprofile.faulttolerance.Timeout;
...
public class CoffeeResource {
    ...
    @GET
    @Path("/{id}/recommendations")
    @Timeout(250)
    public List<Coffee> recommendations(int id) {
        long started = System.currentTimeMillis();
        final long invocationNumber = counter.getAndIncrement();

        try {
            randomDelay();
            LOGGER.infof("CoffeeResource#recommendations() invocation #%d returning successfully", invocationNumber);
            return coffeeRepository.getRecommendations(id);
        } catch (InterruptedException e) {
            LOGGER.errorf("CoffeeResource#recommendations() invocation #%d timed out after %d ms",
                    invocationNumber, System.currentTimeMillis() - started);
            return null;
        }
    }

    private void randomDelay() throws InterruptedException {
        Thread.sleep(new Random().nextInt(500));
    }
}

我们添加了一些新功能。 我们希望能够根据用户当前正在查看的咖啡推荐一些相关的咖啡。 这不是一项关键功能,而是一项锦上添花的功能。 当系统过载且获取推荐背后的逻辑花费的时间太长时,我们宁愿超时并呈现没有推荐的 UI。

请注意,超时配置为 250 毫秒,并且在 CoffeeResource#recommendations() 方法中引入了 0 到 500 毫秒之间的随机人为延迟。

在您的浏览器中,转到 https://:8080/coffee/2/recommendations 并多次点击刷新。

您应该看到一些请求因 org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException 而超时。 未超时的请求应以 JSON 格式显示两个推荐的咖啡样品。

增加弹性:回退

让我们通过提供一种回退(并且可能更快)的方式来获得相关咖啡,从而使我们的推荐功能更加出色。

将回退方法添加到 CoffeeResource,并将 @Fallback 注释添加到 CoffeeResource#recommendations() 方法,如下所示

import java.util.Collections;
import org.eclipse.microprofile.faulttolerance.Fallback;

...
public class CoffeeResource {
    ...
    @Fallback(fallbackMethod = "fallbackRecommendations")
    public List<Coffee> recommendations(int id) {
        ...
    }

    public List<Coffee> fallbackRecommendations(int id) {
        LOGGER.info("Falling back to RecommendationResource#fallbackRecommendations()");
        // safe bet, return something that everybody likes
        return Collections.singletonList(coffeeRepository.getCoffeeById(1));
    }
    ...
}

https://:8080/coffee/2/recommendations 上多次点击刷新。 TimeoutException 不应再出现。 相反,在发生超时的情况下,页面将显示我们在回退方法 fallbackRecommendations() 中硬编码的单个推荐,而不是原始方法返回的两个推荐。

检查服务器输出以查看回退是否真的发生

2020-01-09 13:21:34,250 INFO  [org.acm.fau.CoffeeResource] (executor-thread-1) CoffeeResource#recommendations() invocation #1 returning successfully
2020-01-09 13:21:36,354 ERROR [org.acm.fau.CoffeeResource] (executor-thread-1) CoffeeResource#recommendations() invocation #2 timed out after 250 ms
2020-01-09 13:21:36,355 INFO  [org.acm.fau.CoffeeResource] (executor-thread-1) Falling back to RecommendationResource#fallbackRecommendations()
回退方法需要具有与原始方法相同的参数。

增加弹性:断路器

当系统的一部分暂时变得不稳定时,断路器对于限制系统中发生的故障数量很有用。 断路器会记录方法的成功和失败调用,当失败调用的比例达到指定的阈值时,断路器会打开并阻止该方法的所有进一步调用一段时间。

将以下代码添加到 CoffeeRepositoryService Bean 中,以便我们可以演示断路器的运行

import java.util.concurrent.atomic.AtomicLong;
import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
...

public class CoffeeRepositoryService {
    ...

    private AtomicLong counter = new AtomicLong(0);

    @CircuitBreaker(requestVolumeThreshold = 4)
    public Integer getAvailability(Coffee coffee) {
        maybeFail();
        return new Random().nextInt(30);
    }

    private void maybeFail() {
        // introduce some artificial failures
        final Long invocationNumber = counter.getAndIncrement();
        if (invocationNumber % 4 > 1) { // alternate 2 successful and 2 failing invocations
            throw new RuntimeException("Service failed.");
        }
    }
}

并将以下代码注入到 CoffeeResource 端点中

public class CoffeeResource {
    ...
    @Path("/{id}/availability")
    @GET
    public Response availability(int id) {
        final Long invocationNumber = counter.getAndIncrement();

        Coffee coffee = coffeeRepository.getCoffeeById(id);
        // check that coffee with given id exists, return 404 if not
        if (coffee == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }

        try {
            Integer availability = coffeeRepository.getAvailability(coffee);
            LOGGER.infof("CoffeeResource#availability() invocation #%d returning successfully", invocationNumber);
            return Response.ok(availability).build();
        } catch (RuntimeException e) {
            String message = e.getClass().getSimpleName() + ": " + e.getMessage();
            LOGGER.errorf("CoffeeResource#availability() invocation #%d failed: %s", invocationNumber, message);
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(message)
                    .type(MediaType.TEXT_PLAIN_TYPE)
                    .build();
        }
    }
    ...
}

我们添加了另一个功能 - 应用程序可以返回我们商店中给定咖啡的剩余包装数量(只是一个随机数)。

这一次,在 CDI Bean 中引入了人为故障:CoffeeRepositoryService#getAvailability() 方法将在两次成功和两次失败调用之间交替。

我们还添加了一个 @CircuitBreaker 注释,其中 requestVolumeThreshold = 4CircuitBreaker.failureRatio 默认为 0.5,CircuitBreaker.delay 默认为 5 秒。 这意味着当最近 4 次调用中有 2 次失败时,断路器将打开,并且将保持打开 5 秒钟。

要对此进行测试,请执行以下操作

  1. 在浏览器中转到 https://:8080/coffee/2/availability。 您应该看到返回一个数字。

  2. 点击刷新,第二个请求应再次成功并返回一个数字。

  3. 再刷新两次。 两次您都应该看到文本“RuntimeException: Service failed.”,这是 CoffeeRepositoryService#getAvailability() 抛出的异常。

  4. 再刷新几次。 除非您等待的时间过长,否则您应该再次看到异常,但这次是“CircuitBreakerOpenException: getAvailability”。 此异常表明断路器已打开,并且不再调用 CoffeeRepositoryService#getAvailability() 方法。

  5. 给它 5 秒钟,在此期间断路器应关闭,并且您应该能够再次发出两个成功的请求。

增加弹性:速率限制

这是 SmallRye Fault Tolerance 的一项附加功能,MicroProfile Fault Tolerance 未指定此功能。

可以使用速率限制来防止操作过于频繁地执行。 速率限制强制执行某个时间窗口内允许的最大调用次数。 例如,使用速率限制,可以确保一个方法每分钟只能被调用 50 次。 超过限制的调用将被拒绝,并显示 RateLimitException 类型的异常。

此外,可以定义调用之间的最小间隔。 例如,如果最小间隔为 1 秒,如果第二次调用在第一次调用后 500 毫秒发生,即使尚未超过限制,也会被拒绝。

速率限制表面上类似于 Bulkhead(并发限制),但实际上却大相径庭。 Bulkhead 限制在任何时间点发生的并发执行次数。 速率限制限制在某个时间窗口内的执行次数,而不考虑并发性。

速率限制需要在调用之间维护一些状态:最近的调用次数、上次调用的时间戳等等。 此状态是单例,与使用 @RateLimit 注释的 Bean 的生命周期无关。

更具体地说,速率限制状态由 Bean 类 (java.lang.Class) 和表示受保护方法的 Method 对象 (java.lang.reflect.Method) 的组合唯一标识。

让 Quarkus 开发模式运行,并在您的 IDE 中将 @RateLimit 注释添加到 CoffeeResource#coffees() 方法,如下所示,并保存文件

import java.time.temporal.ChronoUnit;
import io.smallrye.faulttolerance.api.RateLimit;

...
public class CoffeeResource {
    ...
    @GET
    @RateLimit(value = 2, window = 10, windowUnit = ChronoUnit.SECONDS)
    public List<Coffee> coffees() {
        ...
    }
    ...
}

点击浏览器中的刷新。 Quarkus 开发服务器将自动检测更改并为您重新编译应用程序,因此无需重新启动它。

您可以多次点击刷新。 在 10 秒间隔内进行 2 个请求后,您应该开始在日志中看到错误,类似于以下内容

INFO  [org.acm.mic.fau.CoffeeResource] (executor-thread-1) CoffeeResource#coffees() invocation #1 returning successfully
ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-1) HTTP Request to /coffee failed, error id: d3e59090-fd45-4c67-844e-80a8f7fa6ee0-4: io.smallrye.faulttolerance.api.RateLimitException: org.acme.microprofile.faulttolerance.CoffeeResource#coffees rate limit exceeded
        at io.smallrye.faulttolerance.core.rate.limit.RateLimit.doApply(RateLimit.java:58)
        at io.smallrye.faulttolerance.core.rate.limit.RateLimit.apply(RateLimit.java:44)
        at io.smallrye.faulttolerance.FaultToleranceInterceptor.syncFlow(FaultToleranceInterceptor.java:255)
        at io.smallrye.faulttolerance.FaultToleranceInterceptor.intercept(FaultToleranceInterceptor.java:182)
        at io.smallrye.faulttolerance.FaultToleranceInterceptor_Bean.intercept(Unknown Source)
        at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:42)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:30)
        at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:27)
        at org.acme.microprofile.faulttolerance.CoffeeResource_Subclass.coffees(Unknown Source)
        at org.acme.microprofile.faulttolerance.CoffeeResource$quarkusrestinvoker$coffees_73d7590ab944adfa130e4ad57c30282f825b2d18.invoke(Unknown Source)
        at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
        at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141)
        at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
        at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:599)
        at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2516)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2495)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1521)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1583)

如果在 @RateLimit 中使用了 @Fallback,则如果抛出 RateLimitException,则可以调用回退方法或处理程序,具体取决于回退配置。

如果在 @RateLimit 中使用了 @Retry,则每个重试尝试都由速率限制作为独立调用处理。 如果抛出 RateLimitException,则可以重试执行,具体取决于重试的配置方式。

如果在 @RateLimit 中使用了 @CircuitBreaker,则在强制执行速率限制之前会检查断路器。 如果速率限制导致 RateLimitException,则这可能会被视为失败,具体取决于断路器的配置方式。

运行时配置

您可以在 application.properties 文件中的运行时覆盖注释参数。

如果我们采用已经看到的重试示例

package org.acme;

import org.eclipse.microprofile.faulttolerance.Retry;
...

public class CoffeeResource {
    ...
    @GET
    @Retry(maxRetries = 4)
    public List<Coffee> coffees() {
        ...
    }
    ...
}

我们可以使用以下配置项将 maxRetries 参数覆盖为 6 次重试,而不是 4 次

quarkus.fault-tolerance."org.acme.CoffeeResource/coffees".retry.max-retries=6

# alternatively, a specification-defined property can be used
org.acme.CoffeeResource/coffees/Retry/maxRetries=6

Quarkus 原生配置属性的完整集在 配置参考中详细介绍。 规范定义的配置属性仍然受支持,但 Quarkus 原生配置优先。

结论

SmallRye Fault Tolerance 允许提高应用程序的弹性,而不会对我们的业务逻辑的复杂性产生影响。

启用 Quarkus 中的容错功能所需的全部操作是

  • 使用 quarkus-maven-pluginsmallrye-fault-tolerance Quarkus 扩展添加到您的项目中

    CLI
    quarkus extension add smallrye-fault-tolerance
    Maven
    ./mvnw quarkus:add-extension -Dextensions='smallrye-fault-tolerance'
    Gradle
    ./gradlew addExtension --extensions='smallrye-fault-tolerance'
  • 或只需添加以下 Maven 依赖项

    pom.xml
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-smallrye-fault-tolerance</artifactId>
    </dependency>
    build.gradle
    implementation("io.quarkus:quarkus-smallrye-fault-tolerance")

其他资源

SmallRye Fault Tolerance 具有比此处显示的更多功能。 请查看 SmallRye Fault Tolerance 文档以了解它们。

在 Quarkus 中,您可以开箱即用地使用 SmallRye Fault Tolerance 可选功能。

支持 Mutiny,因此您的异步方法除了 CompletionStage 之外还可以返回 Uni

MicroProfile Context Propagation 与 Fault Tolerance 集成,因此现有上下文会自动传播到您的异步方法。

这也适用于 CDI 请求上下文:如果它在原始线程上处于活动状态,则会传播到新线程,但如果不是,则新线程也不会拥有它。 这与 MicroProfile Fault Tolerance 规范相反,该规范声明请求上下文必须在 @Asynchronous 方法调用期间处于活动状态。

我们认为,在存在 MicroProfile Context Propagation 的情况下,此要求不应适用。 上下文传播的全部意义在于确保新线程具有与原始线程相同的上下文。

默认情况下启用非兼容模式。 这意味着返回 CompletionStage(或 Uni)的方法应用异步容错,而无需 @Asynchronous@AsynchronousNonBlocking 注释。 这也意味着如果异常本身不足以决定应该发生什么,断路器、回退和重试会自动检查异常原因链。

此模式与 MicroProfile Fault Tolerance 规范不兼容,尽管不兼容性非常小。 要恢复完全兼容性,请添加此配置属性

quarkus.fault-tolerance.mp-compatibility=true

程序化 API存在并与声明性、基于注释的 API 集成。 您可以开箱即用地使用 GuardTypedGuard@ApplyGuard API。

支持 Kotlin(假设您使用 Kotlin 的 Quarkus 扩展),因此您可以使用容错注释来保护您的 suspend 函数。

自动发现指标并集成。 如果您的应用程序使用 Micrometer 的 Quarkus 扩展,则 SmallRye Fault Tolerance 将向 Micrometer 发出指标。 如果您的应用程序使用 SmallRye Metrics 的 Quarkus 扩展,则 SmallRye Fault Tolerance 将向 MicroProfile Metrics 发出指标。 否则,SmallRye Fault Tolerance 指标将被禁用。

配置参考

以下 "<identifier>"

  • "<classname>/<methodname>" 用于每个方法的配置

  • "<classname>" 用于每个类的配置

  • global 用于全局配置

  • 它也可以是 @Identifier 值,用于配置以编程方式构造的 GuardTypedGuard,这些值通过 @ApplyGuard 以声明方式使用。 请注意,在这种情况下,Guard/TypedGuard 绝不能以编程方式使用,因为配置是在创建时应用的,这是在第一次使用时延迟发生的。 第一次使用必须通过 @ApplyGuard,否则配置将被忽略。

构建时固定的配置属性 - 所有其他配置属性都可以在运行时覆盖

配置属性

类型

默认

是否启用容错策略。 请注意,@Fallback 始终启用,这适用于所有其他策略。

环境变量:QUARKUS_FAULT_TOLERANCE_ENABLED

显示更多

布尔值

true

是否启用容错指标。

环境变量:QUARKUS_FAULT_TOLERANCE_METRICS_ENABLED

显示更多

布尔值

true

SmallRye Fault Tolerance 是否应与 MicroProfile Fault Tolerance 规范兼容。

环境变量:QUARKUS_FAULT_TOLERANCE_MP_COMPATIBILITY

显示更多

布尔值

false

重试之前要调用的方法的名称。 该方法属于与受保护方法相同的类。 该方法必须没有参数并且返回 void

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___BEFORE_RETRY_METHOD_NAME

显示更多

字符串

在回退时要调用的方法的名称。 该方法属于与受保护方法相同的类。 该方法必须具有与受保护方法的签名匹配的签名。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___FALLBACK_FALLBACK_METHOD

显示更多

字符串

是否启用 @ApplyGuard 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___APPLY_GUARD_ENABLED

显示更多

布尔值

true

要用于带注释的方法的 io.smallrye.faulttolerance.api.Guard Guardio.smallrye.faulttolerance.api.TypedGuard TypedGuardio.smallrye.common.annotation.Identifier @Identifier

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___APPLY_GUARD_VALUE

显示更多

字符串

是否启用 @Asynchronous 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___ASYNCHRONOUS_ENABLED

显示更多

布尔值

true

是否启用 @AsynchronousNonBlocking 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___ASYNCHRONOUS_NON_BLOCKING_ENABLED

显示更多

布尔值

true

是否启用 @BeforeRetry 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___BEFORE_RETRY_ENABLED

显示更多

布尔值

true

重试之前要调用的 BeforeRetryHandler 的类。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___BEFORE_RETRY_VALUE

显示更多

是否启用 @Bulkhead 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___BULKHEAD_ENABLED

显示更多

布尔值

true

并发调用的最大数量。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___BULKHEAD_VALUE

显示更多

整数

10

排队的异步调用的最大数量。 当正在进行的并发调用次数已达到最大值时,异步调用将排队。 同步调用根本不会排队,并且会被立即拒绝。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___BULKHEAD_WAITING_TASK_QUEUE

显示更多

整数

10

是否启用 @CircuitBreaker 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___CIRCUIT_BREAKER_ENABLED

显示更多

布尔值

true

打开的断路器移动到半打开状态后的延迟。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___CIRCUIT_BREAKER_DELAY

显示更多

long

5 秒

delay() 的单位。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___CIRCUIT_BREAKER_DELAY_UNIT

显示更多

nanosmicrosmillissecondsminuteshourshalf-daysdaysweeksmonthsyearsdecadescenturiesmillenniaerasforever

被认为是失败的异常类型。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___CIRCUIT_BREAKER_FAIL_ON

显示更多

list of Class

Throwable(所有异常)

滚动窗口内将使关闭的断路器移动到打开状态的故障比率。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___CIRCUIT_BREAKER_FAILURE_RATIO

显示更多

double

0.5

断路器滚动窗口的大小。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD

显示更多

整数

20

不被认为是失败的异常类型。 优先于 fail-on()

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___CIRCUIT_BREAKER_SKIP_ON

显示更多

list of Class

<empty set>

使半打开的断路器移动到关闭状态的成功执行次数。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___CIRCUIT_BREAKER_SUCCESS_THRESHOLD

显示更多

整数

1

是否启用 @CustomBackoff 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___CUSTOM_BACKOFF_ENABLED

显示更多

布尔值

true

将用于计算重试延迟的 CustomBackoffStrategy 的类。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___CUSTOM_BACKOFF_VALUE

显示更多

是否启用 @ExponentialBackoff 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___EXPONENTIAL_BACKOFF_ENABLED

显示更多

布尔值

true

在确定两次重试之间的延迟时使用的乘法因子。 延迟计算为 factor * previousDelay,从而导致指数增长。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___EXPONENTIAL_BACKOFF_FACTOR

显示更多

整数

2

两次重试之间的最大延迟。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___EXPONENTIAL_BACKOFF_MAX_DELAY

显示更多

long

1 分钟

max-delay() 的单位。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___EXPONENTIAL_BACKOFF_MAX_DELAY_UNIT

显示更多

nanosmicrosmillissecondsminuteshourshalf-daysdaysweeksmonthsyearsdecadescenturiesmillenniaerasforever

是否启用 @Fallback 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___FALLBACK_ENABLED

显示更多

布尔值

true

被认为是失败因而应触发回退的异常类型。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___FALLBACK_APPLY_ON

显示更多

list of Class

Throwable(所有异常)

不被认为是失败因而不应触发回退的异常类型。 优先于 apply-on()

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___FALLBACK_SKIP_ON

显示更多

list of Class

<empty set>

回退时要调用的 FallbackHandler 的类。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___FALLBACK_VALUE

显示更多

是否启用 @FibonacciBackoff 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___FIBONACCI_BACKOFF_ENABLED

显示更多

布尔值

true

两次重试之间的最大延迟。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___FIBONACCI_BACKOFF_MAX_DELAY

显示更多

long

1 分钟

max-delay() 的单位。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___FIBONACCI_BACKOFF_MAX_DELAY_UNIT

显示更多

nanosmicrosmillissecondsminuteshourshalf-daysdaysweeksmonthsyearsdecadescenturiesmillenniaerasforever

是否启用 @RateLimit 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RATE_LIMIT_ENABLED

显示更多

布尔值

true

两次连续调用之间的最短时间。 如果两次连续调用之间的时间较短,则会拒绝第二次调用。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RATE_LIMIT_MIN_SPACING

显示更多

long

0

min-spacing() 的单位。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RATE_LIMIT_MIN_SPACING_UNIT

显示更多

nanosmicrosmillissecondsminuteshourshalf-daysdaysweeksmonthsyearsdecadescenturiesmillenniaerasforever

用于速率限制的类型窗口的类型。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RATE_LIMIT_TYPE

显示更多

fixedrollingsmooth

fixed

时间窗口内的最大调用次数。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RATE_LIMIT_VALUE

显示更多

整数

100

时间窗口长度。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RATE_LIMIT_WINDOW

显示更多

long

1 秒

window() 的单位。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RATE_LIMIT_WINDOW_UNIT

显示更多

nanosmicrosmillissecondsminuteshourshalf-daysdaysweeksmonthsyearsdecadescenturiesmillenniaerasforever

是否启用 @Retry 策略。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_ENABLED

显示更多

布尔值

true

不被认为是失败因而不应重试的异常类型。 优先于 retry-on()

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_ABORT_ON

显示更多

list of Class

<empty set>

重试尝试之间的延迟。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_DELAY

显示更多

long

0

delay() 的单位。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_DELAY_UNIT

显示更多

nanosmicrosmillissecondsminuteshourshalf-daysdaysweeksmonthsyearsdecadescenturiesmillenniaerasforever

应用于重试尝试之间延迟的最大抖动。 实际延迟将在 [delay - jitter, delay + jitter] 间隔内,但不会为负数。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_JITTER

显示更多

long

200 毫秒

jitter() 的单位。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_JITTER_UNIT

显示更多

nanosmicrosmillissecondsminuteshourshalf-daysdaysweeksmonthsyearsdecadescenturiesmillenniaerasforever

重试的最长时间。

环境变量:QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_MAX_DURATION

显示更多

long

3 分钟

max-duration() 的单位。

环境变量: QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_MAX_DURATION_UNIT

显示更多

nanosmicrosmillissecondsminuteshourshalf-daysdaysweeksmonthsyearsdecadescenturiesmillenniaerasforever

最大重试次数。

环境变量: QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_MAX_RETRIES

显示更多

整数

3

被认为是失败并因此应该重试的异常类型。

环境变量: QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_RETRY_ON

显示更多

list of Class

异常(所有异常)

是否启用 @RetryWhen 策略。

环境变量: QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_WHEN_ENABLED

显示更多

布尔值

true

谓词的类,该谓词将用于确定在受保护的方法抛出异常时是否应重试调用。

环境变量: QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_WHEN_EXCEPTION

显示更多

AlwaysOnException

谓词的类,该谓词将用于确定在受保护的方法返回结果时是否应重试调用。

环境变量: QUARKUS_FAULT_TOLERANCE___IDENTIFIER___RETRY_WHEN_RESULT

显示更多

NeverOnResult

是否启用 @Timeout 策略。

环境变量: QUARKUS_FAULT_TOLERANCE___IDENTIFIER___TIMEOUT_ENABLED

显示更多

布尔值

true

value() 的单位。

环境变量: QUARKUS_FAULT_TOLERANCE___IDENTIFIER___TIMEOUT_UNIT

显示更多

nanosmicrosmillissecondsminuteshourshalf-daysdaysweeksmonthsyearsdecadescenturiesmillenniaerasforever

要强制执行的超时。

环境变量: QUARKUS_FAULT_TOLERANCE___IDENTIFIER___TIMEOUT_VALUE

显示更多

long

1 秒

以下是规范定义的属性如何映射到 Quarkus 原生配置

规范定义的配置属性 Quarkus 原生配置属性

<classname>/<methodname>/<annotation>/<member>

quarkus.fault-tolerance."<classname>/<methodname>".<annotation>.<member>

<classname>/<annotation>/<member>

quarkus.fault-tolerance."<classname>".<annotation>.<member>

<annotation>/<member>

quarkus.fault-tolerance.global.<annotation>.<member>

MP_Fault_Tolerance_NonFallback_Enabled

quarkus.fault-tolerance.enabled

MP_Fault_Tolerance_Metrics_Enabled

quarkus.fault-tolerance.metrics.enabled

所有 <annotation><member> 部分都从驼峰命名法 (BeforeRetry, methodName) 更改为 kebab 命名法 (before-retry, method-name)。 特殊处理了两个注解成员以提高一致性

  • Retry/durationUnit 移动到 retry.max-duration-unit

  • Retry/jitterDelayUnit 移动到 retry.jitter-unit