9.9 KiB
aliases | tags | date | zero-link | parents | linked | ||
---|---|---|---|---|---|---|---|
|
2024-10-02 |
Организатор:: ../../meta/organizations/Т-Банк Конференция:: ../conference/Конференция. JVM Day 2024 Автор:: ../../meta/people/Сергей Петрелевич Ссылка:: Могут ли Virtual threads заменить Webflux? — Сергей Петрелевич, Squad - YouTube
О чем доклад: Автор пытается понять есть ли место реактивной парадигме в современной Java, после выхода ../../dev/java/Java Virtual Threads. Для этого он проводит нагрузочное тестирование и сравнивает результаты.
Тезисы
- Прикладным разработчикам удобнее работать с абстракциями высшего порядка (Spring WebFlux, Quarkus Reactive).
- Реактивный подход остается актуальным в некоторых задачах. Архитектору как и прежде необходимо выбирать подходящий инструмент для конкретной задачи.
- Виртуальные потоки могут дать существенный прирост (в 2 раза) производительности существующему приложению.
- Виртуальные потоки легко включить, от разработчика не требуется переписывать существующий код.
- Реактивный подход (Spring WebFlux) позволит дать максимальный прирост производительности (в 3.8 раза), но за это придется заплатить.
- ../../../../knowledge/dev/Реактивное программирование требует от разработчика изучение новой парадигмы и новых подходов: "функциональный" стиль разработки (Fluent API).
- Виртуальные потоки могут дать существенный прирост (в 2 раза) производительности существующему приложению.
Конспект
Автор считает, что Java не самый эффективный язык программирования с точки зрения потребления ресурсов
Имеется куча вариантов оптимизации, которые автор предлагает рассмотреть. Рассматривать начинаем с двух концепций
- ../../dev/architecture/Один клиент — один поток
- С таким подходов в Java быстро доходим до пределов количества потоков, которые возможно создать
- Применим, если нагрузка на систему не большая
- ../../dev/architecture/Много клиентов — один поток
- Кажется, что это то что надо, но это не всегда так
Автор рассматривает ../../dev/architecture/Event Loop. Реализация в Java: NIO Selector.
Можно работать напрямую с NIO, но прикладным разработчикам удобнее работать с Netty, который позволяет работать с более высокоуровневыми абстракциям, при этом сохраняя все преимущества NIO. Но есть еще более высокоуровневая абстракция поверх Netty.
NIO посылает события Netty их преобразовывает в более удобный вид. Далее можно сделать ../../../../_inbox/Callback, на основе этого работает Vert.x. Второй подход это использовать реактивный API: Reactor Netty. Именно этот подход автор и будет рассматривать.
Можно реализовывать свои приложения сразу на Reactor Netty, но еще удобнее использовать Spring Webflux. Это реактивный функциональный (позволяет разрабатывать в функциональном стиле) http-сервер, который эффективно использует ресурсы.
Пример "функционального" подхода. Fluent API !
Теперь рассмотрим ../../dev/java/Java Virtual Threads, которые появились в Java 21. Один платформенный поток Java может работать со множеством клиентов одновременно. По сути виртуальный поток это объект класса, который выполняется на базе платформенного потока, который в свою очередь является фактически ../../dev/fundamental/Поток процесса ОС.
Виртуальный поток помогает с операциями, где есть ../../dev/architecture/Блокирующий вызов, где нужно "подождать". В таком случае ожидание практически ничего не стоит, так как виртуальный поток на это время блокируется и уступает платформенный поток другому виртуальному потоку. Но если вам нужно что-то считать, если у вас какие-то тяжелые 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.
- ../../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?).
Дополнительные материалы
Мета информация
Область:: Родитель:: Источник:: Создана:: 2024-10-02 Автор::