Node.js は、同時接続を処理し、高性能アプリケーションを強化する機能で知られ、過去 10 年にわたって開発者にとって頼りになるソリューションになりました。リッチ テキスト エディターを使用して Express プロジェクトに取り組んだ経験から、Node.js がコンテンツ作成アプリケーションをスケーラブルでカスタマイズ可能なソリューションにどのように変換できるかを直接見てきました。しかし、ここに大きな疑問があります。Node.js はエンタープライズ レベルで数百万のユーザーをサポートできるように本当に拡張できるのでしょうか?
答えは「はい」ですが、現実はさらに微妙です。 Node.js は拡張できるように設計されていますが、大規模なパフォーマンスはアプリケーション アーキテクチャ、最適化、システム リソースの管理アプローチに大きく依存します。
高トラフィックの処理に関しては、Node.js は賞賛されると同時に懐疑的な見方もされることがよくあります。一部の開発者は、これはリアルタイム アプリケーションにとって大変革だと主張していますが、他の開発者は、数百万のユーザーに拡張する場合には限界があると主張しています。一般的な通説を見てみましょう:
現実: Node.js はイベント駆動型のノンブロッキング I/O モデルに基づいて構築されており、実際に何千もの同時接続を簡単に管理できます。リクエストごとに新しいスレッドを作成し、すぐにリソースを消費する従来のサーバー アーキテクチャ (Apache、PHP) とは異なり、Node.js は単一のスレッドで動作し、イベント ループを使用してタスクを非同期に処理します。この正確な設計により、リソースの使用量が最小限に抑えられ、スケーラビリティが向上します。
現実: Node.js は JavaScript 上で実行されますが、その能力は JavaScript を最適化されたマシン コードにコンパイルする Google の V8 JavaScript エンジンから来ています。これは、Node.js が単にスクリプトを実行しているだけではなく、多くのユースケースでコンパイル言語に匹敵するパフォーマンスを提供していることを意味します。
現実: Node.js のアーキテクチャは、API サーバー、チャット アプリ、リアルタイム システムなどの I/O 負荷の高いタスクに最適ですが、数百万のユーザーに拡張するには慎重な計画が必要です。正しいアーキテクチャ。負荷分散、クラスタリング、システム リソースの最適化などの技術が、大規模に動作させる鍵となります。
神話の誤りを暴いた後は、事実について話しましょう。 Node.js は、高性能でスケーラブルなアプリケーションを強化できることを証明していますが、数百万のユーザーに拡張するには課題がないわけではありません。
Node.js のアーキテクチャの基礎から始めましょう。シングルスレッドのイベント駆動モデルは I/O タスクに最適であり、複数の接続を同時に処理する際に効率的になります。ただし、CPU を集中的に使用する操作になると、この同じモデルがボトルネックになる可能性があります。単一スレッドで大量の計算を行うとイベント ループがブロックされ、他のリクエストの処理に遅れが生じる可能性があります。
シングルスレッドには制限がありますが、Node.js はノンブロッキング I/O により複数の接続を同時に処理することにも優れていることを覚えておく必要があります。シングルスレッド モデルの制限に対処するには、アプリケーションのアーキテクチャに応じて、ワーカー スレッドまたはマイクロサービスを使用して、CPU 集中型のタスクをオフロードできます。
アプリケーションが成長するにつれて、リソースの管理がますます重要になります。実際、メモリ リークは、成長する Node.js アプリケーションにとって大きな問題になる可能性があります。これらは、オブジェクトや変数などのリソースが適切にクリーンアップされない場合に発生します。これにより、時間の経過とともに、特にトラフィックが急増した場合に、すべての速度が低下したり、サーバーがクラッシュしたりすることがあります。
Adidas は、Node.js システムでメモリ リークに直面し、ユーザー ベースが拡大するにつれてパフォーマンスの問題が発生しました。 Adidas のソフトウェア エンジニアリング ディレクターである Aleksandar Mirilovic は、Node.js アプリケーションで運用メモリ リークを見つける方法 というタイトルの記事で自身の経験を共有しました。彼は、オブジェクトがメモリ内に不必要に保持されており、それがリソースの肥大化につながっていることを発見しました。
TL;DR: ローカルおよびステージングで問題を再現しようとして失敗した後、Adidas は運用環境から直接ヒープ スナップショットをキャプチャしました。根本原因は、リクエストごとに新しい gRPC 接続を閉じずに作成する Google reCAPTCHA ライブラリにあることが判明しました。単一のクライアント インスタンスを使用するようにコードをリファクタリングすると、問題が修正され、メモリ使用量が安定し、パフォーマンスが向上しました。
I/O とメモリ管理を最適化したら、スケーリングの別の側面、つまりハードウェア使用率を考慮する必要があります。デフォルトでは、Node.js は単一スレッドで実行されます。これは、使用可能なすべての CPU コアを自動的に利用するわけではないことを意味します。 トラフィックの多いアプリの場合、サーバーの処理能力の多くが使用されなくなる可能性があるため、これが問題になる可能性があります。多くの開発者はこのことに気づいておらず、クラスタリングなどを設定しないとハードウェアを最大限に活用できません。
Node.js クラスター モジュールを使用すると、アプリケーションの複数のインスタンスを実行し、各インスタンスを個別の CPU コアで実行できます。これにより、使用可能なすべてのコアにワークロードが分散されるため、アプリはより多くの同時ユーザーを処理できるようになり、パフォーマンスが向上します。
数百万のユーザーを処理できるように Node.js をスケーリングすることは、効率的なコードを書くだけではなく、ユーザー ベースに応じて成長できるインフラストラクチャを構築することも意味します。
単一サーバーで処理できる処理量には限界があります。これはハードウェアの制限によるものです。ここで負荷分散が役に立ちます。トラフィックを複数のサーバーに分散することで、ボトルネックを防ぎ、アプリの応答性を維持できます。これがないと、トラフィックの急増時にダウンタイムが発生したり、パフォーマンスが低下したりする危険があります。
最近の例を考えてみてください。ChatGPT ユーザーがクラッシュにイライラしたり、Amazon の買い物客が商品ページの代わりにかわいい犬の写真で出迎えられたりしました。負荷分散により、需要の急増時にもスムーズな動作が保証されます。 NGINX、HAProxy、AWS Elastic Load Balancer などのツールを使用すると、リクエストを Node.js インスタンス全体に均等に分散できるため、パフォーマンスが向上し、冗長性が追加されるため、サーバーがダウンしてもアプリはオンラインを維持できます。
データベースまたは外部 API から同じデータを繰り返しフェッチすると、アプリの速度が低下し、バックエンド リソースに負担がかかる可能性があります。キャッシュは、頻繁に要求されるデータをメモリに保存することでこの問題を解決し、アプリが汗をかくことなくより高速な応答を提供し、より多くのトラフィックを処理できるようにします。 Redis や Memcached などのツールは、ここで大きな変革をもたらすものであり、実際の例は、キャッシュがいかに影響力を持つかを示しています。
業界全体で Redis がどのように使用されているか:
電子商取引: Gap Inc. は、Redis Enterprise を統合することで、買い物客をイライラさせる遅い在庫更新に取り組みました。これにより、ブラック フライデーの大規模なトラフィック急増時でも、遅延が軽減され、リアルタイムの在庫情報が提供されました。
不正検出: デジタル ID 企業である BioCatch は、Redis Enterprise を使用して毎月 50 億件のトランザクションを処理しています。行動データと API 応答をキャッシュすることで、不正行為を 40 ミリ秒未満で検出し、サイバー脅威の先を行きます。
キャッシュは速度だけを目的とするものではありません。キャッシュにより信頼性が向上し、バックエンドの負荷が軽減され、カート放棄が防止されます。
キャッシュが設置されている場合でも、トラフィックの多いアプリケーションの弱点は、多くの場合データベース操作です。非効率的なクエリや構造の設計が不十分であると、すべてが遅くなり、ユーザーがイライラし、アプリが追いつくのに苦労する可能性があります。キャッシュは頻繁なリクエストを高速化するのに最適ですが、特にトラフィックが増加すると、データベースは残りの作業を効率的に処理する必要があります。
高トラフィックをより効率的に処理するには、データベースにいくつかの重要な改善を加えることができます。まず、クエリの微調整に重点を置きます。これは、SQL ステートメントを簡素化し、不要な操作を削除し、インデックスを追加して処理を高速化することを意味します。
たとえば、アプリが user_id を頻繁に検索する場合、その列にインデックスを追加すると、データベースがその列をより速く検索できるようになります。次に、アプリが送信するクエリの数を減らします。ユーザーの詳細と注文を個別にリクエストするのではなく、結合を使用してそれらを 1 つのクエリに結合します。アプリが大量のトラフィックを処理する場合は、シャーディング (スキーマ アーキテクチャをより小規模で焦点を絞ったデータに分割する) するか、リードレプリカを設定して大量の読み取り操作の負荷を共有することによってスケールする必要があります。
それはすでに世界最大のプラットフォームのいくつかに電力を供給しています。 LinkedIn は Ruby on Rails から Node.js に移行し、6 億人を超えるユーザーをサポートしながらサーバー数を 20 倍に削減しました。 Netflix は Node.js を利用して数百万の同時ストリームを管理し、読み込み時間を短縮します。 Uber のエンジニアリング スタックは、リアルタイム機能を使用して、大量の配車リクエストをシームレスに処理します。そしてウォルマートは、ブラック フライデーの激しいトラフィック急増中にシステムをスムーズに実行し続けるために Node.js を利用しました。
負荷分散、キャッシュ、データベースの最適化などの戦略により、Node.js は最も要求の厳しいワークロードでも処理できます。グローバル プラットフォームを構築している場合でも、トラフィックの増加に合わせてスケールアップしている場合でも、Node.js を使用すると、高速で信頼性が高く、スケーラブルなアプリケーションを真に作成できると確信しています。
以上がNode.js アプリをスケールするための行動、戦略の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。