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

107 lines
10 KiB
Markdown
Raw Normal View History

---
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), которое будет принимать 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?).
## Дополнительные материалы
-
***
## Мета информация
2024-10-04 01:19:00 +03:00
**Область**:: [[../00 Источники|00 Источники]]
**Родитель**::
**Источник**::
**Создана**:: [[2024-10-02]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->