[解決済み] 一般的に、Node.jsは10,000の同時リクエストをどのように処理するのですか?
質問
Node.jsはシングルスレッドとイベントループを使って、一度に1つずつしか処理しない(ノンブロッキングである)ことを理解しています。しかし、それでも、どのように動作するのでしょうか、例えば、10,000の同時リクエストを考えてみましょう。イベントループは、すべてのリクエストを処理するのでしょうか?それでは時間がかかりすぎるのではないでしょうか?
マルチスレッドのウェブサーバーより速いというのは、(まだ)理解できません。マルチスレッドのウェブサーバーはリソース(メモリ、CPU)が高くなることは理解していますが、それでも速くならないのでしょうか?おそらく私が間違っているのでしょう。このシングルスレッドがどのように多くのリクエストで速いのか、また10,000のような多くのリクエストを処理するときに通常何をするのか(高レベルで)説明してください。
また、そのシングルスレッドは、その大量でもうまくスケールするのでしょうか?私はNode.jsを学び始めたばかりであることを念頭に置いてください。
どのように解決するのですか?
もしこの質問をしなければならないとしたら、あなたはおそらくほとんどのウェブアプリケーションやサービスが何をするかについてよく知らないのでしょう。おそらく、すべてのソフトウェアがこれを行うと思っていることでしょう。
user do an action
│
v
application start processing action
└──> loop ...
└──> busy processing
end loop
└──> send result to user
しかし、これはウェブアプリケーション、いや、データベースをバックエンドとするあらゆるアプリケーションの動作方法とは異なります。ウェブアプリケーションはこのように動作します。
user do an action
│
v
application start processing action
└──> make database request
└──> do nothing until request completes
request complete
└──> send result to user
このシナリオでは、ソフトウェアの実行時間のほとんどを、データベースが戻るのを待つ0%のCPU時間として費やしています。
マルチスレッドなネットワークアプリ。
マルチスレッドネットワークアプリは、上記の作業負荷をこのように処理します。
request ──> spawn thread
└──> wait for database request
└──> answer request
request ──> spawn thread
└──> wait for database request
└──> answer request
request ──> spawn thread
└──> wait for database request
└──> answer request
つまり、このスレッドは、データベースがデータを返すのを待つために、0%のCPUを使用してほとんどの時間を費やしています。その間に、スレッドごとに完全に独立したプログラムスタックなどを含むスレッドに必要なメモリを確保しなければなりません。また、スレッドを起動する必要がありますが、これはフルプロセスを起動するほど高価ではありませんが、それでも決して安くはないでしょう。
シングルスレッドイベントループ
私たちはほとんどの時間をCPUの0%を使って過ごしているので、CPUを使っていないときにいくつかのコードを実行してはどうでしょうか。そうすれば、各リクエストはマルチスレッド・アプリケーションと同じ量のCPU時間を得ることができますが、スレッドを開始する必要はありません。そこで、このようにします。
request ──> make database request
request ──> make database request
request ──> make database request
database request complete ──> send response
database request complete ──> send response
database request complete ──> send response
実際には、どちらのアプローチもほぼ同じレイテンシーでデータを返します。なぜなら、処理の大部分を占めるのはデータベースの応答時間だからです。
ここでの主な利点は、新しいスレッドを起動する必要がないため、たくさんのmallocを実行して速度を低下させる必要がないことです。
魔法のような、見えないスレッド
一見不思議に思えるのは、上記の2つのアプローチで、なぜワークロードを"parallel"で実行できるのか、ということです。その答えは、データベースがスレッド化されているからです。つまり、シングルスレッドのアプリは、実は別のプロセスであるデータベースのマルチスレッドな挙動を利用しているのです。
シングルスレッド・アプローチが失敗する場合
データを返す前に多くのCPU計算をする必要がある場合、シングルスレッドアプリは大きな失敗をします。ここで言う計算とは、データベースの結果を処理するforループのことではありません。これはまだほとんどO(n)です。つまり、フーリエ変換(例えばMP3エンコード)やレイトレーシング(3Dレンダリング)等のことです。
シングルスレッドアプリのもう1つの落とし穴は、1つのCPUコアしか利用しないことです。つまり、クアッドコアのサーバーを使用している場合(最近では珍しくありませんが)、他の3つのコアを使用しないことになります。
マルチスレッドアプローチが失敗する場合
マルチスレッド アプリは、スレッドごとに大量の RAM を割り当てる必要がある場合、大きな失敗をします。まず、RAM の使用量自体が、シングルスレッドアプリのように多くのリクエストを処理できないことを意味します。さらに悪いことに、mallocは遅いのです。最近のウェブフレームワークではよくあることですが、たくさんのオブジェクトを割り当てることは、シングルスレッドアプリよりも遅くなる可能性があることを意味します。これは、通常、node.jsが勝つところです。
マルチスレッドを悪化させてしまう使用例として、スレッド内で他のスクリプト言語を実行する必要がある場合があります。まず、その言語のランタイム全体をmallocする必要があり、次にスクリプトで使用する変数をmallocする必要があります。
ですから、もしあなたがCやgoやjavaでネットワークアプリケーションを書いているのなら、スレッドのオーバーヘッドは通常あまり気にならないはずです。もしあなたがPHPやRubyにサービスを提供するためにCのWebサーバーを書いているなら、javascriptやRubyやPythonでより速いサーバーを書くのはとても簡単です。
ハイブリッドアプローチ
ウェブサーバの中には、ハイブリッドなアプローチを採用しているものがあります。例えば Nginx と Apache2 は、ネットワーク処理コードをイベントループのスレッドプールとして実装しています。各スレッドは同時にイベントループを実行し、シングルスレッドでリクエストを処理しますが、リクエストは複数のスレッドに負荷分散されます。
シングルスレッド・アーキテクチャの中には、ハイブリッド・アプローチを採用しているものもあります。1つのプロセスから複数のスレッドを起動するのではなく、複数のアプリケーションを起動します。たとえば、クアッドコアマシンに4つのnode.jsサーバーを起動します。そして、ロードバランサーを使って、各プロセスの作業負荷を分散させるのです。
この2つのアプローチは、技術的には互いに同じ鏡像のようなものです。
関連
-
[解決済み] joiライブラリを使用して2つの時間を比較する方法
-
[解決済み] MongoNetworkError: 最初の接続でサーバー [localhost:27017] への接続に失敗 [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017] 。
-
[解決済み] Node.jsのプログラムにコマンドライン引数を渡すにはどうしたらいいですか?
-
[解決済み] Node.jsを使うタイミングをどう判断するか?
-
[解決済み] Node.jsで終了する方法
-
[解決済み] Node.jsアプリケーションをデバッグするにはどうすればよいですか?
-
[解決済み] Node.jsのnpmモジュールをアンインストールするにはどうすればよいですか?
-
[解決済み] socket.ioとwebsocketの違いについて
-
[解決済み】Node.jsのシングルスレッド・ノンブロッキングIOモデルの動作について
-
[解決済み】Node.jsは内部でThreadsに依存しているのに、どうして本質的に高速なのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】エラーです。EACCES: 権限が拒否されました、アクセス '/usr/local/lib/node_modules' 。
-
[解決済み】Express.js req.bodyが未定義です。
-
[解決済み】POSTできない/expressを使用するとエラーが発生する
-
[解決済み] npm install エラー - ローカルの発行者証明書を取得できません。
-
[解決済み] S3 Bucket に何かを送信しようとすると、AWS Missing credentials が表示される (Node.js)
-
[解決済み] Yarn にパッケージを強制的に再インストールさせるにはどうしたらいいですか?
-
[解決済み] NodeJsのSequelizeでautoIncrementはどのように動作するのですか?
-
[解決済み] NPMが同じエラーで固まる EISDIR: ディレクトリに対する不正な操作、エラーで読み込み (ネイティブ)
-
[解決済み] npm not able to find a fileに関連するエラーは何が原因でしょうか?node_modules サブフォルダ内にコンテンツがありません。なぜでしょうか?
-
[解決済み】Node.jsは内部でThreadsに依存しているのに、どうして本質的に高速なのですか?