1. Netty の概要
Netty は、以下に基づく高性能の非同期イベント駆動型 NIO フレームワークです。 JAVA NIO が提供する API 実装。 TCP、UDP、およびファイル転送のサポートを提供します。非同期 NIO フレームワークとして、Netty のすべての IO 操作は非同期でノンブロッキングです。Future-Listener メカニズムを通じて、ユーザーはアクティブまたは通知メカニズムを通じて簡単に IO 操作を取得できます。結果。現在、最も人気のある NIO フレームワークとして、Netty はインターネット分野、ビッグデータ分散コンピューティング、ゲーム業界、通信業界などで広く使用されています。業界でよく知られているオープンソース コンポーネントの一部も、Netty の NIO フレームワークに基づいて構築されています。
2. Netty スレッド モデル
JAVA NIO に関して言えば、Selector は Reactor モードの基盤を提供します Netty は Selector モードと Reactor モードを組み合わせて効率的なスレッドを設計しますモデル。まずは Reactor パターンを見てみましょう:
2.1 Reactor パターン
Wikipedia では Reactor モデルについて次のように説明しています。次に、サービス ハンドラーは受信リクエストを逆多重化し、それらを関連するリクエスト ハンドラーに同期的にディスパッチします。まず第一に、Reactor モードはイベント駆動型です。1 つ以上の同時入力ソース、サーバー ハンドラー、および複数のリクエスト ハンドラーがあります。このサービス ハンドラーは入力リクエストを同期的に多重化し、対応するリクエスト ハンドラーに分配します。これは、以下の図に示されています。
この構造は、プロデューサー モデルとコンシューマー モデルに似ています。つまり、1 つ以上のプロデューサーがイベントをキューに入れ、 a または複数のコンシューマーが処理のためにこのキューからイベントをアクティブにポーリングします; 一方、Reactor モードにはバッファリング用のキューがありません。イベントがサービス ハンドラーに入力されるたびに、サービス ハンドラーはさまざまなイベント タイプに応じてイベントをさまざまなイベントにアクティブに配布します。対応するリクエスト ハンドラーを使用して処理されます。
2.2 Reator モードの実装
Reator モードを構築する Java NIO については、Doug lea が「Java のスケーラブル IO」で詳しく説明しています。ここでは、Reator モードを実装するための PPT のインターセプトを示します。 . 説明
1. 最初の実装モデルは次のとおりです:
これは、Reactor モードが非同期非同期を使用するため、最も単純な Reactor シングルスレッド モデルです。 -blocking IO、すべての IO 操作はブロックされません理論的には、1 つのスレッドがすべての IO 操作を独立して処理できます。現時点では、Reactor スレッドはジェネラリストであり、複数のソケットの切断、新しい接続の受け入れ、および処理チェーンへのリクエストの分散を担当します。
一部の小容量アプリケーション シナリオでは、シングルスレッド モデルを使用できます。
(1) NIO スレッドが数百または数千のリンクを同時に処理すると、パフォーマンスが低下します。 NIO スレッドの CPU 負荷が 100% に達しても、メッセージを完全に処理できません
(2) NIO スレッドが過負荷になると、処理速度が低下し、多数のクライアント接続がタイムアウトする原因となります。タイムアウト後、メッセージは頻繁に再送信され、さらに重くなります。NIO スレッドの負荷を軽減します。
(3) 信頼性が低い スレッドの予期しない無限ループにより、通信システム全体が使用できなくなります。
これらの問題を解決するために、Reactor マルチスレッド モデルが登場しました。
2.Reactor マルチスレッド モデル:
以前のモデルと比較して、このモデルは処理チェーン部分でマルチスレッド (スレッド プール) を使用します。 。
ほとんどのシナリオでは、このモデルはパフォーマンス要件を満たすことができます。ただし、一部の特殊なアプリケーション シナリオでは、サーバーはクライアントのハンドシェイク メッセージに対してセキュリティ認証を実行します。このようなシナリオでは、単一のアクセプター スレッドのパフォーマンスが不十分になる可能性があります。これらの問題を解決するために、3 番目の Reactor スレッド モデルが作成されました。
関連する推奨事項: 「java 開発チュートリアル 」
3.リアクター マスター/スレーブ モデル
# # 2 番目のモデルと比較すると、このモデルは Reactor を 2 つの部分に分割しており、mainReactor はサーバー ソケットの監視と新しい接続の受け入れを担当し、確立されたソケットを subReactor に割り当てます。 SubReactor は、接続されたソケットの多重化を解除し、ネットワーク データを読み書きし、ビジネス処理機能のためにワーカー スレッド プールにデータをスローする役割を果たします。通常、subReactor の数は CPU の数と同じにすることができます。 2.3 Netty モデル2.2 で Reactor の 3 つのモデルについての説明が終わりましたが、Netty はどれでしょうか?実際、Netty のスレッド モデルは Reactor モデルのバリアントであり、スレッド プールを削除するバリアントの 3 番目の形式であり、Netty NIO のデフォルト モードでもあります。 Netty の Reactor モードの参加者には主に次のコンポーネントが含まれます:
(1) Selector
(2) EventLoopGroup/EventLoop
(3) ChannelPipeline
Selector は、NIO が提供する SelectableChannel マルチプレクサーで、デマルチプレクサーの役割を果たします。ここでは詳細は説明しませんが、他の 2 つの関数と Netty の Reactor モードでの役割を以下に紹介します。
3. EventLoopGroup/EventLoop
システムの実行中にスレッド コンテキストが頻繁に切り替わると、さらなるパフォーマンス損失が発生します。複数のスレッドがビジネス プロセスを同時に実行する場合、ビジネス開発者はスレッドの安全性について常に注意を払う必要があります。同時に変更される可能性のあるデータは何ですか?また、それをどのように保護するか?これにより、開発効率が低下するだけでなく、追加のパフォーマンス損失が発生します。
上記の問題を解決するために、Netty はシリアル化設計コンセプトを採用し、メッセージの読み取り、エンコード、その後のハンドラーの実行まで、常に IO スレッド EventLoop が責任を負い、プロセス全体が実行されないことを意味します。スレッドのコンテキストが切り替わっても、データが同時に変更されるリスクはありません。これは、Netty スレッド モデルが Reactor マスター/スレーブ モデルのスレッド プールを削除する理由も説明します。
EventLoopGroup は、EventLoops のグループを抽象化したものです。EventLoopGroup は、タスクを処理するために、特定のルールに従って EventLoops のグループ内の EventLoops の 1 つを取得できる次のインターフェイスを提供します。EventLoopGroup について知っておくべきことは、こちらをご覧ください。プログラミングでは、BossEventLoopGroup と WorkerEventLoopGroup という 2 つの EventLoopGroup が機能する必要があります。通常、サービス ポート、つまり ServerSocketChannel はセレクターと EventLoop スレッドに対応します。これは、BossEventLoopGroup のスレッド番号パラメーターが 1 であることを意味します。 BossEventLoop は、クライアントの接続を受信し、IO 処理のために SocketChannel を WorkerEventLoopGroup に渡す役割を果たします。
EventLoop の実装は、Reactor パターンのディスパッチャーとして機能します。
4. ChannelPipeline
ChannelPipeline は、実際には Reactor モードでリクエスト プロセッサの役割を果たします。
ChannelPipeline のデフォルトの実装は DefaultChannelPipeline です。DefaultChannelPipeline 自体は、ユーザーには見えない末尾と先頭の ChannelHandler を維持します。これらは、リンク リスト キューの先頭と末尾にそれぞれ配置されます。尾部は上部にあり、頭部はネットワーク層に近い方向にあります。 Netty の ChannelHandler には、ChannelInBoundHandler と ChannelOutBoundHandler という 2 つの重要なインターフェイスがあります。インバウンドはシステムの外部から内部へのネットワーク データの流れとして理解でき、アウトバウンドはシステムの内部からシステムの外部へのネットワーク データの流れとして理解できます。ユーザーによって実装された ChannelHandler は、必要に応じて 1 つ以上のインターフェイスを実装し、パイプラインのリンク リスト キューに配置できます。ChannelPipeline は、さまざまな IO イベント タイプに従って処理する対応するハンドラーを見つけます。リンク リスト キューは責任連鎖モードにあり、トップダウンまたはボトムアップのバリアントで、イベントの相関関係を満たすすべてのハンドラーがイベントを処理します。
ChannelInBoundHandler は、クライアントからサーバーに送信されたメッセージを処理します。通常、ハーフパケット/スティッキー パケット、デコード、データの読み取り、ビジネス処理などを実行するために使用されます。ChannelOutBoundHandler は、サーバーから送信されたメッセージを処理します。クライアントへの処理。通常、メッセージをエンコードしてクライアントに送信するために使用されます。
次の図は、ChannelPipeline の実行プロセスを示しています。
パイプラインの詳細については、「パイプライン モデルに関する簡単な説明」を参照してください。 (パイプライン)
5. バッファ
Netty が提供する拡張バッファには、NIO に比べて多くの利点があります。データ アクセスの非常に重要な部分として、以下を見てみましょう。 Netty's Bufferの特徴は何ですか?
1.ByteBuf 読み取りポインターと書き込みポインター
ByteBuffer では、読み取りポインターと書き込みポインターは位置ですが、ByteBuf では、読み取りポインターと書き込みポインターはそれぞれ ReaderIndex と WriterIndex です。 1 つのポインタで 2 つのポインタの機能を実現し、変数を保存します ただし、ByteBuffer の読み書き状態を切り替える場合は、flip メソッドを呼び出す必要があります。次回書き込む前に、Buffer の内容を読み取ってから呼び出す必要があります。 。各読み取りの前にフリップを呼び出し、書き込みの前にクリアします。これは間違いなく開発に退屈な手順をもたらし、コンテンツが読み取られるまでコンテンツを書き込むことができないため、非常に柔軟性が低くなります。対照的に、ByteBuf を見てみましょう。読み取り時は、readerIndex ポインタのみに依存します。書き込み時は、writerIndex ポインタのみに依存します。各読み取りと書き込みの前に対応するメソッドを呼び出す必要はなく、制限はありません一気に読むことに。
2.ゼロコピー
(1) Netty はダイレクト バッファーを使用して ByteBuffer を送受信し、バイト バッファーのセカンダリ コピーを必要とせずに、ソケットの読み取りと書き込みにオフヒープ ダイレクト メモリを使用します。ソケットの読み取りおよび書き込みに従来のヒープ メモリ (HEAP BUFFERS) を使用する場合、JVM はヒープ メモリのバッファをダイレクト メモリにコピーし、それをソケットに書き込みます。ヒープ外の直接メモリと比較して、メッセージには送信プロセス中にバッファの追加メモリ コピーが含まれます。
(2) Netty は、複数の ByteBuffer オブジェクトを集約できる結合 Buffer オブジェクトを提供します。ユーザーは、メモリ コピーという従来の方法を回避し、バッファを操作するのと同じように結合バッファを簡単に操作できます。バッファは 1 つの大きなバッファにマージされます。バッファ。
(3) Netty のファイル転送は transferTo メソッドを使用します。これにより、ファイル バッファ内のデータをターゲット チャネルに直接送信でき、従来のサイクリック書き込みメソッドによって引き起こされるメモリ コピーの問題を回避できます。
3. 参照カウントとプーリング技術
Netty では、適用された各バッファーは Netty にとって非常に貴重なリソースである可能性があるため、メモリ アプリケーションを取得し、より多くの制御を取り戻すために、Netty はメモリを実装します。参照カウントに基づく管理。 Netty の Buffer の使用はダイレクト メモリ (DirectBuffer) に基づいており、これにより I/O 操作の効率が大幅に向上します。ただし、I/O 操作の高効率に加えて、DirectBuffer と HeapBuffer には当然の欠点もあります。 DirectBuffer のアプリケーションは HeapBuffer よりも効率が悪いため、Netty は参照カウントと組み合わせて PolledBuffer を実装します。つまり、使用量をプールします。参照カウントが 0 に等しい場合、Netty はバッファをプールにリサイクルします。次回のバッファに適用されます。モーメントは再利用されます。
概要
Netty は本質的に Reactor パターンの実装であり、Selector がマルチプレクサー、EventLoop がリピーター、Pipeline がイベント プロセッサーとして機能します。ただし、通常の Reactor とは異なり、Netty はシリアル化を使用し、Pipeline で責任連鎖モデルを使用します。
Netty のバッファーは、NIO のバッファーと比較して最適化されており、パフォーマンスが大幅に向上しています。
以上がJava の netty 原則とは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。