Главная
АИ #34 (113)
Статьи журнала АИ #34 (113)
Методика реактивного программирования spring boot webflux

10.5281/zenodo.12260574

Методика реактивного программирования spring boot webflux

Автор(-ы):

Фроликов Евгений Александрович

27 августа 2022

Секция

Информационные технологии

Ключевые слова

программирование
реактивное программирование
spring boot webflux
IT
IT отрасль

Аннотация статьи

Реактивное программирование, особенно в контексте использования Spring Boot WebFlux, представляет собой парадигму разработки, фокусирующуюся на асинхронной и неблокирующей обработке данных. Эта методология становится все более популярной из-за ограничений традиционного императивного программирования, которые особенно остро проявляются в высоконагруженных системах. В традиционных моделях, таких как Spring MVC, каждый запрос назначается отдельному потоку, что приводит к высоким затратам на память и блокировке потоков во время операций ввода-вывода. Реактивное программирование решает эти проблемы, предлагая асинхронное выполнение и минимизацию блокировок, что повышает эффективность использования ресурсов и снижает время отклика приложений. Основные преимущества включают обработку большего количества запросов с меньшим числом потоков, избегание блокировки во время ввода-вывода, упрощение параллельных вызовов и поддержку механизма обратного давления для управления нагрузкой. Эти аспекты делают реактивное программирование особенно актуальным для современных микросервисных архитектур и высоконагруженных систем.

Текст статьи

Введение

Реактивное программирование с помощью Spring Boot с использованием WebFlux представляет собой переход в сторону создания неблокирующих асинхронных веб-приложений, которые могут обрабатывать больше одновременных пользователей с меньшим количеством аппаратных ресурсов, чем традиционные модели на основе сервлетов. Так, например, внедрение Spring WebFlux в экосистему Spring позволило адаптировать корпоративные приложения к современным требованиям масштабируемости и устойчивости.

Spring WebFlux, представленный в Spring Framework 5, использует API Reactive Streams для поддержки асинхронной обработки потоков с неблокирующим обратным давлением. Платформа предназначена для работы на таких серверах, как контейнеры Netty, Undertow и Servlet 3.1+, через адаптеры, обеспечивая гибкость в развертывании и совместимость с существующими компонентами экосистемы Spring.

Сравнение производительности показывает, что Spring WebFlux предлагает лучшее время отклика при более низких уровнях параллелизма по сравнению с традиционными платформами блокировки, что становится все более очевидным по мере масштабирования системы [6]. Этому способствует его управляемый событиями характер, который оптимально использует системные ресурсы, обрабатывая операции только тогда, когда данные доступны, без связывания потоков, праздно ожидающих завершения операций ввода-вывода.

Более того, интеграция Spring WebFlux с такими технологиями, как GraalVM, открыла возможности для еще более быстрого запуска и уменьшения объема памяти. GraalVM позволяет заранее компилировать приложения Spring Boot в собственные образы, что приводит к значительно более быстрому запуску и максимальной производительности с самого начала, что делает его особенно подходящим для микросервисов, которые могут масштабироваться до нуля по требованию [6].

Наблюдение в приложениях Spring Boot WebFlux повышается за счет интеграции с такими платформами, как Prometheus и Zipkin, что позволяет осуществлять детальный мониторинг и отслеживание веб-запросов и системных показателей. Эти возможности способствуют поддержанию высокопроизводительных реактивных систем и обеспечения их соответствия строгим требованиям современных приложений с точки зрения производительности и надежности [6].

Проактивный подход Spring к использованию реактивного программирования с помощью WebFlux и его интеграции с передовыми технологиями позиционирует его как надежную среду, способную управлять следующим поколением облачных приложений. Постоянные достижения в этой области отражают целенаправленные усилия по удовлетворению растущих потребностей разработчиков и предприятий в более эффективных, масштабируемых и отказоустойчивых архитектурах приложений.

Актуальность изучения этой темы обусловлена не только необходимостью повышения производительности приложений, но и растущим спросом на разработчиков, обладающих компетенциями в области реактивного программирования. Основные проблемы, которые необходимо рассмотреть в рамках данной темы, включают сложности перехода от императивной к реактивной модели программирования, необходимость освоения новых подходов и инструментов, а также интеграцию реактивных приложений с существующими системами и сервисами.

1. Общая характеристика традиционного подхода

Для того чтобы разобраться, в сущности, реактивного программирования и его преимуществах, сначала рассмотрим традиционный подход к разработке веб-приложений с использованием Spring MVC и его развертыванием в контейнере сервлетов, например, Tomcat. Контейнер сервлетов использует выделенный пул потоков для обработки HTTP-запросов, где каждый входящий запрос назначается отдельному потоку, который обрабатывает весь жизненный цикл запроса (так называемая «модель потока на запрос»). Это означает, что приложение может обрабатывать только столько одновременных запросов, сколько позволяет размер пула потоков. Размер пула потоков можно настроить, однако каждый поток требует определенного объема памяти (обычно около 1 МБ), и с увеличением размера пула растет и потребление памяти.

При архитектуре, основанной на микросервисах, масштабируемость приложения повышается, но высокое потребление памяти остается значительной проблемой. Таким образом, модель потока на запрос может быть довольно затратной для приложений, обрабатывающих большое количество одновременных запросов.

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

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

Реактивное программирование предлагает альтернативный подход, который позволяет значительно повысить эффективность использования ресурсов за счет асинхронного выполнения операций и минимизации времени блокировок, что особенно важно для современных высоконагруженных приложений.

image.pngРис. 1. Пример блокирования поток в ожидании ответа [1]

Еще одна проблема традиционного императивного программирования — это время отклика, когда сервису необходимо выполнить более одного запроса ввода-вывода. Например, службе A может потребоваться вызвать службы B и C, а также выполнить поиск в базе данных и затем вернуть в результате некоторые агрегированные данные. Это означало бы, что время ответа службы А, помимо собственного времени обработки, будет суммой:

  • Время ответа службы B (задержка сети + обработка).
  • Время ответа службы C (задержка сети + обработка).
  • Время ответа запроса к базе данных (задержка сети + обработка).

image.pngРис. 2. Вызовы, выполняемые последовательно [1]

Если нет логической необходимости выполнять эти вызовы последовательно, параллельное выполнение окажет значительное положительное влияние на время отклика службы А. Хотя Java предоставляет возможности для асинхронных вызовов с использованием CompletableFutures и регистрации обратных вызовов, широкое применение этого подхода может усложнить код, сделав его менее читабельным и трудным для сопровождения [1].

Описанные выше проблемы призваны решать методы реактивного программирования, о чем будет рассказано далее.

2. Общая характеристика реактивного программирования

Реактивное программирование представляет собой парадигму, широко применяемую в веб-разработке и разработке мобильных приложений. Оно обеспечивает неблокирующий асинхронный метод обработки данных, способствуя эффективному управлению потоками данных и их синхронизации между различными компонентами. Эта парадигма поддерживается множеством фреймворков и библиотек, таких как Project Reactor, RxJava и Spring WebFlux.

Реактивное программирование играет ключевую роль в создании «реактивных систем», концепции, изложенной в «Реактивном манифесте». Данный манифест акцентирует внимание на необходимости разработки современных приложений, обладающих следующими характеристиками:

  • Отзывчивость (своевременное реагирование на запросы).
  • Устойчивость (способность сохранять отзывчивость даже при сбоях).
  • Эластичность (поддержание отзывчивости при изменении рабочей нагрузки).
  • Асинхронная передача сообщений (использование асинхронных механизмов обмена данными).

Создание реактивной системы требует решения множества задач, таких как распределение задач, обеспечение согласованности данных, управление сбоями и выбор подходящих методов обмена сообщениями. Реактивное программирование может служить методом реализации, обеспечивая асинхронную и неблокирующую модель для отдельных сервисов. Однако для проектирования всей системы как реактивной требуется комплексный подход, учитывающий все перечисленные аспекты [2].

Основные компоненты реактивного программирования включают:

Observables: это источники данных, представляющие собой потоки событий. Они генерируют элементы по мере времени, позволяя подписчикам наблюдать за этими событиями и реагировать на них.

Подписчики: это компоненты, которые потребляют события из Observables. Они выполняют определенные действия, такие как обновление состояния системы, в ответ на полученные события.

Операторы: это функции, применяемые к Observables для управления испускаемыми событиями. Операторы могут выполнять фильтрацию, трансформацию и другие виды обработки событий [3, 4].

На рисунке 3 наглядно показано преимущество в производительности реактивных веб-сервисов по сравнению с обычными, блокирующими. При загруженности сервера в 300 и более пользователей Netty начинает превосходить Tomcat по количеству одновременно обрабатываемых запросов. При предельной загруженности сервера в реактивном режиме может одновременно обслуживаться в 2 раза больше пользователей. По другим источникам преимущество не так внушительно, но заметно. Наибольший эффект реактивное программирование дает при вертикальном масштабировании.

image.pngРис. 3. Влияние реактивного программирования на производительность [5]

Также другим преимуществом реактивного подхода является слабая связность. Например, при разрыве соединения между клиентом и сервисом оно автоматически восстанавливается при возобновлении доступа к Интернету. При этом временные ограничения не накладываются, поскольку соединение устанавливается для отдельного потока, не влияя на другие. Важно, чтобы реактивный подход был реализован как на стороне клиента, так и на стороне сервера.

Создание приложений с использованием множества неблокирующих потоков требует особого стиля программирования и подхода. Этот стиль базируется на использовании лямбда-выражений и реактивных библиотек. Например, библиотека Project Reactor, интегрированная в WebFlux, отличается от реактивной библиотеки RxJava, которая часто используется в Android, тем, что более подходит для серверной части приложений. В Project Reactor устранены некоторые проблемы, такие как потенциальные утечки памяти.

Среди недостатков реактивного программирования можно выделить ограниченные возможности работы с реляционными базами данных. Например, библиотеки JPA, такие как Hibernate и EclipseLink, не поддерживают реактивность. В Java невозможно описывать сложные связи между объектами с использованием аннотаций @Entity, @OneToMany, @ManyToMany, @JoinTable и других. Это затрудняет программное описание ограничений целостности таблиц, хотя и придает большую гибкость используемой базе данных. Для привязки классов к таблицам можно использовать аннотации @Table и @Column. Языки JPQL и HQL не подходят для реактивных запросов к базе данных, однако доступен нативный SQL. Вместо традиционного JDBC используется R2DBC [5].

То есть можно сказать, что Spring Boot WebFlux, как часть экосистемы Spring, использует проект Reactor для реализации реактивного подхода, предоставляя разработчикам инструменты для построения более отзывчивых и устойчивых к нагрузкам систем. Это особенно актуально в условиях современных требований к веб-приложениям, где важны не только быстродействие, но и способность обрабатывать высокие объемы данных и поддерживать множество одновременных соединений. Однако переход к реактивной модели требует значительных изменений в архитектуре приложений и освоения новых концепций, что может вызывать трудности у разработчиков, привыкших к традиционному императивному стилю программирования.

Заключение

Реактивное программирование, воплощенное в Spring Boot WebFlux, предлагает значительные улучшения в производительности и эффективности современных веб-приложений по сравнению с традиционными императивными подходами. Оно предоставляет асинхронную и неблокирующую модель, которая позволяет обрабатывать большее количество одновременных запросов с меньшими ресурсными затратами. Этот подход особенно полезен для высоконагруженных систем и микросервисных архитектур, где важно минимизировать время отклика и эффективно управлять ресурсами. Использование асинхронных потоков данных и механизма обратного давления позволяет создавать отзывчивые и устойчивые приложения, которые сохраняют свою эффективность даже при изменении рабочей нагрузки. Несмотря на некоторые ограничения, такие как сложность интеграции с реляционными базами данных, преимущества реактивного программирования делают его незаменимым инструментом для разработки современных веб-приложений, требующих высокой производительности и надежности.

Список литературы

  1. An Introduction to Reactive Programming With Spring. [Электронный ресурс] Режим доступа: https://dzone.com/articles/an-introduction-to-reactive-programming-with-sprin (дата обращения 22.05.2022).
  2. Spring Boot WebFlux example: Building Rest API. [Электронный ресурс] Режим доступа: https://www.bezkoder.com/spring-boot-webflux-rest-api/ (дата обращения 22.05.2022).
  3. How to implement Reactive Programming in Spring Boot? [Электронный ресурс] Режим доступа: https://fullstackdeveloper.guru/2022/06/10/how-to-implement-reactive-programming-in-spring-boot/comment-page-1/ (дата обращения 22.05.2022).
  4. Reactive Programming Spring Boot Tutorial. [Электронный ресурс] Режим доступа: https://javatechonline.com/java-reactive-programming-spring-boot/ (дата обращения 22.05.2022).
  5. Spring WebFlux: Реактивное программирование веб-сервисов. [Электронный ресурс] Режим доступа: https://habr.com/ru/articles/565752/ (дата обращения 22.05.2022).
  6. Spring WebFlux. [Электронный ресурс] Режим доступа: https://docs.spring.io/spring-framework/reference/web/webflux.html (дата обращения 22.05.2022).

Поделиться

Ф. Е. Методика реактивного программирования spring boot webflux // Актуальные исследования. 2022. №34 (113). URL: https://apni.ru/article/6039-metodika-reaktivnogo-programmirovaniya-spring-boot-webflux

Похожие статьи

Другие статьи из раздела «Информационные технологии»

Все статьи выпуска
Актуальные исследования

#27 (209)

Прием материалов

29 июня - 5 июля

осталось 3 дня

Размещение PDF-версии журнала

10 июля

Размещение электронной версии статьи

сразу после оплаты

Рассылка печатных экземпляров

22 июля