Quarkus Reactive Architecture
Quarkus 是响应式的。它甚至不仅仅是这样:Quarkus 统一了响应式和命令式编程。你甚至不必进行选择:你可以实现响应式组件和命令式组件,然后在 same 应用程序中对其进行组合。无需使用不同的栈、工具或 API;Quarkus 连接了这两个世界。
Quarkus is reactive. It’s even more than this: Quarkus unifies reactive and imperative programming. You don’t even have to choose: you can implement reactive components and imperative components then combine them inside the very same application. No need to use different stacks, tooling or APIs; Quarkus bridges both worlds.
此页面将解释 Reactive 的含义以及 Quarkus 如何启用它。我们还将讨论执行和编程模型。最后,我们将列出提供了响应式方面的 Quarkus 扩展。
This page will explain what we mean by Reactive and how Quarkus enables it. We will also discuss execution and programming models. Finally, we will list the Quarkus extensions offering reactive facets.
What is Reactive?
Reactive 一词被过载,并与许多概念相关,例如反压、单子或事件驱动架构。因此,让我们澄清一下 Reactive 的含义。
The Reactive word is overloaded and associated with many concepts such as back-pressure, monads, or event-driven architecture. So, let’s clarify what we mean by Reactive.
Reactive 是一组原则和指导方针,用于构建响应式分布式系统和应用程序。 Reactive Manifesto 将 Reactive Systems 描述为具有以下四个特征的分布式系统:
Reactive is a set of principles and guidelines to build responsive distributed systems and applications. The Reactive Manifesto characterizes Reactive Systems as distributed systems having four characteristics:
-
Responsive - they must respond in a timely fashion
-
Elastic - they adapt themselves to the fluctuating load
-
Resilient - they handle failures gracefully
-
Asynchronous message passing - the component of a reactive system interact using messages

此外, Reactive Principles white paper 列出了一组规则和模式来帮助构建响应式系统。
In addition to this, the Reactive Principles white paper lists a set of rules and patterns to help the construction of reactive systems.
Reactive Systems and Quarkus
响应式系统是一种架构风格,可以概括为:正确完成分布式系统。依赖异步消息传递有助于在不同组件之间强制实现松耦合(无论是在空间方面还是时间方面)。你向虚拟目标发送消息。接收者可以位于任何位置,甚至在发送消息时尚未存在。弹性支柱允许根据负载按比例放大和缩小各个组件。弹性还提供了冗余,有助于提高恢复力。失败是不可避免的。组成响应式系统的组件必须优雅地处理它们,避免级联故障,并自动适应自身。
Reactive System is an architectural style that can be summarized by: distributed systems done right. Relying on asynchronous message passing helps enforce the loose coupling (both in terms of space and time) between the different components. You send messages to virtual destinations. The receiver can be located anywhere, or even not yet exist at the time of the message dispatch. The elasticity pillar allows scaling up and down individual components according to the load. Elasticity also provides redundancy, which helps with the resilience pillar. Failures are inevitable. Components forming a reactive system must handle them gracefully, avoid cascading failures, and self-adapt themselves.
响应式系统可以在面对故障和波动负载时继续处理请求。Quarkus 已为此量身定制。它提供了将有助于你设计、实现和操作响应式系统的一些功能。
A responsive system can continue to handle the request while facing failures and under fluctuating load. Quarkus has been tailored for that. It provides features that will help you design, implement and operate reactive systems.
Reactive Applications
Quarkus 不仅将帮助你构建响应式系统。它还将确保每个组成部分强制执行响应式原则,并且非常高效。
Quarkus is not only going to help you build reactive systems. It’s also going to make sure that each constituent enforces the reactive principles and is highly efficient.
效率至关重要,尤其是在云环境和容器化环境中。资源(如 CPU 和内存)在多个应用程序之间共享。消耗大量内存的贪婪应用程序效率低下,并会对关联应用程序造成负担。你可能需要申请更多内存、CPU 或更大的虚拟机。它要么会增加你的每月云账单,要么会降低你的部署密度。
Efficiency is essential, especially in the Cloud and in containerized environments. Resources, such as CPU and memory, are shared among multiple applications. Greedy applications that consume lots of memory are inefficient and put penalties on sibling applications. You may need to request more memory, CPU, or bigger virtual machines. It either increases your monthly Cloud bill or decreases your deployment density.
I/O 是几乎任何现代系统的重要组成部分。无论是调用远程服务、与数据库交互还是向代理发送消息,所有这些都是基于 I/O 的操作。有效地处理它们对于避免贪婪应用程序至关重要。出于这个原因,Quarkus 使用非阻塞 I/O,它允许少量操作系统线程管理许多并发 I/O。因此,Quarkus 应用程序允许更高的并发性,使用更少的内存,并提高部署密度。
I/O is an essential part of almost any modern system. Whether it is to call a remote service, interact with a database, or send messages to a broker, there are all I/O-based operations. Efficiently handling them is critical to avoid greedy applications. For this reason, Quarkus uses non-blocking I/O, which allows a low number of OS threads to manage many concurrent I/Os. As a result, Quarkus applications allow for higher concurrency, use less memory, and improve the deployment density.
How does Quarkus enable Reactive?
在底层,Quarkus 有一个响应式引擎。由 Eclipse Vert.x 和 Netty 提供支持的此引擎处理非阻塞 I/O 交互。
Under the hood, Quarkus has a reactive engine. This engine, powered by Eclipse Vert.x and Netty, handles the non-blocking I/O interactions.

Quarkus 扩展和应用程序代码可以使用此引擎来协调 I/O 交互,与数据库交互,发送和接收消息,等等。
Quarkus extensions and the application code can use this engine to orchestrate I/O interactions, interact with databases, send and receive messages, and so on.
Reactive execution model
尽管使用非阻塞 I/O 有着巨大的好处,但它并不是免费的。事实上,它引入了一种与经典框架使用的执行模型完全不同的新执行模型。
While using non-blocking I/O has tremendous benefits, it does not come for free. Indeed, it introduces a new execution model quite different from the one used by classical frameworks.
传统的应用程序使用阻塞 I/O 和命令式(顺序)执行模型。因此,在公开 HTTP 终结点的应用程序中,每个 HTTP 请求都与一个线程相关联。通常,该线程会处理整个请求,并且该线程在该请求的持续时间内仅用于处理该请求。当处理需要与远程服务交互时,它使用阻塞 I/O。该线程被阻塞,等待 I/O 的结果。虽然该模型很容易开发(因为一切都按顺序进行),但它有一些缺点。为了处理并发请求,你需要多个线程,所以你需要引入一个工作线程池。此池的大小限制了应用程序的并发性。此外,每个线程在内存和 CPU 方面都有一定成本。大型线程池会导致贪婪的应用程序。
Traditional applications use blocking I/O and an imperative (sequential) execution model. So, in an application exposing an HTTP endpoint, each HTTP request is associated with a thread. In general, that thread is going to process the whole request and the thread is tied up serving only that request for the duration of that request. When the processing requires interacting with a remote service, it uses blocking I/O. The thread is blocked, waiting for the result of the I/O. While that model is simple to develop with (as everything is sequential), it has a few drawbacks. To handle concurrent requests, you need multiple threads, so, you need to introduce a worker thread pool. The size of this pool constrains the concurrency of the application. In addition, each thread has a cost in terms of memory and CPU. Large thread pools result in greedy applications.

如上所述,非阻塞 I/O 避免了这个问题。几个线程可以处理许多并发 I/O。如果我们回到 HTTP 终结点示例,请求处理是在其中一个 I/O 线程上执行的。因为它们的数量很少,所以你需要明智地使用它们。当请求处理需要调用远程服务时,你不能再阻塞线程。你调度 I/O 并传递一个延续,即 I/O 完成后执行的代码。
As we have seen above, non-blocking I/O avoids that problem. A few threads can handle many concurrent I/O. If we go back to the HTTP endpoint example, the request processing is executed on one of these I/O threads. Because there are only a few of them, you need to use them wisely. When the request processing needs to call a remote service, you can’t block the thread anymore. You schedule the I/O and pass a continuation, i.e., the code to execute once the I/O completes.

此模型的效率要高得多,但我们需要一种编写代码的方法来表达这些延续。
This model is much more efficient, but we need a way to write code to express these continuations.
Reactive Programming Models
基于非阻塞 I/O 和消息传递的 Quarkus 架构允许多个支持性响应式开发模型,它们在表达延续方面各不相同。使用 Quarkus 编写响应式代码的两种主要方法是:
The Quarkus architecture, based on non-blocking I/O and message passing, allows multiple supporting reactive development models that are all different in how they express continuations. The two main ways to write reactive code with Quarkus are:
-
Reactive Programming with Mutiny, and
-
Coroutines with Kotlin
首先,@ReactiveProgramming 是一个直观的、事件驱动的响应式编程库。使用 Mutiny,你编写的是事件驱动的代码。你的代码是一个接收事件并处理它们的管道。管道中的每个阶段都可以看作是一个延续,因为 Mutiny 在管道的上游部分发出事件时调用它们。
First, Mutiny is an intuitive, event-driven reactive programming library. With Mutiny, you write event-driven code. Your code is a pipeline receiving events and processing them. Each stage in your pipeline can be seen as a continuation, as Mutiny invokes them when the upstream part of the pipeline emits an event.
Mutiny API 经过精心设计,以提高代码库的可读性和可维护性。Mutiny 提供了编排异步操作所需的一切功能,包括并发执行。它还提供了一大组操作符来处理单个事件和事件流。
The Mutiny API has been tailored to improve the readability and maintenance of the codebase. Mutiny provides everything you need to orchestrate asynchronous actions, including concurrent execution. It also offers a large set of operators to manipulate individual events and streams of events.
在 @Quarkus Extensions documentation 找到有关 Mutiny 及其在 Quarkus 中的用法的更多信息。 |
Find more info about Mutiny and its usage in Quarkus on Mutiny support documentation. |
协程是一种按顺序编写异步代码的方法。它在 I/O 期间暂停代码执行,并将代码的其余部分注册为延续。在 Kotlin 中进行开发时,Kotlin 协程非常棒,而且只需要表达顺序组合(即协同异步任务的链)即可。
Co-routines are a way to write asynchronous code sequentially. It suspends the execution of the code during I/O and registers the rest of the code as the continuation. Kotlin coroutines are great when developing in Kotlin and only need to express sequential compositions (chain of co-dependent asynchronous tasks).
Unification of Imperative and Reactive
更改你的开发模型并不简单。它需要以非阻塞方式重新学习和重构代码。幸运的是,你不需要这样做!
Changing your development model is not simple. It requires relearning and restructuring code in a non-blocking fashion. Fortunately, you don’t have to do it!
Quarkus 由于它的响应式引擎而固有的响应式。但是,作为应用程序开发人员的你,不必编写响应式代码。Quarkus 统一了响应式和命令式编程。这意味着你可以在 Quarkus 上编写传统的阻塞应用程序。但是,该如何避免阻塞 I/O 线程?Quarkus 实现了一个 @BlockingExecutor,它在需要时切换到工作线程。
Quarkus is inherently reactive thanks to its reactive engine. But, you, as an application developer, don’t have to write reactive code. Quarkus unifies reactive and imperative. It means that you can write traditional blocking applications on Quarkus. But how do you avoid blocking the I/O threads? Quarkus implements a proactor pattern that switches to worker thread when needed.

多亏了代码中的提示(比如 @Blocking 和 @NonBlocking 注解),Quarkus 扩展可以决定应用程序逻辑是阻塞还是非阻塞。如果我们回到上面的 HTTP 终结点示例,HTTP 请求始终在一个 I/O 线程上接收。然后,将请求分派到你的代码的扩展决定是否在 I/O 线程上调用它,以避免线程切换,还是在工作线程上调用。此决定取决于扩展。例如,Quarkus REST(以前称为 RESTEasy Reactive)扩展使用 @Blocking 注解来确定是否需要使用工作线程调用该方法,或者是否可以使用 I/O 线程调用该方法。
Thanks to hints in your code (such as the @Blocking
and @NonBlocking
annotations), Quarkus extensions can decide when the application logic is blocking or non-blocking.
If we go back to the HTTP endpoint example from above, the HTTP request is always received on an I/O thread.
Then, the extension dispatching that request to your code decides whether to call it on the I/O thread, avoiding thread switches, or on a worker thread.
This decision depends on the extension.
For example, the Quarkus REST (formerly RESTEasy Reactive) extension uses the @Blocking
annotation to determine if the method needs to be invoked using a worker thread, or if it can be invoked using the I/O thread.
Quarkus 是务实且多功能的。你决定如何开发和执行你的应用程序。你可以使用命令式方法、响应式方法,或者将它们混合使用,在应用程序的高并发部分使用响应式编程。
Quarkus is pragmatic and versatile. You decide how to develop and execute your application. You can use the imperative way, the reactive way, or mix them, using reactive on the parts of the application under high concurrency.
Quarkus Extensions enabling Reactive
Quarkus 提供了一大组响应式 API 和功能。本节列出了最重要的部分,但不是详尽无遗的列表。Quarkus 在每次发布中都会添加新功能,而 @Quarkus Extensions documentation 则提出了允许 @DevServices 的许多扩展。
Quarkus offers a large set of reactive APIs and features. This section lists the most important, but it’s not an exhaustive list. Quarkus adds new features in every release, and the Quarkiverse proposes many extensions enabling Reactive.
HTTP
-
Quarkus REST: an implementation of Jakarta REST tailored for the Quarkus architecture. It follows a reactive-first approach but allows imperative code using the
@Blocking
annotation. -
Reactive Routes: a declarative way to register HTTP routes directly on the Vert.x router used by Quarkus to route HTTP requests to methods.
-
REST Client: allows consuming HTTP endpoints. Under the hood, it uses the non-blocking I/O features from Quarkus.
-
Qute - the Qute template engine exposes a reactive API to render templates in a non-blocking manner.
Data
-
Hibernate Reactive: a version of Hibernate ORM using asynchronous and non-blocking clients to interact with the database.
-
Hibernate Reactive with Panache: provide active record and repository support on top of Hibernate Reactive.
-
Reactive PostgreSQL client: an asynchronous and non-blocking client interacting with a PostgreSQL database, allowing high concurrency.
-
Reactive MySQL client: an asynchronous and non-blocking client interacting with a MySQL database
-
The MongoDB extension: exposes an imperative and reactive (Mutiny) APIs to interact with MongoDB.
-
Mongo with Panache offers active record support for both the imperative and reactive APIs.
-
The Cassandra extension: exposes an imperative and reactive (Mutiny) APIs to interact with Cassandra
-
The Redis extension: exposes an imperative and reactive (Mutiny) APIs to store and retrieve data from a Redis key-value store.
Event-Driven Architecture
-
Reactive Messaging: allows implementing event-driven applications using reactive and imperative code.
-
Kafka Connector for Reactive Messaging: allows implementing applications consuming and writing Kafka records
-
AMQP 1.0 Connector for Reactive Message: allows implementing applications sending and receiving AMQP messages.
Network Protocols and Utilities
-
gRPC: implement and consume gRPC services. Offer reactive and imperative programming interfaces.
-
GraphQL: implement and query (client) data store using GraphQL. Offers Mutiny APIs and subscriptions as event streams.
-
Fault Tolerance: provide retry, fallback, circuit breakers abilities to your application.It can be used with Mutiny types.
Engine
-
Vert.x : the underlying reactive engine of Quarkus. The extension allows accessing to the managed Vert.x instance, as well as its Mutiny variant (exposing the Vert.x API using Mutiny types)
-
Context Propagation: capture and propagate contextual objects (transaction, principal…) in a reactive pipeline