--- aliases: tags: - maturity/🌱 - type/source/lecture date: 2024-10-02 zero-link: parents: linked: --- **Организатор**:: [[../../meta/organizations/Т-Банк|Т-Банк]] **Конференция**:: [[../conference/Конференция. JVM Day 2024|Конференция. JVM Day 2024]] **Автор**:: [[../../meta/people/Сергей Петрелевич|Сергей Петрелевич]] **Ссылка::** [Могут ли Virtual threads заменить Webflux? — Сергей Петрелевич, Squad - YouTube](https://www.youtube.com/watch?v=SOvzg-uoVco) *** ![Могут ли Virtual threads заменить Webflux? — Сергей Петрелевич, Squad - YouTube](https://www.youtube.com/watch?v=SOvzg-uoVco) *** **О чем доклад:** Автор пытается понять есть ли место реактивной парадигме в современной Java, после выхода [[../../dev/java/Java Virtual Threads|виртуальных потоков]]. Для этого он проводит нагрузочное тестирование и сравнивает результаты. ## Тезисы - Прикладным разработчикам удобнее работать с абстракциями высшего порядка (Spring WebFlux, Quarkus Reactive). - Реактивный подход остается актуальным в некоторых задачах. Архитектору как и прежде необходимо выбирать подходящий инструмент для конкретной задачи. - Виртуальные потоки могут дать существенный прирост (в 2 раза) производительности существующему приложению. - Виртуальные потоки легко включить, от разработчика не требуется переписывать существующий код. - Реактивный подход (Spring WebFlux) позволит дать максимальный прирост производительности (в 3.8 раза), но за это придется заплатить. - [[../../../../knowledge/dev/Реактивное программирование|Реактивное программирование]] требует от разработчика изучение новой парадигмы и новых подходов: "функциональный" стиль разработки (Fluent API). *** ## Конспект Автор считает, что Java не самый эффективный язык программирования с точки зрения потребления ресурсов Имеется куча вариантов оптимизации, которые автор предлагает рассмотреть. Рассматривать начинаем с двух концепций - [[../../dev/architecture/Один клиент — один поток|Один клиент — один поток]] - С таким подходов в Java быстро доходим до пределов количества потоков, которые возможно создать - Применим, если нагрузка на систему не большая - [[../../dev/architecture/Много клиентов — один поток|Много клиентов — один поток]] - Кажется, что это то что надо, но это не всегда так Автор рассматривает [[../../dev/architecture/Event Loop|Event Loop]]. Реализация в Java: NIO Selector. Можно работать напрямую с NIO, но прикладным разработчикам удобнее работать с Netty, который позволяет работать с более высокоуровневыми абстракциям, при этом сохраняя все преимущества NIO. Но есть еще более высокоуровневая абстракция поверх Netty. NIO посылает события Netty их преобразовывает в более удобный вид. Далее можно сделать [[../../../../_inbox/Callback|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](https://github.com/petrelevich/jvm-digging/tree/master/virtual-thread) Итого, Sping WebFlux позволял нам обрабатывать множество запросов на одном потоке. И виртуальные потоки нам позволяют делать по сути то же самое. При этом не нужно разбираться в реактивной парадигме разработки. Тогда зачем нам WebFlux? ## Сравнение производительности Для этого сравним два подхода на примере [небольшого приложения](https://github.com/petrelevich/jvm-digging/tree/master/virtual-thread), которое будет принимать [[../../dev/system-design/RESTful|REST]] запросы и отправлять их в кафку, после чего отвечать клиенту что сообщение доставлено. ![[../../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|Garbage Collector]]: G1 - Прогрев: два запуска - Измерений: 7 - Стандартное отклонение: 3,8; 3,7; 2,6 ![[../../meta/files/images/Pasted image 20241003084259.png|500]] Прирост производительности: 200% Virtual Thread по сравнению с платформенными потоками, а если переключиться на Webflux, то мы получим **поверх** еще 30%. Переход на Virtual Thread максимально прост, при этом максимально эффективен. Поэтому особого смысла переписывать старые приложения на рекативной подход нет, проще включить виртуальные потоки. ### Причины Почему Webflux производительней виртуальных потоков? - Может быть, где-то в коде есть synchronized? События jdk.VirtualThreadPinned не фиксируются - Замедление, наиболее вероятно, связано с переключением на платформенные потоки. JMC показывает множество событий: jdk.VirtualThreadStart, jdk.VirtualThreadEnd. При этом их длительность 0 (WTF?). ## Дополнительные материалы - *** ## Мета информация **Область**:: [[../00 Источники|00 Источники]] **Родитель**:: **Источник**:: **Создана**:: [[2024-10-02]] **Автор**:: ### Дополнительные материалы - ### Дочерние заметки