digital-garden/source/lecture/Доклад. Могут ли Virtual threads заменить Webflux.md

10 KiB
Raw Permalink Blame History

aliases tags date zero-link parents linked
maturity/🌱
type/source/lecture
2024-10-02

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


Могут ли Virtual threads заменить Webflux? — Сергей Петрелевич, Squad - YouTube


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

Тезисы

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

Конспект

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

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

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

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

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

!../../meta/files/images/Pasted image 20241003080932.png

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

Пример "функционального" подхода. Fluent API !../../meta/files/images/Pasted image 20241003081345.png

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

!../../../../garden/ru/meta/files/images/Pasted image 20241003081726.png

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

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

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

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

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

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

!../../meta/files/images/Pasted image 20241003083724.png

!../../meta/files/images/Pasted image 20241003083758.png

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

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

!../../meta/files/images/Pasted image 20241003084259.png

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

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

Причины

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

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

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


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

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

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

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