Good practices for high-performance and scalable Node.js applications [Part 3/3]をgoogle翻訳します。

Chapter 3Additional good practices for efficiency and performance(効率とパフォーマンスのための追加のグッドプラクティス)

このシリーズの最初の2つの記事では、Node.jsアプリケーションをスケールする方法と、このプロセス中に期待どおりに動作させるためにコード側で検討するものを見ました。

Web and Worker processes(WebプロセスとWorkerプロセス)

ご存じのように、Node.jsは実際にはシングルスレッドなので、プロセスの1つのインスタンスは一度に1つのアクションしか実行できません。。 Webアプリケーションのライフサイクルでは、API呼び出しの管理、DBへの読み取り/書き込み、外部ネットワークサービスとの通信、不可避的なCPU集約的な作業の実行など、さまざまなタスクが実行されます。

非同期プログラミングを使用しても、これらのアクションをすべてAPI呼び出しに応答する同じプロセスに委任することは、非常に非効率的なアプローチになります。

般的なパターンは、アプリケーションを構成する2つの異なる種類のプロセス(通常はWebプロセスとワーカープロセス)間の責任の分離に基づいています。

Webプロセスは、着信ネットワークコールを主に管理し、できるだけ早くそれらをディスパッチするように設計されています。電子メール/通知の送信、ログの書き込み、API呼び出しに応答する必要のないトリガーアクションの実行など、非ブロッキングタスクを実行する必要があるときはいつでも、Webプロセスはそのアクションをワーカー1に委譲します。

Webプロセスとワーカープロセス間の通信は、さまざまな方法で実装できます。一般的で効率的なソリューションは、次の段落で説明するKue(https://automattic.github.io/kue/)に実装されているような優先キューです。

このアプローチの大きな利点の1つは、同じマシン上または異なるマシン上で、Webプロセスとワーカープロセスを独立してスケーリングできることです。

たとえば、アプリケーションのトラフィックが多く、副作用がほとんど発生していない場合は、ワーカー・プロセスよりも多くのWebプロセスをデプロイできます。一方、ワーカーのために多くのジョブを生成するネットワーク要求が少ない場合は、それに応じてリソースを再配布することができます。

Kue

Webプロセスとワーカープロセスを互いに対話させるために、キューは柔軟なアプローチであり、プロセス間通信について心配する必要はありません。

KueはNode.jsの一般的なキューライブラリで、Redisをベースにしており、まったく同じ方法で同じマシンまたは別のマシンに生成された通信プロセスを入れることができます。

どのような種類のプロセスでも、ジョブを作成してキューに入れることができます。次に、これらのジョブを選択して実行するようにワーカープロセスが構成されます。優先度、TTL、遅延など、各ジョブに多数のオプションを提供できます。

作成したワーカープロセスが多いほど、これらのジョブを実行するために必要な並列処理量は増えます。

Cron

アプリケーションでは、定期的に実行する必要のあるタスクを持つのが一般的です。通常、この種の操作は、アプリケーションの外部から単一のスクリプトが呼び出されるOSレベルのcronジョブによって管理されます。

このアプローチでは、新しいマシンにアプリケーションをデプロイするときに余分な作業が必要になるため、デプロイを自動化したい場合はプロセスが不快になります。

同じ結果を達成するより快適な方法は、NPMで入手可能なcronモジュールを使用することです。Node.jsコードの中でcronジョブを定義し、OSの設定とは無関係にします。

上記のweb / workerパターンによれば、ワーカープロセスはcronを作成することができ、cronはキューに新しいジョブを定期的に投入する関数を呼び出します。

キューを使用すると、よりクリーンになり、優先順位、再試行などkueが提供するすべての機能を利用できます。

cron関数はすべてのプロセスで同時にアプリケーションを起動させ、何度も実行される同じジョブの重複をキューに入れてしまうため、複数のワーカープロセスがあるときに問題が発生します。

この問題を解決するには、cron操作を実行する単一のワーカープロセスを特定する必要があります。

Leader election and cron-cluster

この種の問題は、「Leader election」として知られています。この特定のシナリオには、cron-clusterと呼ばれる私たちの手口を担当するNPMパッケージがあります。
これは、cronモジュールに動力を与える同じAPIを公開しますが、セットアップ中に他のプロセスと通信してリーダー選出アルゴリズムを実行するために使用されるredis接続が必要です。

本当に単一のソースとしてredisを使用すると、すべてのプロセスがcronを実行する人に同意し、ジョブのコピーが1つだけキューに入れられます。その後、すべてのワーカープロセスはいつものようにジョブを実行する資格があります。

Caching API calls(APIキャッシュ呼び出し)

サーバー側のキャッシュは、API呼び出しのパフォーマンスと反応性を向上させるための一般的な方法ですが、実現可能な実装が非常に広いトピックです。

このシリーズで説明したような分散環境では、すべてのノードを同じように動作させるために、キャッシュされた値を格納するためにredisを使用するのがおそらく最良のアプローチです。

キャッシングで考慮する最も難しい側面は、無効化です。クイックダーティーソリューションは時間のみを考慮しているため、キャッシュ内の値は固定TTL後にフラッシュされ、応答の更新を確認するために次回のフラッシュを待たなければならないという欠点があります。

費やす時間がある場合は、アプリケーションレベルで無効化を実装し、DB上の値が変更されたときに、レディスキャッシュのレコードを手動でフラッシュすることをお勧めします。

Conclusions(結論)

このシリーズの記事では、スケーリングとパフォーマンスに関する一般的な話題を取り上げました。提供された提案は、プロジェクトの特定のニーズに合わせてカスタマイズする必要があるガイドラインとして使用できます。

Node.jsとDevOpsの垂直トピックに関する他の記事をお楽しみください!