🔥 FREE PRO OFFER OnlyLink.click Pro Version is 100% Free of Cost till 31 December, 2026! Claim Free Pro

Введение в Quarkus: почему разработчики Java переходят на сверхзвуковую Java

Введение в Quarkus: почему разработчики Java переходят на сверхзвуковую Java

На протяжении почти трех десятилетий Java была доминирующей силой в разработке корпоративного программного обеспечения. Его богатая экосистема, надежная объектно-ориентированная основа, независимость от платформы благодаря виртуальной машине Java (JVM) и проверенные в боевых условиях платформы, такие как Spring Boot, сделали его бесспорным королем серверной инфраструктуры.

Однако переход к облачной архитектуре, оркестрации Kubernetes, контейнеризации (Docker) и бессерверным вычислениям (AWS Lambda, Knative) выявил серьезную уязвимость в традиционных платформах приложений Java: высокие затраты памяти и медленное время запуска.

Когда микросервису необходимо горизонтально масштабироваться от нуля до 100 реплик в ответ на всплеск трафика или когда бессерверная функция выполняется по требованию, ожидание загрузки процесса Java от 3 до 10 секунд недопустимо. Современная облачная инфраструктура требует мгновенного запуска и небольшого потребления памяти — качества, традиционно присущие таким языкам, как Go, Rust или Node.js.

Встречайте Quarkus: нативную платформу Java для Kubernetes, разработанную специально для GraalVM и OpenJDK HotSpot. Часто называемый «Сверхзвуковой субатомной Java»*, Quarkus фундаментально меняет способ компиляции, загрузки и запуска Java-приложений.

В этом подробном руководстве мы рассмотрим, почему разработчики Java используют Quarkus, как Quarkus обеспечивает время запуска менее секунды и объем микропамяти, архитектурную механику оптимизации времени сборки и как создать готовый к работе реактивный микросервис на Java с помощью Quarkus.


1. Дилемма облачной среды традиционной Java

Чтобы понять, почему существует Quarkus, мы должны изучить, как «под капотом» работают традиционные Java-фреймворки, такие как Spring Boot или Jakarta EE.

A. Стоимость инициализации тяжелой среды выполнения

Традиционные платформы Java в значительной степени полагаются на динамическое отражение во время выполнения, сканирование путей к классам и генерацию прокси:

  1. Сканирование пути к классам. Во время запуска JVM сканирует каждый файл JAR в пути к классам, чтобы обнаружить такие аннотации, как @Component, @Service, @Controller или @Entity.
  2. Обработка и отражение аннотаций. Платформа использует отражение (Class.forName(), getDeclaredFields()) для построения в памяти графа компонентов, свойств конфигурации и зависимостей.
  3. Динамическое создание прокси: CGLIB или ByteBuddy генерирует динамические прокси-байт-коды в памяти времени выполнения для поддержки аспектно-ориентированного программирования (AOP), управления транзакциями базы данных (@Transactional) и границ безопасности.
  4. Метапространство и расширение RSS. Все метаданные, отраженные дескрипторы классов и сгенерированные прокси должны храниться в памяти внутри метапространства JVM и размера резидентного набора (RSS).

Этот цикл отражения во время выполнения требует значительных циклов ЦП и увеличивает потребление динамической памяти. Базовая служба CRUD REST в традиционной Java может легко занимать от 140 до 300 МБ ОЗУ в режиме ожидания и запускаться от 3 до 8 секунд.

B. Финансовые штрафы за облачные вычисления

В бессерверных и контейнерных средах поставщики облачных услуг взимают плату на основе двух показателей: выделенной памяти (ГБ) и длительности выполнения (миллисекунды).

  • Холодный запуск. Если для загрузки бессерверной функции требуется 5 секунд, конечные пользователи сталкиваются с заметной задержкой, и вы платите за 5 секунд вычислений при запуске в режиме ожидания.
  • Плотность и масштабируемость модулей. В кластере Kubernetes с рабочим узлом, имеющим 16 ГБ ОЗУ, вы можете запустить только около 40 традиционных экземпляров микросервиса Spring Boot, прежде чем у вас закончится память. Если бы каждый экземпляр потреблял только 15 МБ ОЗУ, на одном узле можно было бы разместить более 800 экземпляров.

2. Архитектура Quarkus: перенос работы со времени выполнения на время сборки

Quarkus решает дилемму облачных технологий посредством радикального изменения архитектурной парадигмы: перенос динамических операций из среды выполнения во время сборки.

Традиционная Java во время выполнения и диаграмма архитектуры оптимизации времени сборки Quarkus

Обработка во время сборки (заранее время оптимизации)

Вместо выполнения сканирования пути к классам, анализа аннотаций и связывания графов компонентов каждый раз при загрузке приложения Quarkus выполняет все эти тяжелые операции один раз на этапе сборки (mvn package или ./gradlew build).

  1. Архитектура расширений и этапы сборки: Quarkus использует подключаемую платформу расширений. При компиляции вашего приложения расширения Quarkus анализируют аннотации, генерируют оптимизированный статический байт-код и заранее разрешают графы внедрения зависимостей.
  2. Предварительно подготовленные метаданные: все метаданные внедрения зависимостей предварительно рассчитываются. При запуске приложения Quarkus напрямую создает экземпляры предварительно скомпилированных классов, не вызывая отражения и не сканируя пути к классам.
  3. Устранение мертвого кода (Tree Shaking). В процессе сборки Quarkus определяет классы, методы и библиотеки, которые не используются вашим приложением, и полностью удаляет их.

К моменту создания JAR-файла вашего приложения или собственного двоичного файла все накладные расходы времени выполнения устраняются. JVM просто загружает предварительно подключенные статические байт-коды и мгновенно запускается.


3. Собственный образ GraalVM и OpenJDK HotSpot

Quarkus предлагает модель двойного выполнения: он работает исключительно быстро в стандартном OpenJDK HotSpot, но достигает максимального потенциала производительности при компиляции в собственный образ GraalVM.

+-----------------------------------------------------------------------+
|                         Java Source Code (.java)                      |
+-----------------------------------------------------------------------+
                                    |
                                    v (Standard javac)
+-----------------------------------------------------------------------+
|                            Bytecode (.class)                          |
+-----------------------------------------------------------------------+
                       /                         \
                      /                           \
                     v                             v
   +----------------------------------+   +----------------------------------+
   |      OpenJDK HotSpot JVM         |   |     GraalVM Native Image (AOT)   |
   |  - JIT Compilation (C1/C2)       |   |  - Substrate VM                  |
   |  - Dynamic Class Loading         |   |  - No Classpath Scanning          |
   |  - Fast throughput, longer boot  |   |  - Millisecond boot, tiny RAM    |
   +----------------------------------+   +----------------------------------+

Предварительная компиляция (AOT) и виртуальная машина подложки

GraalVM Native Image берет байт-код Java и компилирует его непосредственно в автономный исполняемый двоичный файл для конкретной ОС (двоичный файл ELF в Linux, Mach-O в macOS, EXE в Windows).

  • Предположение о закрытом мире: GraalVM предполагает, что весь доступный код, классы и ресурсы известны во время сборки.
  • Substrate VM: Собственный исполняемый файл включает в себя миниатюрный механизм выполнения под названием Substrate VM, который управляет памятью, планированием потоков и сборкой мусора без запуска полного экземпляра JVM.
  • Нулевые затраты на отражение: поскольку Quarkus подготавливает конфигурации отражения и определения прокси во время сборки, компиляция собственного образа GraalVM проходит гладко без файлов ручной настройки, которые исторически требовались для собственных сборок GraalVM.

4. Контрольные показатели производительности: эмпирические данные

Чтобы проиллюстрировать резкий контраст в производительности, давайте рассмотрим сравнение стандартных отраслевых тестов для трех конфигураций среды выполнения Java, использующих стандартную службу REST + Database CRUD:

  1. Традиционный облачный стек (традиционная JVM/Spring Boot)
  2. Quarkus в OpenJDK HotSpot
  3. Quarkus в собственном образе GraalVM
Сравнение производительности Java Framework: потребление памяти и время запуска

Сводная таблица производительности

Метрика Традиционный стек (JVM) Кваркус (JVM HotSpot) Кваркус (родной GraalVM)
REST RSS-память ~140 МБ ~74 МБ ~13 МБ
REST + RSS-память CRUD ~218 МБ ~112 МБ ~35 МБ
Время запуска REST ~4,3 секунды ~0,98 секунды ~0,014 секунды (14 мс)
REST + Время запуска CRUD ~9,5 секунд ~2,0 секунды ~0,042 секунды (42 мс)
Исполняемый артефакт Большой толстый JAR (~50 МБ) Оптимизированный JAR (~20 МБ) Автономный собственный двоичный файл (~30 МБ)

Обратите внимание, что Quarkus, скомпилированный в собственный образ, загружается за 14 миллисекунд — быстрее, чем одно мгновение — и потребляет всего 13 МБ ОЗУ. Это делает Java полностью конкурентоспособным с Go и Rust для бессерверных и облачных развертываний.


5. Реактивный и императивный двухъядерный двигатель

Исторически разработчикам Java приходилось выбирать между двумя взаимоисключающими моделями программирования:

  1. Императивный (потоков на запрос): простой, читаемый код блокировки с использованием стандартных драйверов JDBC и синхронных конечных точек REST.
  2. Реактивный (цикл событий): асинхронный неблокирующийся код (например, RxJava, Project Reactor), обладающий высокой пропускной способностью, но известный своими сложными цепочками обратных вызовов и сложной отладкой.

Quarkus объединяет оба мира в одном связном движке, работающем на базе Eclipse Vert.x и Netty.

                      +---------------------------------+
                      |     Client HTTP Request         |
                      +---------------------------------+
                                       |
                                       v
                      +---------------------------------+
                      |       Eclipse Vert.x I/O        |
                      |          (Event Loop)           |
                      +---------------------------------+
                                   /       \
                                  /         \
                                 v           v
                 +-------------------+   +-------------------+
                 | Reactive Endpoint |   |Blocking Endpoint  |
                 | (Event Loop)      |   | (Worker Thread)   |
                 | - Mutiny (Uni/Multi)| | - Standard JDBC   |
                 | - Non-blocking    |   | - Imperative Code |
                 +-------------------+   +-------------------+

В Quarkus основой является неблокирующий ввод-вывод. Если вы пишете традиционный блокирующий код, Quarkus автоматически отправляет выполнение в управляемый пул рабочих потоков. Если вы используете реактивные типы, такие как SmallRye Mutiny (Uni<T> и Multi<T>), выполнение остается в высокопроизводительном неблокирующем потоке цикла событий.


6. Радость разработчика: услуги живого кодирования и разработки

Помимо производительности во время выполнения, Quarkus предоставляет революционные возможности для разработчиков, призванные устранить утомительный цикл обратной связи «сборка-тестирование-перезапуск».

A. Живое кодирование с нулевым перезапуском (quarkus:dev)

При запуске mvn quarkus:dev Quarkus запускает режим живого кодирования. Вы можете редактировать файлы Java, изменять свойства, изменять шаблоны HTML или обновлять схемы базы данных.

В следующий раз, когда вы вызовете HTTP-запрос в браузере или терминале, Quarkus обнаружит изменения в файле, повторно применит этапы сборки и перезагрузит приложение в горячем режиме за менее 500 миллисекунд. Вам никогда не придется вручную останавливать и перезапускать сервер приложений во время разработки.

B. Quarkus Dev Services (тестовые контейнеры с нулевой конфигурацией)

Подключение микросервиса к базе данных PostgreSQL, брокеру Kafka или кешу Redis обычно требует написания файла docker-compose.yml и настройки портов локальной базы данных.

С помощью Quarkus Dev Services:

  • Если Quarkus обнаруживает зависимость базы данных (например, quarkus-reactive-pg-client), но URL-адрес базы данных не настроен в application.properties, Quarkus автоматически запускает контейнер Docker, запускающий PostgreSQL через Testcontainers в фоновом режиме.
  • Он автоматически вводит учетные данные подключения в работающее приложение.
  • Когда вы выходите из режима разработки, контейнер полностью очищается.

7. Практическое руководство: создание готового к эксплуатации реактивного сервиса Quarkus

Давайте создадим чистый, высокопроизводительный микросервис Quarkus на Java, который предоставляет REST API, подключенный к базе данных PostgreSQL, с помощью Hibernate Reactive with Panache.

Шаг 1. Зависимости проекта (pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ghaznix.quarkus</groupId>
    <artifactId>user-service</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <properties>
        <compiler-plugin.version>3.13.0</compiler-plugin.version>
        <maven.compiler.release>21</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
        <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
        <quarkus.platform.version>3.15.1</quarkus.platform.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>${quarkus.platform.artifact-id}</artifactId>
                <version>${quarkus.platform.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- RESTEasy Reactive for high-performance HTTP endpoints -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
        </dependency>

        <!-- Hibernate Reactive with Panache for active-record data access -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-hibernate-reactive-panache</artifactId>
        </dependency>

        <!-- Reactive PostgreSQL Driver -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-reactive-pg-client</artifactId>
        </dependency>

        <!-- Quarkus SmallRye OpenAPI / Swagger UI -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-smallrye-openapi</artifactId>
        </dependency>

        <!-- Testing -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>quarkus-maven-plugin</artifactId>
                <version>${quarkus.platform.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Шаг 2. Определите реактивную сущность (UserEntity.java)

Quarkus упростил доступ к данным с помощью Panache, реализации шаблона Active-Record поверх Hibernate.

package com.ghaznix.quarkus.entity;

import io.quarkus.hibernate.reactive.panache.PanacheEntity;
import io.smallrye.mutiny.Uni;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import java.time.Instant;

@Entity
@Table(name = "users")
public class UserEntity extends PanacheEntity {

    @NotBlank(message = "Username cannot be blank")
    @Column(unique = true, nullable = false)
    public String username;

    @Email(message = "Email must be valid")
    @Column(unique = true, nullable = false)
    public String email;

    @Column(nullable = false)
    public String role;

    @Column(name = "created_at", nullable = false, updatable = false)
    public Instant createdAt = Instant.now();

    /**
     * Helper method to find a user reactively by email.
     */
    public static Uni<UserEntity> findByEmail(String email) {
        return find("email", email).firstResult();
    }
}

Шаг 3. Реализация реактивного ресурса REST (UserResource.java)

Используя RESTEasy Reactive и SmallRye Mutiny, наши конечные точки HTTP работают полностью асинхронно в неблокирующих потоках:

package com.ghaznix.quarkus.resource;

import com.ghaznix.quarkus.entity.UserEntity;
import io.quarkus.hibernate.reactive.panache.Panache;
import io.smallrye.mutiny.Uni;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.validation.Valid;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.net.URI;
import java.util.List;

@Path("/api/v1/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@ApplicationScoped
public class UserResource {

    @GET
    public Uni<List<UserEntity>> getAllUsers() {
        return UserEntity.listAll();
    }

    @GET
    @Path("/{id}")
    public Uni<Response> getUserById(@PathParam("id") Long id) {
        return UserEntity.<UserEntity>findById(id)
                .onItem().ifNotNull().transform(user -> Response.ok(user).build())
                .onItem().ifNull().continueWith(() -> Response.status(Response.Status.NOT_FOUND).build());
    }

    @POST
    public Uni<Response> createUser(@Valid UserEntity user) {
        return Panache.withTransaction(user::persist)
                .replaceWith(() -> Response.created(URI.create("/api/v1/users/" + user.id))
                        .entity(user)
                        .build());
    }

    @DELETE
    @Path("/{id}")
    public Uni<Response> deleteUser(@PathParam("id") Long id) {
        return Panache.withTransaction(() -> UserEntity.deleteById(id))
                .map(deleted -> deleted 
                        ? Response.noContent().build() 
                        : Response.status(Response.Status.NOT_FOUND).build());
    }
}

Шаг 4. Настройка приложения (application.properties)

# Quarkus Application Configuration
quarkus.application.name=user-service
quarkus.http.port=8080

# Database Schema Management (Automatically managed by Dev Services in dev mode)
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.log.sql=true

# SmallRye OpenAPI & Swagger UI Configuration
quarkus.smallrye-openapi.path=/swagger-ui
quarkus.swagger-ui.always-include=true

Обратите внимание, что мы не настраивали URL-адреса базы данных, имена пользователей и пароли! Когда вы запускаете ./mvnw quarkus:dev, Quarkus автоматически обнаруживает PostgreSQL, запускает контейнер Docker, настраивает таблицы схемы базы данных и открывает пользовательский интерфейс Swagger по адресу http://localhost:8080/swagger-ui.


Шаг 5. Создание и выполнение собственных исполняемых файлов

Чтобы запустить мгновенный режим разработки Live-Coding:

./mvnw quarkus:dev

Чтобы создать собственный двоичный файл Linux с использованием GraalVM внутри контейнера Docker (локальная установка GraalVM не требуется):

./mvnw package -Dnative -Dquarkus.native.container-build=true

Чтобы запустить полученный бинарный файл непосредственно в вашей ОС:

./target/user-service-1.0.0-SNAPSHOT-runner
__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
2026-08-26 01:37:15,102 INFO  [io.quarkus] (main) user-service 1.0.0-SNAPSHOT native (powered by Quarkus 3.15.1) started in 0.016s. Listening on: http://0.0.0.0:8080
2026-08-26 01:37:15,103 INFO  [io.quarkus] (main) Profile prod activated. 
2026-08-26 01:37:15,103 INFO  [io.quarkus] (main) Installed features: [cdi, hibernate-reactive, panache, reactive-pg-client, resteasy-reactive, resteasy-reactive-jackson, smallrye-openapi]

Запуск 0,016 секунды!


8. Сравнение стратегических функций: Quarkus и Spring Boot

Возможность/Функция Традиционная весенняя загрузка 3.x Кваркус 3.x
Основная архитектура Отражение во время выполнения и динамическое сканирование Обработка во время сборки и оптимизация AOT
Встроенная компиляция Spring Native (требуются сложные подсказки) Первоклассная встроенная интеграция GraalVM
Скорость запуска (исходная) ~0,1–0,5 с ~0,01–0,04 с
Память RSS-следа 140 МБ - 300 МБ 13–40 МБ
Среда разработки Горячая замена через DevTools (ограничено) Живое кодирование без перезапуска (quarkus:dev)
Сторонние услуги Ручная настройка Docker/Testcontainers Услуги автоматической разработки (контейнеры с нулевой конфигурацией)
Поддержка стандартов Весенняя экосистема Стандартные характеристики Jakarta EE и MicroProfile
Реактивная парадигма Spring WebFlux (отдельный стек) Унифицированный движок (ядро Vert.x/реактивный + императивный)

9. Заключение: пора ли переходить на Quarkus?

Quarkus — это не просто еще один веб-фреймворк; он представляет собой эволюцию Java в эпоху облачных технологий. Сочетая оптимизацию времени сборки со встроенной компиляцией GraalVM, Quarkus опровергает устаревший стереотип о том, что Java слишком медленная или слишком перегруженная памятью для современных микросервисов и бессерверных функций.

Когда следует выбирать Quarkus?

  • Бессерверные и управляемые событиями приложения. Если вы развертываете микросервисы в AWS Lambda, GCP Cloud Run или Knative, встроенные двоичные файлы Quarkus полностью устраняют проблемы с холодным запуском.
  • Кластеры Kubernetes с высокой плотностью. Если в расходах на инфраструктуру преобладает потребление оперативной памяти кластера, миграция сервисов на Quarkus может сократить затраты на память до 75 %.
  • Реактивные микросервисы. Если вы создаете системы с высокой пропускной способностью, требующие неблокируемой потоковой передачи (Kafka, gRPC, WebSockets), Quarkus сразу же обеспечивает высочайший уровень производительности.

Java больше не привязана к медленным запускам или раздутой среде выполнения. С помощью Quarkus разработчики Java могут создавать облачные приложения с сверхзвуковой скоростью и субатомным объемом.

Ghaznix Ecosystem Products

Empower Your Digital Presence & Workflows

Explore top-tier tools built by Ghaznix to streamline your links, surveys, and brand growth.