Good practices for high-performance and scalable Node.js applications [Part 2/3]を翻訳する。
※ほとんどgoogle翻訳です。

Part1 は こちら

Chapter 2How to make your Node.js app ready to scale(Node.jsアプリケーションを拡大縮小する準備をする方法)

前回の記事では、コードを気にすることなく、Node.jsアプリケーションを水平にスケーリングする方法を見てきました。今回は、プロセスをスケールアップするときに望ましくない動作を防ぐために考慮する必要があるいくつかの側面について説明します。

Decouple application instances from DB(DBからアプリケーションインスタンスを切り離す)

最初のヒントは、コードについてではなく、インフラストラクチャについてです。

アプリケーションを異なるホスト間で拡張できるようにするには、データベースを独立したマシンに配置する必要があります。そのため、アプリケーション・マシンを自由に複製できます。

同じマシンにアプリケーションとデータベースをデプロイすることは手軽に、開発目的で使用することができます。アプリケーションとデータベースが独立して拡張可能でなければならない本番環境では、絶対に推奨されません。 Redisのようなメモリ内のデータベースにも同じことが当てはまります。

Be stateless (ステートレスにする)

アプリケーションの複数のインスタンスを生成する場合、各プロセスには独自のメモリ空間があります。つまり、単一のマシン上で実行していても、グローバル変数に値を格納したり、メモリー内のセッションを保存すると、次の要求時にバランサが別のプロセスにリダイレクトしても、それを見つけることはできません。

これは、セッションデータと内部値の両方に適用されます。

実行時に変更可能な設定や構成については、すべてのプロセスがアクセス可能にするために、それらを外部データベース(記憶域またはインメモリー)に格納することが解決策です。

Stateless authentication with JWT(JWTによるステートレス認証)

認証は、ステートレスアプリケーションを開発する際に考慮すべき最初のトピックの1つです。セッションをメモリに保存すると、それらのセッションにスコープが設定されます。

作業を進めるには、同じユーザーを常に同じマシンにリダイレクトするようにネットワーク負荷分散装置を構成する必要があります。同じユーザーを常に同じプロセス(sticky sessions)にリダイレクトするためにローカルのものを使用します。

この問題に対する些細な解決策は、セッションのストレージ戦略を永続性の任意の形式に設定することです。たとえば、RAMの代わりにDBに格納するなどです。しかし、アプリケーションが各リクエストでセッションデータをチェックすると、すべてのAPI呼び出しでディスクI / Oが発生しますが、パフォーマンスの観点からはよくありません。

あなたの認証フレームワークがそれをサポートしているなら、より速く、より速い解決策はRedisのようなメモリ内のDBにセッションを保存することです。Redisインスタンスは、通常、DBインスタンスのようなアプリケーションインスタンスの外部にありますが、メモリ内で作業すると、はるかに高速になります。とにかくRAMにセッションを格納すると、同時セッション数が増えるとさらに多くのメモリが必要になります。

ステートレス認証のより効率的なアプローチを採用したい場合は、JSON Web Tokenを見ることができます。

JWTの背後にあるアイデアは非常に簡単です。ユーザーがログインすると、サーバーはトークンを生成します。トークンは基本的に、ペイロードを含むJSONオブジェクトのBase64エンコードと、そのペイロードをサーバーが所有する秘密鍵でハッシュした署名を生成します。ペイロードには、ユーザーIDとそれに関連付けられたACLロールなど、ユーザーを認証および認可するために使用されるデータを含めることができます。トークンはクライアントに送り返され、すべてのAPI要求の認証に使用されます。

サーバーが着信要求を処理すると、サーバーはトークンのペイロードを受け取り、その秘密鍵を使用して署名を再作成します。2つの署名が一致する場合、ペイロードは有効とみなされ、変更されず、ユーザを識別することができる。

JWTはいかなる形式の暗号化も提供していないことを覚えておくことが重要です。ペイロードはbase64でのみエンコードされ、クリアテキストで送信されるため、コンテンツを非表示にする必要がある場合はSSLを使用する必要があります。jwt.ioによって借用された次のスキーマは、認証プロセスを再開します。

認証プロセスの間、サーバはどこかに格納されたセッションデータにアクセスする必要はなく、各要求は非常に効率的な方法で異なるプロセスまたはマシンによって処理されることができます。RAMにはデータは保存されず、ストレージI / Oを実行する必要もないため、この手法は大規模になると非常に便利です。

Storage on S3 (S3上のストレージ)

複数のマシンを使用する場合、ユーザー生成資産をファイルシステムに直接保存することはできません。ファイルには、そのサーバーのローカルプロセスのみがアクセスできるからです。解決策は、おそらくAmazon S3のような専用サービスにすべてのコンテンツを外部サービスに格納し、そのリソースを指し示す絶対URLだけをDBに保存することです。


すべてのプロセス/マシンは同じ方法でそのリソースにアクセスします。

Node.js用の公式のAWS sdkを使用することは非常に簡単で、特別な努力なしにアプリケーションをアプリケーションの中に統合することができます。S3は非常に安く、この目的のために最適化されているため、アプリが複数のプロセスでない場合にも適しています。

Properly configure WebSockets(適切にWebSocketsを設定する)

アプリケーションがWebSocketを使用してクライアント間またはクライアントとサーバー間でリアルタイムの対話を行う場合、ブロードキャストメッセージ、または異なるノードに接続されたクライアント間のメッセージを正しく伝播するために、バックエンドインスタンスをリンクする必要があります。

Socket.ioライブラリには、この目的のための特別なアダプタsocket.io-redisがあり、Redis pub-sub機能を使用してサーバーインスタンスをリンクすることができます。

マルチノードのsocket.io環境を使用するには、長いポーリングでスティッキーセッションが動作する必要があるため、プロトコルを強制的に "websockets"にする必要があります。

Next steps

この短い記事では、Node.jsアプリケーションを拡張したい場合に気を付けるべき簡単な要素をいくつか見てきました。これは、単一ノード環境でも良い方法と見なすことができます。

この小さなシリーズの次の最後の記事では、アプリケーションのパフォーマンスを向上させるためのパターンをいくつか見ていきます。ここ(https://medium.com/iquii/good-practices-for-high-performance-and-scalable-node-js-applications-part-3-3-c1a3381e1382) で見つけることができます。