今朝、Spring Boot 仮想スレッドと Webflux のパフォーマンス比較に関する記事を見て、かなり良いと思いました。内容が長いので翻訳は省略し、すぐに読んでいただけるよう記事の核となる内容を紹介することに重点を置きます。
テストシナリオ
著者は、可能な限り現実に近いシナリオを使用しています。
- 認可ヘッダーからJWTを抽出する
- JWT を検証し、JWT からユーザーの電子メールを抽出します。
- ユーザーの電子メールを使用して MySQL でクエリを実行します
- ユーザーレコードを返す
試験技術
ここで比較する 2 つの主要な技術点は次のとおりです。
- 仮想スレッドを使用した Spring Boot: これは、従来の物理スレッド上で実行される Spring Boot アプリケーションではなく、仮想スレッド上で実行されます。これらの軽量スレッドにより、高スループットの同時アプリケーションの開発、保守、デバッグの複雑なタスクが簡素化されます。仮想スレッドは依然として基礎となるオペレーティング システム スレッド上で実行されますが、効率が大幅に向上します。仮想スレッドでブロッキング I/O 操作が発生すると、Java ランタイムは仮想スレッドを一時的に停止し、関連するオペレーティング システム スレッドを解放して他の仮想スレッドにサービスを提供できるようにします。この洗練されたソリューションはリソース割り当てを最適化し、アプリケーション全体の応答性を向上させます。
- Spring Boot Webflux: Spring Boot WebFlux は、Project Reactor ライブラリを利用してノンブロッキングのイベント駆動型プログラミングを実装する、Spring エコシステムのリアクティブ プログラミング フレームワークです。したがって、高い同時実行性と低い遅延を必要とするアプリケーションに特に適しています。リアクティブなアプローチに依存するため、開発者は、さまざまなデータ ソースや通信プロトコルと統合する柔軟性を備えながら、多数の同時リクエストを効率的に処理できます。
Webflux と仮想スレッドのどちらも、プログラムに高い同時実行機能を提供するように設計されています。では、どちらが優れているでしょうか? 具体的なテストを見てみましょう。
テスト環境
動作環境とツール
- 16G メモリを搭載した MacBook Pro M1
- Java 20
- スプリングブート 3.1.3
- プレビュー モードを有効にして仮想スレッドの機能を活用します
- 依存するサードパーティ ライブラリ: jjwt、mysql-connector-java
- テストツール: ボンバルディア
- データベース: MySQL
データの準備
- Bombardier で 100,000 個の JWT のリストを準備し、その中からJWT をランダムに選択し、HTTP リクエストの認可情報に追加します。
- MySQL に次のテーブル構造を持つ users テーブルを作成します。
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)
- users テーブルに 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
User
エンティティ (ここでは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"));
}
}
試験結果
次がハイライトです。著者は 500 万のリクエストで両方の技術ソリューションをテストしました。評価されたさまざまな同時接続レベルには、50、100、および 300 が含まれます。
具体的な結果は以下の通りです。
最後に、著者は、仮想スレッドを備えた Spring Boot よりも Spring Boot Webflux の方が優れていると結論付けました。
仮想スレッドの導入はすでに使われている Webflux ほどではないのでしょうか?関連する調査を行ったことがありますか? もしそうなら、メッセージエリアでお気軽にチャットしてください〜
勉強中に困難に遭遇したらどうしますか?私たちの超高品質なSpring テクノロジー交換グループに参加して、より良い学習と進歩のための交換やディスカッションに参加できます。Spring Boot チュートリアルの詳細については、ここをクリックしてください。、サポートのために収集して転送することを歓迎します。このコンテンツの原文に興味がある場合は、ここをクリックして表示することもできます。
JetBrains が Rust IDE をリリース: RustRover Java 21 / JDK 21 (LTS) GA 中国には非常に多くの Java 開発者がいることから、エコロジーレベルのアプリケーション開発フレームワーク .NET 8 が誕生するはずであり、パフォーマンスは大幅に向上しており、 をはるかに上回っています。 NET 7. PostgreSQL 16 は、Rust チームの元メンバーによってリリースされました。大変遺憾ながら名前をキャンセルしていただきました。 昨日、フロントエンドの Nue JS の削除を完了しました。作者は、新しい Web エコシステムを作成すると言っています。 NetEase Fuxi、「バグにより人事部から脅迫された」従業員の死亡に対応 任正非氏:私たちは第4次産業革命を迎えようとしている、Appleはファーウェイの師であるVercelの新製品「v0」:UIインターフェースコードをベースに生成文章私の公開アカウント、プログラマー DD をフォローしてください。最先端の業界ニュースを誰よりも早く理解し、詳細な技術情報を共有し、質の高い学習リソースを入手します