Quarkus Reactive Architecture

Quarkus 是响应式的。它甚至不仅仅是这样:Quarkus 统一了响应式和命令式编程。你甚至不必进行选择:你可以实现响应式组件和命令式组件,然后在 same 应用程序中对其进行组合。无需使用不同的栈、工具或 API;Quarkus 连接了这两个世界。 此页面将解释 Reactive 的含义以及 Quarkus 如何启用它。我们还将讨论执行和编程模型。最后,我们将列出提供了响应式方面的 Quarkus 扩展。

What is Reactive?

Reactive 一词被过载,并与许多概念相关,例如反压、单子或事件驱动架构。因此,让我们澄清一下 Reactive 的含义。

Reactive 是一组原则和指导方针,用于构建响应式分布式系统和应用程序。 Reactive ManifestoReactive Systems 描述为具有以下四个特征的分布式系统:

  1. 响应式——它们必须及时响应

  2. 弹性——它们会自动适应波动负载

  3. 恢复力——它们会优雅地处理故障

  4. 异步消息传递——响应式系统组件使用消息进行交互

reactive systems

此外, Reactive Principles white paper 列出了一组规则和模式来帮助构建响应式系统。

Reactive Systems and Quarkus

响应式系统是一种架构风格,可以概括为:正确完成分布式系统。依赖异步消息传递有助于在不同组件之间强制实现松耦合(无论是在空间方面还是时间方面)。你向虚拟目标发送消息。接收者可以位于任何位置,甚至在发送消息时尚未存在。弹性支柱允许根据负载按比例放大和缩小各个组件。弹性还提供了冗余,有助于提高恢复力。失败是不可避免的。组成响应式系统的组件必须优雅地处理它们,避免级联故障,并自动适应自身。

响应式系统可以在面对故障和波动负载时继续处理请求。Quarkus 已为此量身定制。它提供了将有助于你设计、实现和操作响应式系统的一些功能。

Reactive Applications

Quarkus 不仅将帮助你构建响应式系统。它还将确保每个组成部分强制执行响应式原则,并且非常高效。

效率至关重要,尤其是在云环境和容器化环境中。资源(如 CPU 和内存)在多个应用程序之间共享。消耗大量内存的贪婪应用程序效率低下,并会对关联应用程序造成负担。你可能需要申请更多内存、CPU 或更大的虚拟机。它要么会增加你的每月云账单,要么会降低你的部署密度。

I/O 是几乎任何现代系统的重要组成部分。无论是调用远程服务、与数据库交互还是向代理发送消息,所有这些都是基于 I/O 的操作。有效地处理它们对于避免贪婪应用程序至关重要。出于这个原因,Quarkus 使用非阻塞 I/O,它允许少量操作系统线程管理许多并发 I/O。因此,Quarkus 应用程序允许更高的并发性,使用更少的内存,并提高部署密度。

How does Quarkus enable Reactive?

在底层,Quarkus 有一个响应式引擎。由 Eclipse Vert.x 和 Netty 提供支持的此引擎处理非阻塞 I/O 交互。

quarkus reactive core

Quarkus 扩展和应用程序代码可以使用此引擎来协调 I/O 交互,与数据库交互,发送和接收消息,等等。

Reactive execution model

尽管使用非阻塞 I/O 有着巨大的好处,但它并不是免费的。事实上,它引入了一种与经典框架使用的执行模型完全不同的新执行模型。

传统的应用程序使用阻塞 I/O 和命令式(顺序)执行模型。因此,在公开 HTTP 终结点的应用程序中,每个 HTTP 请求都与一个线程相关联。通常,该线程会处理整个请求,并且该线程在该请求的持续时间内仅用于处理该请求。当处理需要与远程服务交互时,它使用阻塞 I/O。该线程被阻塞,等待 I/O 的结果。虽然该模型很容易开发(因为一切都按顺序进行),但它有一些缺点。为了处理并发请求,你需要多个线程,所以你需要引入一个工作线程池。此池的大小限制了应用程序的并发性。此外,每个线程在内存和 CPU 方面都有一定成本。大型线程池会导致贪婪的应用程序。

blocking threads

如上所述,非阻塞 I/O 避免了这个问题。几个线程可以处理许多并发 I/O。如果我们回到 HTTP 终结点示例,请求处理是在其中一个 I/O 线程上执行的。因为它们的数量很少,所以你需要明智地使用它们。当请求处理需要调用远程服务时,你不能再阻塞线程。你调度 I/O 并传递一个延续,即 I/O 完成后执行的代码。

reactive thread

此模型的效率要高得多,但我们需要一种编写代码的方法来表达这些延续。

Reactive Programming Models

基于非阻塞 I/O 和消息传递的 Quarkus 架构允许多个支持性响应式开发模型,它们在表达延续方面各不相同。使用 Quarkus 编写响应式代码的两种主要方法是:

  • 使用 @ReactiveProgramming 的响应式编程,以及

  • Coroutines with Kotlin

首先,@ReactiveProgramming 是一个直观的、事件驱动的响应式编程库。使用 Mutiny,你编写的是事件驱动的代码。你的代码是一个接收事件并处理它们的管道。管道中的每个阶段都可以看作是一个延续,因为 Mutiny 在管道的上游部分发出事件时调用它们。

Mutiny API 经过精心设计,以提高代码库的可读性和可维护性。Mutiny 提供了编排异步操作所需的一切功能,包括并发执行。它还提供了一大组操作符来处理单个事件和事件流。

在 @Quarkus Extensions documentation 找到有关 Mutiny 及其在 Quarkus 中的用法的更多信息。

协程是一种按顺序编写异步代码的方法。它在 I/O 期间暂停代码执行,并将代码的其余部分注册为延续。在 Kotlin 中进行开发时,Kotlin 协程非常棒,而且只需要表达顺序组合(即协同异步任务的链)即可。

Unification of Imperative and Reactive

更改你的开发模型并不简单。它需要以非阻塞方式重新学习和重构代码。幸运的是,你不需要这样做!

Quarkus 由于它的响应式引擎而固有的响应式。但是,作为应用程序开发人员的你,不必编写响应式代码。Quarkus 统一了响应式和命令式编程。这意味着你可以在 Quarkus 上编写传统的阻塞应用程序。但是,该如何避免阻塞 I/O 线程?Quarkus 实现了一个 @BlockingExecutor,它在需要时切换到工作线程。

proactor pattern

多亏了代码中的提示(比如 @Blocking 和 @NonBlocking 注解),Quarkus 扩展可以决定应用程序逻辑是阻塞还是非阻塞。如果我们回到上面的 HTTP 终结点示例,HTTP 请求始终在一个 I/O 线程上接收。然后,将请求分派到你的代码的扩展决定是否在 I/O 线程上调用它,以避免线程切换,还是在工作线程上调用。此决定取决于扩展。例如,Quarkus REST(以前称为 RESTEasy Reactive)扩展使用 @Blocking 注解来确定是否需要使用工作线程调用该方法,或者是否可以使用 I/O 线程调用该方法。

Quarkus 是务实且多功能的。你决定如何开发和执行你的应用程序。你可以使用命令式方法、响应式方法,或者将它们混合使用,在应用程序的高并发部分使用响应式编程。

Quarkus Extensions enabling Reactive

Quarkus 提供了一大组响应式 API 和功能。本节列出了最重要的部分,但不是详尽无遗的列表。Quarkus 在每次发布中都会添加新功能,而 @Quarkus Extensions documentation 则提出了允许 @DevServices 的许多扩展。

HTTP

  • Quarkus REST:为 Quarkus 架构定制的 Jakarta REST 实现。它遵循响应式优先的方法,但允许使用 @NonBlocking 注解的命令式代码。

  • 响应式路由:一种在 Quarkus 使用的 Vert.x 路由器上直接注册 HTTP 路由的声明方式,用于将 HTTP 请求路由到方法。

  • REST Client:允许消耗 HTTP 终结点。在其底层,它使用 Quarkus 的非阻塞 I/O 功能。

  • Qute - Qute 模板引擎公开了一个响应式 API,用于以非阻塞方式渲染模板。

Data

  • Hibernate Reactive:使用异步且非阻塞客户端来与数据库进行交互的 Hibernate ORM 的一个版本。

  • Hibernate Reactive with Panache:在 Hibernate Reactive 之上提供活动记录与存储库支持。

  • Reactive PostgreSQL 客户端:与 PostgreSQL 数据库交互的异步且非阻塞客户端,允许高度并发。

  • Reactive MySQL 客户端:与 MySQL 数据库交互的异步且非阻塞客户端

  • MongoDB 扩展:提供命令性和响应式(Mutiny)API,以便与 MongoDB 进行交互。

  • Mongo with Panache 为命令性和响应式 API 同时提供活动记录支持。

  • Cassandra 扩展:提供命令性和响应式(Mutiny)API,以便与 Cassandra 进行交互

  • Redis 扩展:提供命令性和响应式(Mutiny)API 来自 Redis 键值存储中存储和检索数据。

Event-Driven Architecture

  • Reactive Messaging:允许使用响应式和命令性代码实现事件驱动的应用程序。

  • Reactive Messaging 的 Kafka 连接器:允许实现消费和写入 Kafka 记录的应用程序

  • Reactive Message 的 AMQP 1.0 连接器:允许实现发送和接收 AMQP 消息的应用程序。

Network Protocols and Utilities

  • gRPC:实现和消费 gRPC 服务。提供响应式和命令性编程接口。

  • GraphQL:使用 GraphQL 实现和查询(客户端)数据存储。提供 Mutiny API 和订阅即事件流。

  • 容错:提供重试、后备、断路器功能,让您的应用程序可以利用 Mutiny 类型。

Engine

  • Vert.x:Quarkus 潜在的响应式引擎。此扩展允许访问托管的 Vert.x 实例及其 Mutiny 变体(使用 Mutiny 类型公开 Vert.x API)

  • 上下文传播:在响应式管道中捕获并传播上下文对象(事务、主体……)