NIOとReactorモデルの関係
NIO はノンブロッキング IO であり、Reactor は NIO に基づく設計パターンです。NIO は、NIO を使用して実装されたモデル、アイデアです。Reactor モデルの具体的な設計を見てみましょう。
Single Reactor シングルスレッドモード
- ブロッキング オブジェクトを介して複数の接続要求を監視することが可能です。
- Reactor オブジェクトは、select を介してクライアント要求イベントをリッスンし、dispatch を介してそれらを配布します。
- リンク リクエストの場合、Acceptor はリンク リクエストを受け入れて処理し、リンクが完了した後にさまざまなイベントを処理する Handler オブジェクトを作成します。
- リンク要求でない場合は、Reactor がディスパッチし、リンクに対応する Handler を呼び出すことによって処理されます。
- Handler は、Read->business processing->send の完全なビジネス プロセスを完了します。
短所:
ハンドラーの 1 つがブロックされると、他のすべてのクライアント ハンドラーが実行されなくなります。さらに深刻なことに、ハンドラーがブロックされると、サービス全体が新しいクライアント リクエストを受信できなくなります (アクセプターもブロックされるため)。マルチコア リソースを十分に活用できません。
スレッドが過負荷になると、処理速度が遅くなり、多数のクライアント接続がタイムアウトになり、タイムアウト後に頻繁に再送信されるため、NIO スレッドの負荷が増加し、最終的には大量のメッセージ バックログと処理タイムアウトが発生し、システム パフォーマンスのボトルネックになります。
NIO スレッドが誤って暴走したり、無限ループに入ったりすると、システム全体の通信モジュールが使用できなくなり、外部メッセージを受信および処理できなくなり、ノード障害が発生します。
Single Reactor マルチスレッド モード
ワーカー スレッド プールが追加され、非 I/O 操作が実行のために Reactor スレッドからワーカー スレッド プールに移動されます。これにより、Reactor スレッドの I/O 応答が改善され、時間のかかるビジネス ロジックが原因で後続の I/O 要求の処理が遅延することはありません。主な目的は、ビジネス ロジックの処理を個別のスレッドに分離して実行し、ビジネス ロジックの処理が I/O 操作の効率に影響を与えないようにすることです。
- Reactor オブジェクトは select を介してクライアント リクエスト イベントをリッスンし、イベントを受け取った後、dispatch を介してそれを配布します。
- リンク リクエストの場合、Acceptor はリンク リクエストを受け入れて処理し、リンクが完了した後にさまざまなイベントを処理する Handler オブジェクトを作成します。
- リンク要求でない場合は、Reactor がディスパッチし、リンクに対応する Handler を呼び出すことによって処理されます。
- Handler は特定の業務処理を行わずにイベント応答のみを担当
- データは read によって read された後、処理のためにワーカー スレッド プールに分散され、処理が完了すると Handler に返されます. Handler がそれを受け取ると、send によって結果をクライアントに返します
マスター/スレーブ Reactor マルチスレッド
Reactor スレッド プール内の各 Reactor スレッドには、独自のセレクター、スレッド、ディスパッチ イベント ループ ロジックがあります
。mainReactor は 1 つしか存在できませんが、通常は複数の subReactor があります。mainReactor スレッドは主に、クライアントからの接続要求を受け取り、受け取った SocketChannel を subReactor に渡し、subReactor がクライアントとの通信を完了します。
- Reactor メイン スレッドの MainReactor オブジェクトは、select を介してリンク イベントをリッスンし、Acceptor を介してそれらを処理します。
- Acceptor がリンク イベントを処理した後、MainReactor はリンクを SubReactor に割り当てます。
- SubReactor はリッスン用のキューにリンクを追加し、イベント処理用の Handler を作成します
- 新しいイベントが発生すると、SubReactor は対応する Handler を呼び出して処理します
- Handler は read によってデータを読み取り、それをワーカー スレッド プールに分散して処理し、処理が完了するとそれを Handler に返します. Handler がデータを受け取ると、結果を send によってクライアントに返します
- Reactor メインスレッドは複数の Reactor サブスレッドに対応可能
リアクターモデルとオブザーバーモデルの違い
オブザーバー モードはパブリッシュ/サブスクライブ モードとも呼ばれ、オブジェクトの状態に応じて主に複数のオブジェクトに適用され、オブジェクトの状態が変化すると、他の依存オブジェクトに更新が通知されます。これは 1 対多の関係です。もちろん、
従属オブジェクトが 1 つしかない場合も、特別な 1 対 1 の関係です。通常、オブザーバー モードはメッセージ イベント処理に適しています.
リスナーがイベントをリッスンすると、イベント ハンドラーにイベントを処理するように通知します (これは、
リアクターおよびプロクター モード) .
リアクター モード、つまりリアクター モードは、効率的な非同期 IO モードであり、コールバックが特徴で、IO が完了すると、対応する関数が呼び出されて処理されます。このモードは実際には非同期ではありませんが、非同期思考を使用します. IO イベントがトリガーされると、アプリケーションは IO 処理を実行するように通知されます. パターン自体は、システムの非同期 IO 関数を呼び出しません。
リアクター パターンはオブザーバー パターンに少し似ています。ただし、Observer パターンは単一のイベント ソースに関連付けられていますが、Reactor パターンは複数のイベント ソースに関連付けられています。サブジェクトが変更されると、すべての扶養家族に通知されます。
適用シナリオ
Reactor モデルは通常、ネットワーク モデルで使用され、接続、読み取り操作、書き込み操作を高い並行性で実行するサービスで I/O イベントを実行します。たとえば、redis と nginx では、Reactor モデルを使用して、クライアント接続サービスのネットワーク モデルを実現し、データを読み書きします。自社でサービスを提供し、多数のクライアントが提供するサービスで I/O 操作を実行する場合、I/O 多重化に Reactor モデルを使用してサービスの I/O パフォーマンスを向上させることを検討できます。