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

107 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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 раза), но за это придется заплатить.
- [[../../dev/architecture/Реактивное программирование|Реактивное программирование]] требует от разработчика изучение новой парадигмы и новых подходов: "функциональный" стиль разработки (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]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->