🌊 Spring Framework 講座【第48回】ノンブロッキングの極意!〜リアクティブプログラミングの基本(Reactor)〜

docs

前回、メッセージキューを使ったアプリケーション間の非同期連携を学びました。これはシステム間の連携を効率化する技術でした。

今回は、単一のアプリケーション内で、特にI/O処理(ネットワーク通信やDBアクセス)における性能を限界まで引き出すための設計思想、**リアクティブプログラミング(Reactive Programming)**の基本を学びます。

Spring Frameworkでは、このリアクティブプログラミングを実現するために Spring WebFluxProject Reactor が中核を担っています。


1. なぜリアクティブプログラミングが必要か?

これまでのSpring MVCで扱ってきた処理は、ほとんどが**同期処理(ブロッキング)**でした。

  • ブロッキング(同期I/O): 外部APIへのリクエストやDBアクセスが発生すると、その処理が完了して結果が返ってくるまで、**アプリケーションのスレッドは待機(ブロック)**します。スレッドがブロックされている間、そのスレッドは他のリクエストを処理できず、多数の同時接続に弱くなります。

**リアクティブプログラミング(ノンブロッキングI/O)は、スレッドを待機させません。I/O処理中にスレッドがブロックされる代わりに、そのスレッドは別のリクエスト処理に切り替わります。I/O処理が完了したら、「データが利用可能になった」という通知(イベント)**が届き、処理を再開します。

  • メリット: スレッドの利用効率が極限まで高まり、少数のスレッドで大量の同時接続を処理できるようになります。

2. リアクティブプログラミングの核:Project Reactor

Spring WebFlux(リアクティブなWebフレームワーク)の基盤となっているのが、Project Reactorというライブラリです。Reactorは、非同期で発生するデータを扱うための2つの主要な型を提供します。

2-1. Mono(モノ)

  • 意味: 0件または1件のデータ、またはエラーを非同期的に処理するコンテナ。
  • 用途: 単一のオブジェクトや、処理の完了通知(Void)を扱う場合に主に使用されます(例:単一のユーザーデータ取得、POSTリクエストのレスポンス)。

2-2. Flux(フラックス)

  • 意味: 0件以上の複数件のデータストリーム、またはエラーを非同期的に処理するコンテナ。
  • 用途: リストやコレクション、継続的なストリームデータ(例:複数のユーザーリスト、WebSocketからの継続的なデータ)を扱う場合に主に使用されます。

2-3. リアクティブの基本操作

MonoやFluxは、データを**ストリーム(流れ)**として扱い、メソッドチェーンで処理を繋げていくのが特徴です。

Java

import reactor.core.publisher.Flux;

public void reactiveExample() {
    // 1. Fluxの生成 (データの発行元/Publisher)
    Flux<String> names = Flux.just("Alice", "Bob", "Charlie")
        
        // 2. 処理の定義 (データが流れてきたら実行される操作)
        .map(name -> name.toUpperCase()) // 全て大文字に変換
        .filter(name -> name.startsWith("A")) // 'A'で始まるものだけ残す
        
        // 3. 購読(Subscription/Consumer)
        // 実際にデータが流れ始めるのは、subscribe()が呼ばれた後
        .subscribe(
            name -> System.out.println("受信データ: " + name), // データ受信時の処理
            error -> System.err.println("エラーが発生: " + error), // エラー発生時の処理
            () -> System.out.println("ストリーム完了") // 完了時の処理
        );
}

3. Spring WebFluxとの関係

第33回で学んだ WebClient の戻り値が MonoFlux であったのは、WebClientがこのリアクティブな仕組み(Project Reactor)の上に構築されているからです。

Spring WebFlux環境では、Controllerの戻り値もMonoやFluxになります。

Java

// Spring WebFlux環境のController
@RestController
public class ItemController {
    
    // Mono<Item>を返す。クライアントへのレスポンスは、データが到着次第送信される(ノンブロッキング)
    public Mono<Item> getItemDetail(Long id) {
        // ... (Repositoryからノンブロッキングでデータを取得する処理)
    }
}

Spring WebFluxは、従来のサーブレットコンテナ(Tomcatなど)ではなく、NettyなどのノンブロッキングI/Oに特化したサーバーをデフォルトで使用します。

4. バックプレッシャー(Backpressure)

リアクティブプログラミングの重要な概念にバックプレッシャーがあります。

  • 問題点: データの発行元(プロデューサー)が、データの処理速度が追いつかないほど大量のデータを送りつけた場合、処理側(コンシューマー)がパンクしてしまう可能性があります。
  • バックプレッシャー: コンシューマーがプロデューサーに対して「これ以上送らないで。あとN個だけなら処理できるよ」と信号を送り、データの流量を調整する仕組みです。

これにより、システムが過負荷によって停止するのを防ぎ、処理能力を超えないように安定した動作が保証されます。

✅ 本日のまとめ

  • リアクティブプログラミングは、I/O処理中にスレッドを待機させないノンブロッキングI/Oを実現し、少数のスレッドで大量の同時リクエストを処理する。
  • Springのリアクティブ基盤は Project Reactor であり、データを扱う主要な型としてMono(0〜1件)とFlux(0件以上)がある。
  • MonoとFluxは、メソッドチェーンによって非同期の処理フローを定義し、**subscribe()**が呼ばれるまでデータは流れ始めない(怠惰な実行)。
  • バックプレッシャーは、データの流れの速度をコンシューマー側が制御する仕組みであり、システムの安定性を保つ。

🔔 次回予告

これで、Javaのリアクティブプログラミングの核心に触れることができました。

次回は、全50回講座の総仕上げとして、これまで学んだ知識を統合し、Spring Bootアプリケーションの最終的な性能チューニングと改善に関する総まとめを行います。

次回:【第49回】総仕上げ!〜Spring Bootの最終性能チューニングと改善ポイント〜 にご期待ください!

コメント

タイトルとURLをコピーしました