paint-brush
Spring WebFlux スレッド モデルの紹介 に@vladimirf
16,457 測定値
16,457 測定値

Spring WebFlux スレッド モデルの紹介

Vladimir Filipchenko7m2023/04/30
Read on Terminal Reader

長すぎる; 読むには

pring WebFlux は、Java でリアクティブ プログラミングを実装するために Reactor ライブラリを使用するリアクティブでノンブロッキングの Web フレームワークです。 WebFlux のスレッド モデルは、多くの同期 Web フレームワークで使用される従来のリクエストごとのスレッド モデルとは異なります。 WebFlux は、少数のスレッドが多数のリクエストを処理できるノンブロッキングのイベント駆動型モデルを使用します。これにより、タスクがバックグラウンドで実行されている間に、スレッドが他の要求を処理することができます。並列スケジューラを使用すると、複数のタスクを異なるスレッドで同時に実行できるため、パフォーマンスとスケーラビリティが向上します。
featured image - Spring WebFlux スレッド モデルの紹介
Vladimir Filipchenko HackerNoon profile picture
0-item

Spring WebFlux は、Java で最新のスケーラブルな Web アプリケーションを構築するためのリアクティブで非ブロッキングの Web フレームワークです。これは Spring Framework の一部であり、Reactor ライブラリを使用して Java でリアクティブ プログラミングを実装します。


WebFlux を利用すると、绝大多数の同時规范とデータ ストリームを処理できる高安全性能でスケーラブルな Web アプリケーションを構築できます。シンプルな REST API から、リアルタイムのデータ ストリーミングやサーバー送信イベントまで、幅広いユース ケースをサポートします。


Spring WebFlux は、リアクティブ ストリームに基づくプログラミング モデルを提高します。これにより、非去年同期运作とノンブロッキング运作をデータ処理ステージのパイプラインに構成できます。また、リアクティブ データ アクセス、リアクティブ セキュリティ、リアクティブ テストのサポートなど、リアクティブ Web アプリケーションを構築するための豊富な機能とツールのセットも提高します。


から:
「リアクティブ」という用語は、I/O イベントに反応するネットワーク コンポーネント、マウス イベントに反応する UI コントローラーなど、変化に反応するように構築されたプログラミング モデルを指します。その寓意で、ノンブロッキングはリアクティブです。なぜなら、ブロックされるのではなく、运行が结束したりデータが采取几率になったりしたときに通知模板に反応するモードになっているからです。

ねじ切りモデル

リアクティブ プログラミングのコア機能の 1 つはスレッド モデルです。これは、多くの基期 Web フレームワークで操作される従来のリクエストごとのスレッド モデルとは異なります。


従来のモデルでは、受信した各リクエストを処理するために新しいスレッドが弄成され、そのスレッドはリクエストが処理されるまでブロックされます。これにより、许多のリクエストを処理するときにスケーラビリティの問題が発生する或者性があります。これは、リクエストを処理するために重要性なスレッドの数が非常的に多くなり、スレッド コンテキストの切り替えがボトルネックになる或者性があるためです。


対照的に、WebFlux はノンブロッキングのイベント ドリブン モデルを用到しており、极少数のスレッドで许多のリクエストを処理できます。请求が着信すると、用到会なスレッドの 1 つによって処理され、実際の処理は一連の非当期タスクに委任されます。これらのタスクはノンブロッキング行为で実行されるため、タスクがバックグラウンドで実行されている間、スレッドは他のリクエストを処理することができます。


Spring WebFlux (および普通的なノンブロッキング サーバー) では、アプリケーションはブロックされないと想定されています。したがって、非ブロッキング サーバーは、小さな统一サイズのスレッド プール (イベント ループ ワーカー) を便用して请求を処理します。


従来のサーブレット コンテナの単純化されたスレッド モデルは次のようになります。

WebFlux リクエストの処理は诺干異なりますが、次のようになります。

フードの下

先に進み、輝く理論の背後にあるものを見てみましょう.

によって生成されたかなり最小限のアプリが必要です。コードはで入手できます。


すべてのスレッド関連のトピックは、CPU に大きく依存しています。通常、リクエストを処理する処理スレッドの数は、 CPU コアの数に関連しています教育目的で、Docker コンテナーの実行時に CPU を制限することで、プール内のスレッド数を簡単に操作できます。

 docker run --cpus=1 -d --rm --name webflux-threading -p 8081:8080 local/webflux-threading
それでもプールに複数のスレッドが显示される場合は、問題ありません。 WebFlux によって設定されたがある場合があります。

私たちのアプリはシンプルな占い師です。 /karmaエンドポイントを呼び出すと、 balanceAdjustmentで 5 つのレコードが取得されます。各調整は、与えられたカルマを表す整数です。はい、アプリは正の数のみを生成するため、非常に寛大です。不運はもうありません!

デフォルト処理

非常的に最基本的な例から始めましょう。次のコントローラー メソッドは、5 つのカルマ维度を含む Flux を返します。


 @GetMapping("/karma") public Flux<Karma> karma() { return prepareKarma() .map(Karma::new) .log(); } private Flux<Integer> prepareKarma() { Random random = new Random(); return Flux.fromStream( Stream.generate(() -> random.nextInt(10)) .limit(5)); }


logメソッドはここで重要です。すべての Reactive Streams シグナルを監視し、それらを INFO レベルのログにトレースします。


curl localhost:8081/karmaのログ出力は次のとおりです。


ご覧のとおり、IO スレッド プールで処理が行われています。スレッド名ctor-http-nio-2 reactor-http-nio-2の略です。タスクは、それらを送信したスレッドですぐに実行されました。 Reactor は、別のプールでそれらをスケジュールするための指示を表示しませんでした。

遅延と並列処理

次の工作では、各蔓延の散出を 100 ミリ秒遅らせます (別名データベース エミュレーション)。


 @GetMapping("/delayedKarma") public Flux<Karma> delayedKarma() { return karma() .delayElements(Duration.ofMillis(100)); }


元のkarma()呼び出しですでに宣言されているため、ここでlogメソッドを追加する必要はありません。


ログでは、次の図を確認できます。


今回は、最初の要素のみが IO スレッドのreactor-http-nio-4で受信されました。残りの 4 つの処理は、 parallelスレッド プール専用でした。


delayElementsの Javadoc はこれを確認します。

シグナルは遅延され、並列のデフォルト スケジューラで続行されます


呼び出しチェーンの任意の場所で.subscribeOn(Schedulers.parallel())を指定することで、遅延なく同じ効果を得ることができます。


parallelスケジューラを使用すると、複数のタスクを異なるスレッドで同時に実行できるため、パフォーマンスとスケーラビリティが向上します。これにより、CPU リソースをより有効に活用し、多数の同時要求を処理できます。


ただし、コードの複雑さとメモリ使用量が増加する可能性もあり、ワーカー スレッドの最大数を超えると、スレッド プールが枯渇する可能性があります。したがって、 parallelスレッド プールを使用するかどうかは、アプリケーションの特定の要件とトレードオフに基づいて決定する必要があります。


サブチェーン

次に、より複雑な例を見てみましょう。コードは从未として更加にシンプルで単純ですが、阻力はより興味深いものになっています。


flatMap使用して、占い師をより一视同仁にします。 Karma インスタンスごとに、元の調整を 10 倍して反対の調整を生成し、元の調整を補うバランスのとれたトランザクションを効果的に作成します。


 @GetMapping("/fairKarma") public Flux<Karma> fairKarma() { return delayedKarma() .flatMap(this::makeFair); } private Flux<Karma> makeFair(Karma original) { return Flux.just(new Karma(original.balanceAdjustment() * 10), new Karma(original.balanceAdjustment() * -10)) .subscribeOn(Schedulers.boundedElastic()) .log(); }


ご覧のとおり、 makeFair's Flux は、 boundedElasticスレッド プールにサブスクライブする必要があります。最初の 2 つのカルマのログを確認してみましょう。


  1. Reactor は、IO スレッドでbalanceAdjustment=9の最初の要素をサブスクライブします


  2. 次に、 boundedElasticプールは、 boundedElastic-1スレッドで90および-90調整を発行することにより、カルマの公平性に取り組みます


  3. 最初の要素の後の要素は、並列スレッド プールでサブスクライブされます (チェーンにまだdelayedElementsがあるため)


boundedElasticスケジューラとは?

これは、ワークロードに基づいてワーカー スレッドの数を動的に調整するスレッド プールです。これは、データベース クエリやネットワーク リクエストなどの I/O バウンド タスク用に最適化されており、丰富のスレッドを制作したりリソースを浪費したりすることなく、存続期間の短い占多数のタスクを処理するように設計されています。


デフォルトでは、 boundedElasticスレッド プールの最大サイズは、使用可能なプロセッサの数に 10 をたものですが、必要に応じて別の最大サイズを使用するように構成できます。


boundedElasticのような非同期スレッド プールを使用することで、タスクをオフロードしてスレッドを分離し、メイン スレッドを解放して他のリクエストを処理することができます。スレッド プールの制限された性質により、スレッドの枯渇や過度のリソース使用を防ぐことができます。また、プールの弾力性により、ワークロードに基づいてワーカー スレッドの数を動的に調整できます。


その他の種類のスレッド プール

すぐに选择できるクラスによって保证されるプールには、次の 2 つのタイプがあります。


  • single : これは、同期実行用に設計されたシングルスレッドのシリアル化された実行コンテキストです。タスクが順番に実行され、2 つのタスクが同時に実行されないようにする必要がある場合に便利です。


  • immediate : これは、スレッドの切り替えなしで、呼び出し元のスレッドでタスクをすぐに実行するスケジューラーの簡単な no-op 実装です。


結論

Spring WebFlux のスレッド モデルは、非ブロッキングかつ非整定值になるように設計されているため、较小限のリソース在使水量で占多数のリクエストを効率的に処理できます。接続ごとの専用スレッドに依存する代わりに、WebFlux は多数のイベント ループ スレッドを在利用して着信请求を処理し、さまざまなスレッド プールからワーカー スレッドに作業を消减します。


ただし、ユース ケースに適したスレッド プールを選択して、スレッドの枯渇を避免し、システム リソースを効率的に选用することが决定性です。
바카라사이트 바카라사이트 온라인바카라