web-dev-qa-db-ja.com

多くのブロッキングVS単一の非ブロッキングワーカー

接続を受け入れるHTTPサーバーがあり、ヘッダーが完全に送信されるまでどういうわけか待機していると仮定します。それを実装する最も一般的な方法は何ですか?残りの長所と短所。私はこれらだけを考えることができます:

次の理由により、多くのブロッキングワーカーが適しています:

  • それはより敏感です。
  • 新しい接続を導入する方が簡単です(同期リストに追加できるようになるまで外部の人が待つのではなく、ワーカーが自分で接続を取得します)。
  • CPU使用率は、接続数の増減に応じて自動的に(追加の作業なしで)バランスをとります。
  • CPU使用量が少ない(ブロックされたスレッドは実行ループから除外され、クライアント間をジャンプするためのロジックは必要ありません)。

次の理由により、単一の非ブロッキングワーカーが適しています:

  • より少ないメモリを使用します。
  • レイジークライアント(サーバーへの接続とヘッダーの送信が遅い、またはまったく送信しない)に対する脆弱性が低い。

おそらくお分かりのように、私の意見では、複数のワーカースレッドは全体的に少し優れたソリューションのように見えます。それに関する唯一の問題は、そのようなサーバーを攻撃する方が簡単であることです。

編集(詳細な調査):Webで見つけたリソース( 数千のスレッドとブロックI/O-古い書き方) Java Servers is new(and way way) by Paul Tyma)ブロッキングアプローチが一般的に優れていることを示唆していますが、偽の接続を処理する方法はまだわかりません。

追伸タスクに一部のライブラリまたはアプリケーションの使用を提案しないでください。私は、それが機能するのではなく、実際にどのように機能するか、または機能する可能性があるかを知りたいと思っています。

P.S.S.ロジックを複数の部分に分割しましたが、これはHTTPヘッダーの受け入れのみを処理します。それらを処理しません。

9
Pijusn

銀の弾丸はありません

実際には、状況によって異なります...

tl; dr-簡単な解決策、nginxを使用...

ブロッキング:

たとえば、Apacheはデフォルトで、すべての接続に対してプロセスが分岐されるブロッキングスキームを使用します。つまり、すべての接続には独自のメモリスペースが必要であり、接続の数が増えると、コンテキスト切り替えのオーバーヘッドの量も増えます。しかし、利点は、接続が閉じられると、コンテキストが破棄され、すべて/すべてのメモリを簡単に取得できることです。

マルチスレッドのアプローチは、接続の数に応じてコンテキスト切り替えのオーバーヘッドが増加するという点で似ていますが、共有コンテキストではメモリ効率が向上する可能性があります。このようなアプローチの問題は、安全な方法で共有メモリを管理することが難しいことです。多くの場合、メモリ同期の問題を克服するためのアプローチには独自のオーバーヘッドが含まれます。たとえば、ロックはCPU集中型の負荷でメインスレッドを凍結する可能性があり、不変タイプを使用すると、データの不必要なコピーが大量に追加されます。

AFAIKは、ブロッキングHTTPサーバーでマルチプロセスアプローチを使用することをお勧めします。これは、安全な方法でメモリを管理/回復するほうが安全/簡単であるためです。メモリの回復がプロセスの停止と同じくらい簡単な場合、ガベージコレクションは問題にはなりません。実行時間の長いプロセス(つまり、デーモン)の場合、その特性は特に重要です。

ワーカー数が少ない場合、コンテキスト切り替えのオーバーヘッドは取るに足らないものに見えるかもしれませんが、負荷が数百から数千の同時接続にスケールアップすると、デメリットがより重要になります。せいぜい、コンテキストスイッチングは、存在するワーカーの数にO(n)をスケーリングしますが、実際にはそれよりも悪い可能性があります。

IO高負荷の場合、ブロッキングを使用するサーバーが理想的な選択肢ではない場合がありますが、CPU集中型の作業には理想的であり、メッセージパッシングは最小限に抑えられます。

非ブロッキング:

非ブロッキングは、Node.jsやnginxのようなものです。これらは、IO集約型の負荷がかかった状態で、ノードあたりの接続数を大幅に増やすことが特に知られています。基本的に、スレッド/プロセスベースのサーバーが処理できる上限に達すると、代替オプションを模索し始めました。これは C10K問題 とも呼ばれます(つまり、10,000の同時接続を処理する機能)。

非ブロッキング非同期サーバーは通常、メインスレッドに過負荷をかけたくないため、CPU集中型の負荷を回避するように注意する必要があるという点で、ロック付きマルチスレッドアプローチと多くの特性を共有します。利点は、コンテキストの切り替えによって発生するオーバーヘッドが本質的に排除され、1つのコンテキストメッセージの受け渡しだけで問題がなくなることです。

多くのネットワーキングプロトコルでは機能しない可能性がありますが、HTTPのステートレスな性質は、非ブロッキングアーキテクチャでは特に効果的です。リバースプロキシと複数のノンブロッキングHTTPサーバーの組み合わせを使用することで、負荷が大きいノードを特定してルーティングすることが可能です。

ノードが1つしかないサーバーでも、スループットを最大化するために、セットアップでプロセッサコアごとに1つのサーバーを含めることは非常に一般的です。

両方:

「理想的な」ユースケースは、両方の組み合わせになります。上部のルーティング要求専用のフロントにあるリバースプロキシ、次にブロッキングサーバーと非ブロッキングサーバーの混合。 IO静的コンテンツ、キャッシュコンテンツ、htmlコンテンツの提供などのタスクの非ブロック化。画像/ビデオのエンコード、ストリーミングコンテンツ、数値処理、データベース書き込みなどのCPU負荷の高いタスクのブロック化。

あなたの場合:

ヘッダーを確認するだけで実際にリクエストを処理しない場合、基本的に説明しているのはリバースプロキシです。そのような場合、私は間違いなく非同期のアプローチを採用します。

nginx組み込みリバースプロキシ のドキュメントをチェックすることをお勧めします。

脇:

私はあなたが提供したリンクから記事を読みました、そして、非同期が彼らの特定の実装のための悪い選択であったことは理にかなっています。問題は1つのステートメントで要約できます。

クライアントを切り替えるときに、値/状態を保存および復元するためのコードが難しいことがわかりました

彼らは国家にふさわしいプラットフォームを構築していた。そのような場合、非同期アプローチは、コンテキストが切り替わるたびに(つまり、イベントが発生したとき)常に状態を保存/ロードする必要があることを意味します。さらに、SMTP側では、CPUを集中的に使用する多くの作業を行っています。

彼らは非同期をかなりよく理解していないようで、その結果、多くの悪い仮定をしました。

4
Evan Plaice