6

私はそれが繰り返される質問であることを知っており、次のような記事を読んだことがあります http://www.mailinator.com/tymaPaulMultithreaded.pdf nio が io よりも優れているとは限りません。

しかし、従来のアクセプター/ワーカー スレッド アーキテクチャよりも Web サーバーを開発する際に、どのように Java nio をより適切にスケーリングできるかを理解するのに苦労しています。説明させてください:

通常、Java Web サーバーは次のパターンを使用して接続を処理します。

  • ServerSocket の accept() メソッドで、コア数に制限されたいくつかのアクセプター スレッドがブロックされます。

    while (true) {
      socket = serverSocket.accept();
      // handleRequest submits the socket to a queue
      handleRequest(socket);
      socket.close();
    }
    
  • クライアント ソケットが取得されると、非ブロッキング キューに送信され、ワー​​カー スレッドのプールからワーカー スレッドによって処理されます。実行中の io 操作の期間に応じたワーカー スレッドの数。

java.nio を使用すると、このアーキテクチャがよりスケーラブルになりますか?

つまり、ブロッキング操作 (データベースまたはファイルシステムへのアクセス、外部サービスの呼び出し) を行うリクエストを処理するために、ワーカー スレッドが必要になるということです。バックエンド操作が node.js のように非同期で実行されない場合でも、1 つまたは 2 つのイベント ディスパッチャー スレッドに対して全体的なスケーラビリティを制限する作業スレッドが必要になります。

4

2 に答える 2

18

この問題に関する Paul Tyma の記事がとても気に入っています。非常に詳細です。彼の記事には、次の 2 つの主要なポイントがあります。

  • 従来のブロッキング IO でスループットを向上させることができます (彼はそれを測定しました)。
  • 従来のブロッキング IO により、サーバー ロジックがより単純になります。クライアントとサーバーの対話の状態は、スレッド フローで暗黙的に定義されます。

ノンブロッキング NIO を使用する主な理由は、非常に多くの同時アイドル リクエストがある場合です。その理由は、NIO を使用すると、同じスレッドから複数のリクエストを処理できるため、このほうが優れているからです。

わかりました、これはどこでも読めるものです。さて...なぜこれが良いのですか?

主な理由は 2 つあります。これらは、各スレッドに伴う 2 種類のオーバーヘッドに関連しています。

  • スケジューラがプロセッサが実行しているスレッドを変更すると、「コンテキストスイッチ」が発生します。これは、高価な操作になる可能性があります (つまり、スレッドには、プロセッサ内に何らかの状態があります。レジスタ内の値、L1、L2 にロードされる大量のデータ)。 、L3 キャッシュなど -- スレッドが停止したときにどこかに「保存」し、スレッドが実行を続けるときに「リロード」する必要があります。また、L1、L2、L3 キャッシュの内容を失うと、大量のキャッシュを取得する可能性があります。キャッシュミス、これは悪い可能性があります (ワークロードによって異なります))
  • 各スレッドは、独自の独立したスタックを割り当てる必要があります(通常、ローカル変数を格納し、関数呼び出しのアドレスを返すために使用されます)。

そのため、各スレッドには、さらに「無駄な」メモリと、「無駄な」プロセッサ サイクルが発生します (「コンテキスト スイッチ」を実行するため)。

ここで、チャット サーバーがあり、クライアントが新しいメッセージを要求する HTTP 接続を作成し、そのクライアントに新しいメッセージがある場合にのみサーバーが応答するとします (クライアントが新しいメッセージを即座に受信できるようにするため)。そのようなクライアントが 10,000 あるとします。従来のブロックする接続ごとのスレッド モデルでは、10,000 スレッドになります。Java では、スレッド スタック サイズ (-Xss) の一般的な標準値は 256kb です。10,000 スレッドの場合、自動的に約 2GB のメモリが使用されます!!!!!!!! さらに悪いことに、チャット サーバーでまったくアクティビティがなく、メッセージが送信されていない場合でも、クライアントによって 2 GB が浪費されます。大量のコンテキスト スイッチを追加すると、問題があることがわかります。

この状況では、ノンブロッキング NIO を使用したほうがよいでしょう。この場合、より少ないスレッド (最終的には 1 つだけ!) で 10k クライアントすべてを処理するのに十分なため、コンテキスト スイッチ (つまり、CPU 時間) を節約し、より複雑なコードを犠牲にしてもスレッド スタック (つまり、メモリ) を節約できます。これは通常、ノンブロッキング NIO を使用することの副作用です。

于 2013-04-12T05:26:47.827 に答える
3

NIO またはノンブロッキング IO は、高い同時実行性のために非常にうまくスケーリングできます。接続ごとに専用のスレッドは必要ありません。接続を受け入れるために必要なメイン スレッドは 1 つだけで、IO を処理する他のいくつかのワーカー スレッドが必要です。スレッドの数は固定されており、これが従来のアクセプター/ワーカー スレッド アーキテクチャよりもスケーラブルである主な理由です。

于 2013-04-12T05:12:54.847 に答える