Node.jsとCPUを多用するリクエスト


215

Node.js HTTPサーバーをいじくり始めて、サーバー側のJavascriptを書きたいと思っていますが、何かが原因で、自分のWebアプリケーションでNode.jsを使い始められません。

非同期I / Oの概念全体を理解していますが、画像の操作や大きなデータセットの並べ替えなど、手続き型コードが非常にCPUを集中的に使用するエッジケースについて少し心配しています。

私が理解しているように、サーバーは、ユーザーのリストの表示やブログ投稿の表示などの単純なWebページ要求に対して非常に高速です。ただし、グラフィックを生成したり、数千の画像のサイズを変更したりする非常にCPU集中型のコード(たとえば、管理バックエンド)を記述したい場合、リクエストは非常に遅くなります(数秒)。このコードは非同期ではないため、数秒の間にサーバーに送られるすべてのリクエストは、遅いリクエストが完了するまでブロックされます。

1つの提案は、CPU集中型のタスクにWebワーカーを使用することでした。ただし、別のJSファイルを含めることで機能するため、Webワーカーがクリーンなコードを作成するのが難しくなると思います。CPU集中型のコードがオブジェクトのメソッドにある場合はどうなりますか?CPUを集中的に使用するメソッドごとにJSファイルを作成するのはちょっと面倒です。

もう1つの提案は、子プロセスを生成することでしたが、これによりコードの保守性がさらに低下します。

この(認識された)障害を克服するための提案はありますか?CPU負荷の高いタスクが非同期で実行されることを確認しながら、Node.jsでクリーンなオブジェクト指向コードをどのように記述しますか?


2
オリビエ、あなたは私が念頭に置いていたのと同じ質問(ノードの初心者)、特に画像の処理に関して質問しました。Javaでは、固定スレッドのExecutorServiceを使用して、すべてのサイズ変更ジョブを渡して、すべての接続から完了するのを待つことができます。ノードでは、制限する外部モジュールへの作業をシャッフルオフする方法がわかりません(言う)一度に2までの同時操作の最大数。これを行うエレガントな方法を見つけましたか?
リヤドカラ2011

回答:


55

必要なのはタスクキューです。長時間実行されているタスクをWebサーバーから移動するのは良いことです。各タスクを「個別の」jsファイルに保存すると、モジュール性とコードの再利用が促進されます。長期的にはデバッグと保守が容易になるような方法でプログラムを構造化する方法を考える必要があります。タスクキューのもう1つの利点は、ワーカーを別の言語で記述できることです。タスクをポップして、作業を行い、応答を書き戻すだけです。

このようなhttps://github.com/resque/resque

彼らがなぜそれを作ったかについてのgithubからの記事はここにありますhttp://github.com/blog/542-introducing-resque


35
特にノードの世界に根ざした質問でRubyライブラリにリンクするのはなぜですか?
ジョナサンドゥメイン

1
@JonathanDumaineタスクキューの優れた実装です。RubyコードをRadし、JavaScriptで書き換えます。利益!
Simon Stender Boisen 2013年

2
私はこのためのギアマンの大ファンです。ギアマンワーカーは新しいジョブについてギアマンサーバーをポーリングしません。新しいジョブは即座にワーカーにプッシュされます。非常に応答性が
Casey Flynn

1
実際、誰かがそれをノードの世界に移植しています:github.com/technoweenie/coffee-resque
FrontierPsycho

@pacerier、どうしてそんなこと言うの?何を提案しますか?
luis.espinal 2017年

289

これはWebサーバーの定義を誤解しています-クライアントとの「会話」にのみ使用してください。高負荷のタスクはスタンドアロンプ​​ログラムに委任する必要があります(もちろん、JSで作成することもできます)。
あなたはおそらくそれが汚いと言うでしょうが、画像のサイズ変更で動かなくなったWebサーバープロセスがさらに悪いことを保証します(他のクエリをブロックしない場合、Apacheと言っても)。それでも、コードの冗長性を回避するために共通ライブラリを使用できます。

編集:私は類推を思いつきました。Webアプリケーションはレストランとして存在する必要があります。ウェイター(Webサーバー)と料理人(ワーカー)がいます。ウェイターはクライアントと連絡を取り、メニューを提供したり、菜食主義の料理があるかどうかを説明したりといった簡単なタスクを行います。一方、彼らはより難しい仕事を台所に委任します。ウェイターは簡単なことしかやっていないので、反応が速く、料理人は仕事に集中できます。

ここでのNode.jsは、一度に多くのリクエストを処理できる単一の非常に才能のあるウェイターであり、Apacheは、それぞれ1つのリクエストを処理するだけのダムウェイターのギャングです。この1つのNode.jsウェイターが料理を始めたら、それはすぐに大惨事になります。それでも、調理はアパッチウェイターの大量の供給さえも枯渇させる可能性があり、キッチンの混乱と責任の漸進的な低下については言及していません。


6
Webサーバーがマルチスレッドまたはマルチプロセスで、複数の同時要求を処理できる環境では、1つの要求に数秒を費やすのが一般的です。人々はそれを期待するようになりました。私が誤解しているのは、node.jsが「通常の」Webサーバーであるということです。node.jsを使用するには、プログラミングモデルを少し調整する必要があります。これには、「長時間実行」ワークアウトを非同期ワーカーにプッシュすることが含まれます。
ティロ

13
リクエストごとに子プロセスを生成しないでください(node.jsの目的に反します)。重いリクエストの内部からのみワーカーを生成します。または、重いバックグラウンド作業をnode.js以外のものにルーティングします。
ティロ

47
いい例え、mbq!
ランスフィッシャー

6
ハ、私は本当にそれが好きです。"Node.js:悪い慣行をうまく機能させない"
ethan

7
@mbq類推は好きですが、いくつかの作業を使用できます。従来のマルチスレッドモデルは、ウェイターであり料理人でもあります。注文が完了すると、その人は別の注文を処理する前に戻って食事を調理する必要があります。node.jsモデルには、ウェイターとしてのノードとクックとしてのウェブワーカーがあります。ワーカーがより時間のかかるタスクを管理する間、ウェイターはリクエストのフェッチ/解決を処理します。より大規模に拡張する必要がある場合は、メインサーバーをノードクラスターにして、CPU集中タスクを、マルチスレッド処理用に構築された他のサーバーにリバースプロキシします。
Evan Plaice、2012年

16

CPUを集中的に使用するコードで非同期に実行するのではなく、並列に実行する必要があります。HTTPリクエストを処理しているスレッドから処理作業を引き出す必要があります。これがこの問題を解決する唯一の方法です。NodeJSでの答えはクラスターモジュールです、重いプロセスを実行するために子プロセスを生成するため。(AFAIKノードには、スレッド/共有メモリの概念はありません。プロセスまたは何もありません)。アプリケーションの構成方法には2つのオプションがあります。80/20ソリューションを取得するには、8つのHTTPサーバーを生成し、子プロセスで計算集約型のタスクを同期的に処理します。それを行うのはかなり簡単です。あなたはそのリンクでそれについて読むのに1時間かかるかもしれません。実際、そのリンクの冒頭にあるサンプルコードを削除するだけで、その方法の95%が得られます。

これを構成するもう1つの方法は、ジョブキューを設定し、大きな計算タスクをキューに送信することです。ジョブキューのIPCには多くのオーバーヘッドが関連付けられていることに注意してください。これは、タスクがオーバーヘッドよりもかなり大きい場合にのみ役立ちます。

これらの他の回答のいずれもクラスターについて言及していないことに驚いています。

背景:非同期コードは、何かが別の場所で発生するまで中断するコードで、その時点でコードが起動し、実行を継続します。何かが遅い場所で発生しなければならない非常に一般的なケースの1つはI / Oです。

非同期コードは、作業を行うのがプロセッサの責任である場合は役に立ちません。それはまさに「計算集約型」タスクの場合です。

さて、非同期コードはニッチであるように見えるかもしれませんが、実際には非常に一般的です。計算集中型のタスクには役に立たないだけです。

たとえば、I / Oの待機は、常にWebサーバーで発生するパターンです。サーバーに接続するすべてのクライアントはソケットを取得します。ほとんどの場合、ソケットは空です。ソケットがデータを受信するまでは何もしたくないので、その時点でリクエストを処理します。内部では、NodeのようなHTTPサーバーは、何千ものオープンソケットを追跡するためにイベントライブラリ(libev)を使用しています。OSはlibevに通知し、ソケットの1つがデータを取得するとlibevにNodeJSに通知します。次に、NodeJSがイベントキューにイベントを配置します。この時点でhttpコードが起動し、次々とイベントを処理します。ソケットにデータがあるまでイベントはキューに入れられないので、イベントはデータを待機することはありません-それはすでにそこにあります。

シングルスレッドのイベントベースのWebサーバーは、ボトルネックがほとんど空のソケット接続の束を待機していて、すべてのアイドル接続に対してスレッド全体またはプロセスが不要で、250kをポーリングしたくない場合のパラダイムとして理にかなっています。データのある次のソケットを見つけるためのソケット。


正解でなければなりません.... 8つのクラスターを生成するソリューションの場合、8つのコアが必要ですか?または、複数のサーバーを備えたロードバランサー。
Muhammad Umer 2017

また、キューを設定する2番目のソリューションについて学ぶための良い方法は何ですか。キューの概念はかなり単純ですが、外部とはプロセスとキューの間のメッセージング部分です。
Muhammad Umer 2017

そのとおり。どういうわけか、作業を別のコアに移す必要があります。そのためには、別のコアが必要です。
masonk 2018年

Re:キュー。実際の答えは、ジョブキューを使用することです。ノードで利用可能なものがあります。一度も使ったことがないので、おすすめできません。好奇心の答えは、ワーカープロセスとキュープロセスが最終的にソケットを介して通信することです。
masonk 2018年

7

使用できるいくつかのアプローチ。

@Timが指摘するように、メインのサービングロジックの外部または並列に配置する非同期タスクを作成できます。正確な要件によって異なりますが、cronでさえキューイングメカニズムとして機能できます。

WebWorkersは非同期プロセスで機能しますが、現在node.jsではサポートされていません。サポートを提供する拡張機能がいくつかあります。例:http : //github.com/cramforce/node-worker

それでも、標準の「必要」メカニズムを使用して、モジュールとコードを再利用できます。ワーカーへの最初のディスパッチが結果の処理に必要なすべての情報を確実に渡すようにする必要があるだけです。


0

使用child_processは1つのソリューションです。ただし、生成された各子プロセスは、Goに比べて大量のメモリを消費する可能性がありますgoroutines

kueなどのキューベースのソリューションを使用することもできます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.