Node.js
Node.jsを使用します。js

Follow

Feb 24, 2017 – 14 min read

この記事は技術コンサルタントで Node.js 熱心者の Tomislav Capan から来ました。 Tomislav はもともと、2013 年 8 月に Toptal ブログでこの記事を発表しました。 以下のテーマは、この著者の意見と経験に基づいています。

JavaScript の人気の高まりは多くの変化をもたらし、今日の Web 開発の様相は劇的に変化しています。 Node.js を掘り下げる前に、言語とデータ形式 (JSON) を統一し、開発者のリソースを最適に再利用できる、スタック全体で JavaScript を使用する利点について読んでおくとよいでしょう。 これはNode.jsというよりJavaScriptの利点なので、ここではあまり触れません。 しかし、スタックに Node.js を組み込む際の重要な利点です。

Node.js は、Chrome の V8 JavaScript エンジン上に構築された JavaScript ランタイム環境です。 Node.js の作成者である Ryan Dahl は、「Gmail のようなアプリケーションに触発されて」、プッシュ機能を備えたリアルタイムの Web サイトの作成を目指していたことは特筆すべきことでしょう。 Node.js において、彼は開発者にノンブロッキング、イベントドリブン I/O パラダイムで作業するためのツールを提供しました。 Node.js は、Web ソケット上のプッシュ技術を採用したリアルタイムの Web アプリケーションで輝きを放っています。 それの何がそんなに革命的なのでしょうか。 クライアントとサーバーの両方が通信を開始することができ、自由にデータを交換することができます。

これは、クライアントが常に通信を開始する典型的な Web 応答パラダイムとはまったく対照的です。 さらに、これはすべて標準ポート 80 上で実行されるオープン Web スタック (HTML、CSS、JS) に基づいています。

Flash や Java アプトの形で長年これを持っていたと言う人がいるかもしれませんが、実際には、これらはクライアントに配信される転送プロトコルとして Web を使用するサンドボックス環境にすぎませんでした。 さらに、それらは孤立して実行され、しばしば非標準のポート上で動作し、特別な許可などが必要だったかもしれません。

そのすべての利点により、現在 Node.js はその独自の利点に依存する多くの有名企業のテクノロジー スタックで重要な役割を担っています。 Node.js Foundation は、Node.js Foundation のケース スタディ ページにある短いプレゼンテーションで、企業が Node.js を考慮すべき理由についての最善の考えをすべて集約しました。

この投稿では、これらの利点が達成される方法だけでなく、なぜ Node.js を使用したいのか – そしてなぜしないのか – 典型的な Web アプリケーション モデルを例として議論したいと思います。

どのように機能するのか

Node.js の主な考え方は、分散デバイス間で実行されるデータ集約型のリアルタイム アプリケーションに直面して、軽量かつ効率的に保つために、ノンブロッキング、イベント駆動型の I/O を使用するというものです。 その代わり、特定のニーズを満たすプラットフォームであるということです。 そして、このことを理解することが絶対に必要です。 Node.jsをCPUに負荷のかかる処理に使うのは絶対に避けなければなりません。 Node.js が本当に優れているのは、高速でスケーラブルなネットワーク アプリケーションを構築することです。 各接続 (リクエスト) が新しいスレッドを生成し、システム RAM を消費し、最終的に利用可能な RAM の量で最大になる従来の Web サービス技術と比較して、Node.

* 画像は元のブログ投稿から引用しています。

簡単に計算すると、各スレッドが 2 MB のメモリを潜在的に持っていると仮定すると、8 GB の RAM を持つシステム上で実行すると、理論上の最大同時接続数は 4000 になります (Michael Abernethy の記事 “Just what is Node.js?” から取った計算、IBM developerWorks で 2011 年に発表、残念ながら記事はもう入手不可)、さらにスレッドのコンテキスト スイッチング コストも必要です。 これは、従来のウェブサービス技術で一般的に扱われるシナリオです。 4281>

もちろん、すべてのクライアント リクエスト間で 1 つのスレッドを共有するという問題があり、これは Node.js アプリケーションを書く際の潜在的な落とし穴です。 まず、重い計算が Node の単一スレッドを窒息させ、計算が完了するまで受信リクエストがブロックされるため、すべてのクライアントに問題を引き起こす可能性があります (これについては後で説明します)。 第二に、開発者は、例外がコア (最上位) の Node.js イベント ループにバブリングして、Node.js インスタンスを終了させる (事実上プログラムをクラッシュさせる) ことがないように本当に注意する必要があります。

表面への例外バブリングを避けるために使用する手法は、コールバック パラメータとして呼び出し元にエラーを戻す (他の環境のようにエラーを投げるのではなく) ことです。 何らかの処理されない例外がバブルアップすることに成功したとしても、Node.js プロセスを監視し、クラッシュしたインスタンスの必要なリカバリを実行するツールが開発されています (おそらくユーザー セッションの現在の状態を回復することはできませんが)。最も一般的には Forever モジュール、または外部システム ツール upstart および monit、あるいは単なる upstart で異なるアプローチを使用することなどがあります。

npm: The Node Package Manager

Node.js について議論するとき、絶対に省略できないのは、すべての Node.js インストールにデフォルトで付属する npm ツールを使用したパッケージ管理に対する組み込みサポートです。 npm モジュールの考え方は、Ruby Gems と非常に似ています。一般に利用可能で再利用可能なコンポーネントのセットで、オンライン リポジトリを介して簡単にインストールでき、バージョンと依存関係を管理できます。 モジュール エコシステムは誰にでも開かれており、誰でも独自のモジュールを公開でき、それは npm リポジトリにリストアップされます。 npm の簡単な紹介は Beginner’s Guide に、モジュールの公開に関する詳細は npm Publishing Tutorial に記載されています。

今日最も便利な npm モジュールは次のとおりです。

  • hapi – Web とサービスアプリケーションを構築するための、非常にモジュール化された、使いやすい設定中心のフレームワーク
  • connect – Connect は Node.Js 用の拡張可能な HTTP サーバーフレームワークです。
  • socket.io and sockjs – 今日最も一般的な 2 つの Web ソケット コンポーネントのサーバー側コンポーネントです。
  • pug (旧 Jade) – HAML にインスパイアされた人気のテンプレートエンジンの一つ。Express.js のデフォルト。
  • mongodb and mongojs – MongoDB オブジェクトデータベース用の API を Node.js で提供する MongoDB ラッパー。
  • redis – Redis クライアントライブラリ。
  • lodash (underscore, lazy.js) – JavaScript ユーティリティの帯です。 Underscore がこのゲームを開始しましたが、主にパフォーマンスとモジュール化された実装のため、2つのうちの1つに押されました。
  • forever – おそらく、与えられたノードスクリプトを継続的に実行するための最も一般的なユーティリティです。
  • bluebird – フル機能の Promises/A+ 実装で、非常に優れたパフォーマンス。
  • moment – 日付のパース、検証、操作、書式設定のための軽量な JavaScript 日付ライブラリです。

    Where Should Be Node.js Be Used

    Chat は最も典型的なリアルタイム、マルチユーザーアプリケーションです。 IRC (当時) から、非標準ポートで動作する多くのプロプライエタリとオープン プロトコルを経て、標準ポート 80 で動作する Web ソケットを備えた Node.js で今日すべてを実装することができます。

    チャット アプリケーションは Node.js にとって本当にスイートスポットの例で、軽量で高トラフィック、データ集約型 (でも処理/コンピューティングは低) アプリケーションで分散デバイスにわたって動きます。 シンプルでありながら、典型的な Node.js アプリケーションで使用するパラダイムのほとんどをカバーしているからです。

    それでは、どのように動作するかを描写してみましょう。 たとえば、Web サイトに 3 人の人がいて、全員がメッセージ ボードに接続しているとします。

    サーバー側では、2 つのことを実装したシンプルな Express.js アプリケーションを用意しています。 1) メッセージボードと新しいメッセージ入力を初期化するための ‘Send’ ボタンの両方を含む Web ページを提供する GET ‘/’ リクエスト ハンドラ、および 2) Web ソケット クライアントによって送信される新しいメッセージをリスンする Web ソケット サーバーです。

    クライアントの 1 つがメッセージを投稿すると、次のようなことが起こります:

    • Browser は JavaScript ハンドラーを通じて ‘Send’ ボタン クリックをキャッチし、入力フィールドから値を拾います (つまり
    • WebSocket 接続のサーバー側コンポーネントはメッセージを受信し、ブロードキャスト メソッドを使用して他のすべての接続されたクライアントに転送します。

    Image taken from original blog.

    This is the simplest example.これは、最も単純な例です。 より堅牢なソリューションとして、Redis ストアをベースにしたシンプルなキャッシュを使用することもできます。 あるいは、さらに高度なソリューションでは、クライアントへのメッセージのルーティングを処理するメッセージ キューと、一時的な接続の損失をカバーする、またはオフラインの間に登録されたクライアントのメッセージを保存する、より堅牢な配信メカニズムがあります。 イベントへの反応、多数の同時接続の処理、およびユーザー エクスペリエンスの流動性の維持です。

    API ON TOP OF AN OBJECT DB

    Node.js はリアルタイム アプリケーションで本当に輝きますが、オブジェクト DB(たとえば MongoDB)からデータをエクスポーズするのに極めて自然に適合しています。 たとえば、Rails を使用している場合、JSON からバイナリ モデルに変換し、React.js や Angular.js などでデータが消費されるとき、あるいは、通常の jQuery AJAX 呼び出しで、HTTP で JSON としてそれらを再度公開することが考えられます。 Node.jsでは、クライアントが消費するために、REST APIでJSONオブジェクトを公開するだけでよいのです。 さらに、(MongoDBを使用している場合)データベースから読み書きするときに、JSONとそれ以外のものの間の変換を心配する必要はありません。 要約すると、クライアント、サーバー、およびデータベースで統一されたデータ シリアライズ形式を使用することにより、複数の変換の必要性を回避できます。

    QUEUED INPUTS

    大量の同時データを受信する場合、データベースがボトルネックとなることがあります。 上に描いたように、Node.js は並行接続自体を簡単に処理できます。 しかし、データベースへのアクセスは(この場合)ブロック操作であるため、トラブルに見舞われます。 解決策は、データが本当にデータベースに書き込まれる前に、クライアントの動作を確認することです。

    このアプローチにより、システムは高負荷下で応答性を維持し、特にクライアントがデータの書き込みが成功したことをしっかり確認する必要がない場合に便利です。 典型的な例としては、バッチで処理され、後日まで使用されないユーザー追跡データのログまたは書き込み、および(Facebook の「いいね」カウントの更新のように)瞬時に反映する必要のない操作で、最終的な一貫性(NoSQL の世界でよく使用されます)が許容される場合です。 RabbitMQ、ZeroMQ など) を通してキューに入れられ、別のデータベース バッチライト プロセスや、そのようなタスクのために性能の良いプラットフォームで書かれた、計算集約型処理のバックエンド サービスによって消化されます。 同様の動作は、他の言語/フレームワークでも実装できますが、同じハードウェア上ではなく、同じように高いスループットを維持します。

    画像は元記事から取られました。

    要するに、Node を使用すると、データベースの書き込みを横に追いやって、後でそれを処理し、成功したかのように進行することができます。 この観察は、Node.NET で利用することができます。jsを使用して、いくつかのクールな機能を構築しています。 例えば、データがストリームで送られてくるので、アップロード中にファイルを処理することが可能で、オンライン方式で処理することができます。 これは、リアルタイムのオーディオまたはビデオ エンコード、および異なるデータ ソース間のプロキシ処理 (次のセクションを参照) のために行うことができます。

    PROXY

    Node.js は、ノンブロッキングで大量の同時接続を処理できるサーバー サイド プロキシとして容易に採用されます。 たとえば、サードパーティのリソースと通信するサーバー側アプリケーション、異なるソースからデータを取り込む、またはサードパーティのクラウド サービスに画像や動画などのアセットを保存する、といった場合を考えてみましょう。 これは、アセットおよびプロキシ/スタブ API リクエスト用に Node.js 開発サーバーを使用してクライアント側アプリを構築し、実運用環境では専用のプロキシ サービス (nginx、HAProxy など) でそのようなインタラクションを処理できることを意味します。 デスクトップ ソフトウェアが主流でありながら、リアルタイムの Web ソリューションに簡単に置き換えることができるもう 1 つの例は、ブローカーのトレーディング ソフトウェアで、株価の追跡、計算/テクニカル分析の実行、およびグラフ/チャートの作成に使用されています。 まもなく、フロリダやイビサ、バリなどのビーチで彼らを見かけるようになるかもしれません。

    APPLICATION MONITORING DASHBOARD

    Node with Web-socket が完全に適合するもうひとつの一般的な使用例は、Web サイト訪問者の追跡とリアルタイムでのインタラクションの視覚化です。 ユーザーからリアルタイムの統計情報を収集したり、訪問者がファネルの特定のポイントに到達したときに通信チャネルを開くことにより、ターゲット インタラクションを導入して次のレベルに移行することもできます – この例は CANDDi.

    もし訪問者がリアルタイムで何をしているかを知っていれば、ビジネスを改善できることを想像してください – 彼らの相互作用を視覚化できれば。 Node.js のリアルタイムの双方向ソケットを使えば、それが可能になります。

    SYSTEM MONITORING DASHBOARD

    さて、次はインフラ側の話をしましょう。 たとえば、SaaS プロバイダーがユーザーにサービス監視ページ (たとえば、GitHub のステータス ページ) を提供することを想像してみてください。 Node.js のイベント ループを使用すると、サービスのステータスを非同期でチェックし、websocket を使用してデータをクライアントにプッシュする、強力な Web ベースのダッシュボードを作成することができます。 このアイデアをもう少し推し進め、通信事業者、クラウド/ネットワーク/ホスティング プロバイダー、または金融機関のアプリケーションを監視するネットワーク オペレーション センター (NOC) を想像してみてください。 そのクラスのアプリケーションには、おそらく Erlang がより良い選択となるでしょう。

    SERVER-SIDE WEB APPLICATIONS

    Node.js と Express.js は、サーバー側でクラシック WEB アプリケーションを作成するために使用することも可能です。 しかし、可能ではありますが、Node.js がレンダリングされた HTML を持ち歩くようなこのリクエスト/レスポンス パラダイムは、最も典型的なユースケースとは言えません。 このアプローチには、賛否両論あります。

    Pros:

    • アプリケーションに CPU 集中型の計算がない場合、Javascript でトップからボトムまで、MongoDB などの JSON 保存オブジェクト DB を使用する場合はデータベース レベルまで構築することができます。 これは、たとえば Node.js の上で実行されるシングル ページ アプリケーションや Web ソケット アプリケーションよりもはるかに SEO フレンドリーです。

    Cons:

    • あらゆる CPU 集中型の計算により Node.js 応答性が妨げられるため、スレッド プラットフォームが良いアプローチとなります。 あるいは、計算をスケールアウトしてみてください。
    • Node.js をリレーショナル データベースで使用するのは、まだかなり困難です (詳細は以下を参照してください)。 自分自身のために、リレーショナルな操作を実行しようとするなら、Rails、Django、または ASP.Net MVC のような他の環境を選んでください。

    (*) CPU 集中型計算の代替案は、Node をクライアントからのリクエストを非同期に処理するフロント面の「書記」として保つためにバックエンド処理で非常に拡張性の高い MQ-backed 環境を作成することです。

    SERVER-SIDE WEB APPLICATION WITH A RELATIONAL DATABASE BEHIND

    Node.js と Express.js と Ruby on Rails を比較すると、たとえばリレーショナル データ アクセスに関しては後者を支持する明確な決定がなされます。 一方、Rails は、DB スキーマ移行サポート ツールやその他の逸品 (ダジャレ) とともに、箱から出してすぐにデータ アクセス設定を自動で提供します。 Rails とその仲間のフレームワークには、成熟し証明された Active Record や Data Mapper データ アクセス レイヤーの実装があり、純粋な JavaScript でそれらを再現しようとすると、かなり失敗します。 (*)

    それでも、本当に JS のままでいたい場合は、Sequelize と Node ORM2 をチェックしてみてください。

    (*) Rails バックエンドとリレーショナル DB への容易なアクセスを維持しながら、公衆向けのファサードとしてのみ Node.js を使用することは可能であり、珍しいことではありません。 いいえ、Node.js でフィボナッチ計算サーバーを構築することは絶対にお勧めしません。 一般に、CPU 集中型の操作は、Node がイベント駆動型、ノンブロッキング I/O モデルで提供するすべてのスループットの利点を無効にしてしまいます。 マルチコア サーバー上で並行処理を追加する場合、クラスタ モジュールの形で Node コア チームによっていくつかの作業が行われています。 4281>

    クラスタリングでは、すべての重い計算をより適切な環境で書かれたバックグラウンド処理にオフロードし、RabbitMQ のようなメッセージ キュー サーバー経由で通信させる必要があります。 もちろん、他のプラットフォームでも同じようなアプローチを使用しますが、Node.NET では、Node.NET を使用することで、Node.NET を使用することで、Node.NET を使用することで、Node.NET を使用することで、他のプラットフォームを使用することなく、簡単に別のワーカー サーバーへ分散させることができます。

    おわりに

    Node.js を理論から実践まで、その目標と野心から始まり、スイートスポットと落とし穴で終わるまで説明してきました。 Node で問題に遭遇したとき、それはほとんどいつも、ブロック操作がすべての悪の根源であるという事実に帰結します。 Node.js は、計算スケーリングの問題を解決するために作成されたわけではありません。 それは I/O スケーリングの問題を解決するために作成され、それは本当によくできています。