Организатор:: Т-Банк
Конференция:: Конференция. JVM Day 2024
Автор:: Сергей Петрелевич
Ссылка:: Могут ли Virtual threads заменить Webflux? — Сергей Петрелевич, Squad - YouTube



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

Тезисы

  • Прикладным разработчикам удобнее работать с абстракциями высшего порядка (Spring WebFlux, Quarkus Reactive).
  • Реактивный подход остается актуальным в некоторых задачах. Архитектору как и прежде необходимо выбирать подходящий инструмент для конкретной задачи.
    • Виртуальные потоки могут дать существенный прирост (в 2 раза) производительности существующему приложению.
      • Виртуальные потоки легко включить, от разработчика не требуется переписывать существующий код.
    • Реактивный подход (Spring WebFlux) позволит дать максимальный прирост производительности (в 3.8 раза), но за это придется заплатить.

Конспект

Автор считает, что Java не самый эффективный язык программирования с точки зрения потребления ресурсов

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

Автор рассматривает Event Loop. Реализация в Java: NIO Selector.

Можно работать напрямую с NIO, но прикладным разработчикам удобнее работать с Netty, который позволяет работать с более высокоуровневыми абстракциям, при этом сохраняя все преимущества NIO. Но есть еще более высокоуровневая абстракция поверх Netty.

NIO посылает события Netty их преобразовывает в более удобный вид. Далее можно сделать Callback-и, на основе этого работает Vert.x. Второй подход это использовать реактивный API: Reactor Netty. Именно этот подход автор и будет рассматривать.

Можно реализовывать свои приложения сразу на Reactor Netty, но еще удобнее использовать Spring Webflux. Это реактивный функциональный (позволяет разрабатывать в функциональном стиле) http-сервер, который эффективно использует ресурсы.

Пример “функционального” подхода. Fluent API

Теперь рассмотрим виртуальные потоки, которые появились в Java 21. Один платформенный поток Java может работать со множеством клиентов одновременно. По сути виртуальный поток это объект класса, который выполняется на базе платформенного потока, который в свою очередь является фактически потоком ОС.

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

Для работы с виртуальными потоками в SpingBoot достаточно включить одну проперти.

Примеры: jvm-digging/virtual-thread at master · petrelevich/jvm-digging · GitHub

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

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

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

Сравнение производительности. Генератор нагрузки: https://github.com/rakyll/hey

/hey -n=1000000 -C=300
  • 300 клиентов отправляют 1000000 запросов
  • Ethernet 1000 Mb/s
  • Запускаем в докере: 256 Mb, 1 cpu.
  • Garbage Collector: G1
  • Прогрев: два запуска
  • Измерений: 7
  • Стандартное отклонение: 3,8; 3,7; 2,6

Прирост производительности: 200% Virtual Thread по сравнению с платформенными потоками, а если переключиться на Webflux, то мы получим поверх еще 30%.

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

Причины

Почему Webflux производительней виртуальных потоков?

  • Может быть, где-то в коде есть synchronized? События jdk.VirtualThreadPinned не фиксируются
  • Замедление, наиболее вероятно, связано с переключением на платформенные потоки. JMC показывает множество событий: jdk.VirtualThreadStart, jdk.VirtualThreadEnd. При этом их длительность 0 (WTF?).

Дополнительные материалы


Мета информация

Область:: 00 Источники
Родитель::
Источник::
Создана:: 2024-10-02
Автор::

Дополнительные материалы

Дочерние заметки