Сравнение производительности виртуальных потоков Spring Boot и Webflux при проверке JWT и запросе MySQL

Сегодня утром я увидел статью о сравнении производительности виртуальных потоков Spring Boot и Webflux и подумал, что она довольно хороша. Содержание длинное, поэтому я не буду его переводить. Вместо этого я сосредоточусь на том, чтобы познакомить вас с основным содержанием этой статьи, чтобы вы могли ее быстро прочитать.

сценарии тестирования

Автор использует сценарий, максимально приближенный к реальности:

  1. Извлечь JWT из заголовка авторизации
  2. Проверьте JWT и извлеките из него адрес электронной почты пользователя.
  3. Используйте электронную почту пользователя для выполнения запроса в MySQL.
  4. Вернуть запись пользователя

технология тестирования

Здесь необходимо сравнить два основных технических момента:

  1. Spring Boot с виртуальными потоками. Это приложение Spring Boot, работающее не в традиционных физических потоках, а в виртуальных потоках. Эти легкие потоки упрощают сложные задачи разработки, обслуживания и отладки параллельных приложений с высокой пропускной способностью. Хотя виртуальные потоки по-прежнему выполняются в потоках базовой операционной системы, они значительно повышают эффективность. Когда виртуальный поток сталкивается с блокирующей операцией ввода-вывода, среда выполнения Java временно приостанавливает ее, освобождая соответствующий поток операционной системы для обслуживания других виртуальных потоков. Это элегантное решение оптимизирует распределение ресурсов и повышает общую скорость реагирования приложений.
  2. Spring Boot Webflux: Spring Boot WebFlux — это среда реактивного программирования в экосистеме Spring, которая использует библиотеку Project Reactor для реализации неблокирующего, управляемого событиями программирования. Поэтому он особенно подходит для приложений, которым требуется высокий уровень параллелизма и низкая задержка. Опираясь на реактивный подход, он позволяет разработчикам эффективно обрабатывать большое количество одновременных запросов, сохраняя при этом гибкость интеграции с различными источниками данных и протоколами связи.

Будь то Webflux или виртуальные потоки, оба они предназначены для обеспечения высокой параллельной работы программ, так кто же лучше? Давайте посмотрим на конкретные тесты.

тестовая среда

Операционная среда и инструменты

  • MacBook Pro M1 с памятью 16 ГБ.
  • Ява 20
  • Весенняя загрузка 3.1.3
  • Включите режим предварительного просмотра, чтобы получить всю мощь виртуальных потоков.
  • Зависимые сторонние библиотеки: jjwt, mysql-connector-java.
  • Инструмент тестирования: Bombardier
  • База данных: MySQL

подготовка данных

  • Подготовьте список из 100 000 JWT в Bombardier, чтобы случайным образом выбрать из них JWT и поместить их в информацию авторизации HTTP-запроса.
  • Создайте таблицу пользователей в MySQL со следующей структурой таблицы:
mysql> desc users;
+--------+--------------+------+-----+---------+-------+
| Field  | Type         | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| email  | varchar(255) | NO   | PRI | NULL    |       |
| first  | varchar(255) | YES  |     | NULL    |       |
| last   | varchar(255) | YES  |     | NULL    |       |
| city   | varchar(255) | YES  |     | NULL    |       |
| county | varchar(255) | YES  |     | NULL    |       |
| age    | int          | YES  |     | NULL    |       |
+--------+--------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
  • Подготовьте 100 000 пользовательских данных для таблицы пользователей.

тестовый код

Программа Spring Boot с виртуальными потоками

application.propertiesКонфигурационный файл:

server.port=3000

spring.datasource.url= jdbc:mysql://localhost:3306/testdb?useSSL=false
spring.datasource.username= testuser
spring.datasource.password= testpwd
spring.jpa.hibernate.ddl-auto= update
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

UserКласс сущности (чтобы сделать статью более краткой, DD опускает здесь геттер и сеттер):

@Entity
@Table(name = "users")
public class User {
  @Id
  private String email;

  private String first;

  private String last;

  private String city;

  private String county;

  private int age;

}

Основной класс приложения:

@SpringBootApplication
public class UserApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }

    @Bean
    public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
        return protocolHandler -> {
            protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
        };
    }
}

Обеспечивает операции CRUD UserRepository:

import org.springframework.data.repository.CrudRepository;
import com.example.demo.User;

public interface UserRepository extends CrudRepository<User, String> {

}

Классы , предоставляющие интерфейсы API UserController:

@RestController
public class UserController {

    @Autowired
    UserRepository userRepository;

    private SignatureAlgorithm sa = SignatureAlgorithm.HS256;
    private String jwtSecret = System.getenv("JWT_SECRET");

    @GetMapping("/")
    public User handleRequest(@RequestHeader(HttpHeaders.AUTHORIZATION) String authHdr) {
        String jwtString = authHdr.replace("Bearer","");
        Claims claims = Jwts.parser()
            .setSigningKey(jwtSecret.getBytes())
            .parseClaimsJws(jwtString).getBody();

        Optional<User> user = userRepository.findById((String)claims.get("email"));
        return user.get();
    }
}

Программа Spring Boot Webflux

application.propertiesКонфигурационный файл:

server.port=3000

spring.r2dbc.url=r2dbc:mysql://localhost:3306/testdb
spring.r2dbc.username=dbser
spring.r2dbc.password=dbpwd

UserEntity (здесь DD также опускает конструктор, геттер и сеттер):

public class User {

  @Id
  private String email;

  private String first;

  private String last;

  private String city;

  private String county;

  private int age;

  // 省略了构造函数、getter、setter
  
}

Основной класс приложения:

@EnableWebFlux
@SpringBootApplication
public class UserApplication {

  public static void main(String[] args) {
    SpringApplication.run(UserApplication.class, args);
  }

}

Обеспечивает операции CRUD UserRepository:

public interface UserRepository extends R2dbcRepository<User, String> {

}

Обеспечивает проверку бизнес-класса пользователя по ID UserService:

@Service
public class UserService {

  @Autowired
  UserRepository userRepository;

  public Mono<User> findById(String id) {
    return userRepository.findById(id);
  }
}

Классы , предоставляющие интерфейсы API UserController:

@RestController
@RequestMapping("/")
public class UserController {

  @Autowired
  UserService userService;

  private SignatureAlgorithm sa = SignatureAlgorithm.HS256;
  private String jwtSecret = System.getenv("JWT_SECRET");

  @GetMapping("/")
  @ResponseStatus(HttpStatus.OK)
  public Mono<User> getUserById(@RequestHeader(HttpHeaders.AUTHORIZATION) String authHdr) {
    String jwtString = authHdr.replace("Bearer","");
    Claims claims = Jwts.parser()
        .setSigningKey(jwtSecret.getBytes())
        .parseClaimsJws(jwtString).getBody();
    return userService.findById((String)claims.get("email"));
  }

}

Результаты теста

Далее следует самое интересное: автор протестировал оба технических решения с 5 миллионами запросов. Оцениваемые различные уровни одновременного подключения включают: 50, 100 и 300.

Конкретные результаты заключаются в следующем:

50 одновременных подключений

100 одновременных подключений

300 одновременных подключений

Наконец, автор пришел к выводу, что Spring Boot Webflux лучше, чем Spring Boot с виртуальными потоками.

Кажется, внедрение виртуальных потоков не так хорошо, как уже используемый Webflux? Интересно, проводили ли вы какие-либо соответствующие исследования? Если да, пожалуйста, напишите нам в области сообщений~

Что делать, если вы столкнулись с трудностями во время учебы? Вы можете присоединиться к нашей высококачественной группе обмена технологиями Spring , чтобы участвовать в обменах и обсуждениях для лучшего обучения и прогресса! Чтобы увидеть больше руководств по Spring Boot, нажмите здесь! Добро пожаловать, собирайте и пересылайте на поддержку! Если вас интересует исходный текст этого контента, вы также можете нажать здесь, чтобы просмотреть его .

Добро пожаловать на мою публичную учетную запись: Programmer DD. Будьте первым, кто узнает о последних новостях отрасли, делится подробной технической информацией и получает высококачественные учебные ресурсы.

JetBrains выпускает Rust IDE: RustRover Java 21 / JDK 21 (LTS) GA Учитывая такое количество разработчиков Java в Китае, должна появиться среда разработки приложений экологического уровня .NET 8. Производительность значительно улучшена и намного опережает .NET 8. NET 7. PostgreSQL 16 выпущен бывшим членом команды Rust, о котором я глубоко сожалею и попросил удалить мое имя. Вчера я завершил удаление Nue JS из внешнего интерфейса. Автор сказал, что я создам новую веб-экосистему. NetEase Fuxi отреагировала на смерть сотрудника, которому «угрожал отдел кадров из-за ОШИБКИ».Жэнь Чжэнфэй: Мы приближаемся к четвертой промышленной революции, Apple — учитель Huawei, новый продукт Vercel «v0»: генерировать код интерфейса пользовательского интерфейса на основе текст
{{o.name}}
{{м.имя}}

рекомендация

отmy.oschina.net/didispace/blog/10111993