ブログ | NGINX

Node.js アプリケーションのパフォーマンス向上のための 5 つのヒント

NGINX-F5 水平黒タイプ RGB の一部
フロイド・スミス サムネイル
フロイド・スミス
2015 年 11 月 16 日公開
#nginx がノード サーバーの前にない場合は、おそらくやり方が間違っています。

Node.js は、世界で最も人気のあるプログラミング言語である JavaScript でサーバー アプリケーションを作成するための主要なツールです。 Node.js は、Web サーバーとアプリケーション サーバーの両方の機能を提供しており、現在ではあらゆる種類のマイクロサービス ベースの開発と配信にとって重要なツールと見なされています。 ( Node.js と NGINX に関する無料の Forrester レポートをダウンロードしてください。)

Node.js は、バックエンド アプリケーション開発において Java または .NET を置き換えたり、補完したりすることができます。

Node.js はシングルスレッドであり、非ブロッキング I/O を使用するため、数万の同時操作を拡張してサポートできます。 これらのアーキテクチャ特性は NGINX と共有されており、NGINX も解決するために発明されたC10K 問題 (10,000 を超える同時接続のサポート) を解決します。 Node.js は、高いパフォーマンスと開発者の生産性でよく知られています。

それで、何が問題になる可能性があるのでしょうか?

Node.js にはいくつかの弱点と脆弱性があり、Node.js ベースのシステムのパフォーマンスが低下したり、クラッシュしたりする可能性があります。 Node.js ベースの Web アプリケーションでトラフィックが急増すると、問題が頻繁に発生します。

また、Node.js は、Web ページのコアとなる可変コンテンツを生成するアプリケーション ロジックを作成および実行するための優れたツールです。 しかし、画像や JavaScript ファイルなどの静的コンテンツを提供したり、複数のサーバー間で負荷分散したりするには、あまり適していません。

Node.js を最大限に活用するには、静的コンテンツをキャッシュし、複数のアプリケーション サーバー間でプロキシと負荷分散を行い、クライアント、Node.js、および Socket.IO を実行するサーバーなどのヘルパー間のポート競合を管理する必要があります。 NGINX はこれらすべての目的に使用できるため、Node.js のパフォーマンス チューニングに最適なツールとなります。

Node.js アプリケーションのパフォーマンスを向上させるには、次のヒントを参考にしてください。

  1. リバースプロキシサーバーを実装する
  2. 静的ファイルをキャッシュする
  3. 複数のサーバー間でトラフィックを負荷分散する
  4. プロキシWebSocket接続
  5. SSL/TLSとHTTP/2を実装する

注記: Node.js アプリケーションのパフォーマンスを素早く改善するには、Node.js 構成を変更して、最新のマルチコア サーバーを活用することです。 Node.js のドキュメントを参照して、Web サーバー上の CPU の数と同じ数の個別の子プロセスを Node.js で生成する方法を確認してください。 すると、各プロセスは魔法のように 1 つの CPU のみに配置され、パフォーマンスが大幅に向上します。

ヒント 1 – リバースプロキシサーバーを実装する

NGINX, Inc. では、高性能サイトの中核で使用されているアプリケーション サーバーがインターネットの受信トラフィックに直接さらされているのを見ると、いつも少し恐怖を感じます。 これには、たとえば、多くのWordPress ベースのサイトや Node.js サイトが含まれます。

Node.js は、ほとんどのアプリケーション サーバーよりもスケーラビリティを重視して設計されており、Web サーバー側では大量のインターネット トラフィックを適切に処理できます。 しかし、Web サービスは Node.js の存在理由ではありません。Node.js が本来目的としていたものではありません。

トラフィック量の多いサイトの場合、アプリケーションのパフォーマンスを向上させる最初のステップは、Node.js サーバーの前にリバース プロキシ サーバーを配置することです。 これにより、Node.js サーバーがインターネット トラフィックに直接さらされることが防止され、複数のアプリケーション サーバーの使用、サーバー間の負荷分散、コンテンツのキャッシュにおいて大きな柔軟性が得られます。

NGINX をリバース プロキシ サーバーとして既存のサーバー セットアップの前に配置して、追加の用途に使用することは、世界中の何千万もの Web サイトで実装されている NGINX の中心的な使用例です。

NGINX を Node.js リバース プロキシ サーバーとして使用すると、次のような具体的な利点があります。

  • 権限処理とポート割り当ての簡素化
  • 静的画像をより効率的に提供する(次のヒントを参照)
  • Node.jsのクラッシュを正常に管理する
  • DoS攻撃の緩和

注記: これらのチュートリアルでは、 Ubuntu 14.04またはCentOS環境で NGINX をリバース プロキシ サーバーとして使用する方法について説明しており、Node.js の前に NGINX を配置するすべてのユーザーにとって役立つ概要となります。

ヒント 2 – 静的ファイルをキャッシュする

Node.js ベースのサイトの使用が増えると、サーバーに負担がかかり始めます。 この時点で実行したいことが 2 つあります。

  1. Node.jsサーバーを最大限に活用する
  2. アプリケーションサーバーの追加とそれらの間の負荷分散を簡単にする

これは実際に簡単に実行できます。 前のヒントで説明したように、まず NGINX をリバース プロキシ サーバーとして実装します。 これにより、キャッシュ、負荷分散 (複数の Node.js サーバーがある場合) などを簡単に実装できます。

アプリケーション コンテナ プラットフォームである Modulus の Web サイトには、NGINX を使用して Node.js アプリケーションのパフォーマンスを大幅に向上させる方法に関する役立つ記事があります。Node.js がすべての作業を独自に実行することで、著者のサイトは平均して 1 秒あたり約 900 件のリクエストを処理できるようになりました。 NGINX をリバース プロキシ サーバーとして使用して静的コンテンツを提供することで、同じサイトが 1 秒あたり 1,600 件を超えるリクエストを処理できるようになりました。これは、パフォーマンスがほぼ 2 倍向上したことを意味します。

パフォーマンスを 2 倍にすることで、サイト設計の見直し (場合によっては改善)、アプリケーション コードの最適化、追加のアプリケーション サーバーの導入など、さらなる成長に対応するための追加手順を実行する時間が生まれます。

以下は、Modulus で実行されている Web サイトで機能する構成コードです。

server { listen 80;
server_name static-test-47242.onmodulus.net;

root /mnt/app;
index index.html index.htm;

location /static/ {
try_files $uri $uri/ =404;
}

location /api/ {
proxy_pass http://node-test-45750.onmodulus.net;
}
}

NGINX, Inc. の Patrick Nommensen によるこの詳細な記事では、Node.js アプリケーションである Ghost オープンソース ブログ プラットフォームで実行される個人ブログから静的コンテンツをキャッシュする方法を説明しています。 一部の詳細は Ghost に固有のものですが、コードの多くを他の Node.js アプリケーションで再利用できます。

たとえば、NGINX のロケーションブロックでは、一部のコンテンツをキャッシュから除外したい場合があります。 たとえば、通常はブログ プラットフォームの管理インターフェイスをキャッシュする必要はありません。 Ghost 管理インターフェースのキャッシュを無効にする (または除外する) 構成コードを次に示します。

location ~ ^/(?:ghost|signout) { proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://ghost_upstream;
add_header Cache-Control "no-cache, private, no-store,
must-revalidate, max-stale=0, post-check=0, pre-check=0";
}

静的コンテンツの提供に関する一般的な情報については、 NGINX Plus 管理者ガイドを参照してください。 管理者ガイドには、構成手順、ファイルの検索が成功または失敗した場合の複数の応答オプション、さらに高速なパフォーマンスを実現するための最適化アプローチが含まれています。

NGINX サーバー上の静的ファイルのキャッシュにより、Node.js アプリケーション サーバーの作業負荷が大幅に軽減され、より高いパフォーマンスを実現できます。

ヒント3 – Node.jsロードバランサーを実装する

Node.js アプリケーションで高い (つまり、ほぼ無制限の) パフォーマンスを実現するための本当の鍵は、複数のアプリケーション サーバーを実行し、それらすべてにわたって負荷を分散することです。

Node.js では、Web ブラウザーで実行される JavaScript コードと Node.js アプリケーション サーバーで実行される JavaScript コードの間で、JSON オブジェクトをデータ交換の媒体として高度なやり取りが可能になるため、Node.js の負荷分散は特に難しい場合があります。 これは、特定のクライアント セッションが特定のアプリケーション サーバー上で継続的に実行されることを意味し、複数のアプリケーション サーバーでセッションの永続性を実現することは本質的に困難です。

インターネットと Web の主な利点の 1 つは、高度なステートレス性です。これには、要求されたファイルにアクセスできる任意のサーバーによってクライアント要求が満たされる機能が含まれます。 Node.js はステートレス性を覆し、同じサーバーが特定のクライアントからのリクエストに一貫して応答するステートフル環境で最適に動作します。

この要件は、NGINX Open Source ではなく、 NGINX Plusによって最もよく満たされます。 NGINX の 2 つのバージョンは非常に似ていますが、大きな違いの 1 つは、異なる負荷分散アルゴリズムをサポートしていることです。

NGINX はステートレスな負荷分散方式をサポートしています:

  • ラウンドロビン– 新しいリクエストはリスト内の次のサーバーに送られます。
  • 最小接続数– 新しいリクエストは、アクティブな接続が最も少ないサーバーに送信されます。
  • IP ハッシュ- 新しいリクエストは、クライアントの IP アドレスのハッシュが割り当てられたサーバーに送信されます。

これらの方法のうち、IP ハッシュだけが、特定のクライアントのリクエストを同じサーバーに確実に送信し、Node.js アプリケーションにメリットをもたらします。 ただし、負荷分散技術に関するこのブログ投稿で説明されているように、IP ハッシュを使用すると、他のサーバーを犠牲にして、1 つのサーバーが不均衡な数のリクエストを受信する可能性が高くなります。 この方法は、サーバー リソース全体にわたるリクエストの割り当てが最適ではない可能性を犠牲にして、ステートフル性をサポートします。

NGINX とは異なり、NGINX Plus はセッション永続性をサポートします。 セッション永続性を使用すると、特定のクライアントからのすべてのリクエストを同じサーバーが確実に受信します。 クライアントとサーバー間のステートフル通信を実現する Node.js と、高度な負荷分散機能を備えた NGINX Plus の利点が最大限に活用されます。

したがって、NGINX または NGINX Plus を使用して、複数の Node.js サーバー間での負荷分散をサポートできます。 ただし、最大の負荷分散パフォーマンスと Node.js に適したステートフルネスの両方を実現できるのは、NGINX Plus を使用する場合のみです。 NGINX Plus に組み込まれているアプリケーションのヘルスチェック監視機能もここで役立ちます。

NGINX Plus はセッション ドレインもサポートしており、これにより、アプリケーション サーバーは、サーバーがサービスを停止するように要求された後に、現在のセッションを正常に完了できます。

ヒント4 – プロキシWebSocket接続

HTTP は、すべてのバージョンにおいて、クライアントがサーバーからファイルを要求する「プル」通信用に設計されています。 WebSocket は、「プッシュ」および「プッシュ/プル」通信を可能にするツールであり、サーバーはクライアントが要求していないファイルを積極的に送信できます。

WebSocket プロトコルを使用すると、転送されるデータの量を減らし、遅延を最小限に抑えながら、クライアントとサーバー間のより堅牢な相互作用を簡単にサポートできます。 必要に応じて、クライアントとサーバーの両方が必要に応じて要求を開始および受信する全二重接続を実現できます。

WebSocket プロトコルは堅牢な JavaScript インターフェイスを備えているため、アプリケーション サーバーとしての Node.js に最適です。また、中程度のトランザクション量を持つ Web アプリケーションの場合は、Web サーバーとしても最適です。 トランザクション量が増えると、NGINX または NGINX Plus を使用して静的ファイルをキャッシュし、複数のアプリケーション サーバー間で負荷分散を行い、クライアントと Node.js Web サーバーの間に NGINX を挿入することが合理的です。

Node.js は、Node.js アプリケーションと一緒に使用することが非常に一般的になった WebSocket API である Socket.IO と組み合わせて使用されることがよくあります。 これにより、ポート 80 (HTTP の場合) またはポート 443 (HTTPS の場合) が非常に混雑する可能性があります。解決策としては、Socket.IO サーバーにプロキシすることです。 前述のように、プロキシ サーバーにNGINX を使用することができ、静的ファイルのキャッシュ、負荷分散などの追加機能も利用できます。

以下は、ポート 5000 をリッスンする server.js ノード アプリケーション ファイルのコードです。 これはプロキシ サーバー (Web サーバーではありません) として機能し、リクエストを適切なポートにルーティングします。

var io = require('socket.io').listen(5000); 
io.sockets.on('connection', function (socket) {
socket.on('set nickname', function (name) {
socket.set('nickname', name, function () {
socket.emit('ready');
});
});

socket.on('msg', function () {
socket.get('nickname', function (err, name) {
console.log('Chat message by ', name);
});
});
});

index.htmlファイル内に次のコードを追加して、サーバー アプリケーションに接続し、アプリケーションとユーザーのブラウザーの間で WebSocket をインスタンス化します。

<script src="/socket.io/socket.io.js"></script><script>// <![CDATA[
var socket = io(); // ここに初期化コードを記述します。
// ]]>
</script>

NGINX 構成を含む完全な手順については、 Node.js および Socket.IO でのNGINX および NGINX Plus の使用に関するブログ投稿を参照してください。 この種の Web アプリケーションの潜在的なアーキテクチャおよびインフラストラクチャの問題の詳細については、リアルタイム Web アプリケーションと WebSocket に関するブログ投稿を参照してください。

ヒント5 – SSL/TLSとHTTP/2を実装する

サイト上のすべてのユーザー操作を保護するために SSL/TLS を使用するサイトが増えています。 この移行を行うかどうか、またいつ行うかはお客様の判断に委ねられますが、移行を行う場合、NGINX は次の 2 つの方法で移行をサポートします。

  1. NGINX をリバース プロキシとして設定すると、NGINX でクライアントへの SSL/TLS 接続を終了できます。 Node.js サーバーは、NGINX リバース プロキシ サーバーとの間で暗号化されていないリクエストとコンテンツを送受信します。
  2. 初期の兆候では、HTTP プロトコルの新しいバージョンであるHTTP/2を使用すると、SSL/TLS の使用によって課せられるパフォーマンスの低下が大部分または完全に相殺される可能性があることが示されています。 NGINX は HTTP/2 をサポートしており、SSL/TLS とともに HTTP/2 を終了できるため、Node.js アプリケーション サーバーを変更する必要がなくなります。

実行する必要がある実装手順には、Node.js 構成ファイル内の URL の更新、NGINX 構成での安全な接続の確立と最適化、必要に応じて SPDY または HTTP/2 の使用などがあります。 HTTP/2 サポートを追加すると、HTTP/2 をサポートするブラウザー バージョンは新しいプロトコルを使用してアプリケーションと通信するようになります。古いブラウザー バージョンは引き続き HTTP/1.x を使用します。

次の構成コードは、ここで説明されているように、SPDY を使用する Ghost ブログ用です。 OCSP ステープルなどの高度な機能が含まれています。 OCSP ステープル オプションを含む、SSL ターミネーションに NGINX を使用する場合の考慮事項については、ここを参照してください。 同じトピックの一般的な概要については、ここを参照してください。

今すぐ、または 2016 年初頭に SPDY サポートが終了したときに、Node.js アプリケーションを構成し、SPDY から HTTP/2 にアップグレードするには、わずかな変更のみを行う必要があります。

サーバー { server_name domain.com;
listen 443 ssl spdy;
spdy_headers_comp 6;
spdy_keepalive_timeout 300;
keepalive_timeout 300;
ssl_certificate_key /etc/nginx/ssl/domain.key;
ssl_certificate /etc/nginx/ssl/domain.crt;
ssl_session_cache shared:SSL:10m; 
ssl_session_timeout 24h; 
ssl_buffer_size 1400; 
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/trust.crt;
リゾルバー 8.8.8.8 8.8.4.4 valid=300s;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';
add_header X-Cache $upstream_cache_status;

location / {
proxy_cache STATIC;
proxy_cache_valid 200 30m;
proxy_cache_valid 404 1m;
proxy_pass http://ghost_upstream;
proxy_ignore_headers X-Accel-Expires Expires Cache-Control;
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
proxy_hide_header X-powered-by;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header ホスト $http_host;
10 分で期限切れ;
}

location /content/images {
alias /path/to/ghost/content/images;
access_log off;
期限切れ最大;
}

location /assets {
alias /path/to/ghost/themes/uno-master/assets;
access_log off;
期限切れ最大;
}

location /public {
alias /path/to/ghost/built/public;
access_log off;
期限切れ最大;
}

location /ghost/scripts {
alias /path/to/ghost/core/built/scripts;
access_log off;
期限切れ最大;
}

location ~ ^/(?:ghost|signout) {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header ホスト $http_host;
proxy_pass http://ghost_upstream;
add_header Cache-Control "no-cache、private、no-store、
must-revalidate、max-stale=0、post-check=0、pre-check=0";
proxy_set_header X-Forwarded-Proto https;
}
}

結論

このブログ記事では、Node.js アプリケーションで実現できる最も重要なパフォーマンスの向上のいくつかについて説明します。 これは、NGINX をリバース プロキシ サーバーとして使用して、静的ファイルのキャッシュ、負荷分散、WebSocket 接続のプロキシ、SSL/TLS および HTTP/2 プロトコルの終了を行うことにより、Node.js とともにアプリケーション ミックスに NGINX を追加することに重点を置いています。

NGINX と Node.js の組み合わせは、マイクロサービス対応の新しいアプリケーションを作成したり、Java または Microsoft .NET を使用する既存の SOA ベースのアプリケーションに柔軟性と機能を追加したりする方法として広く認識されています。 この投稿は、Node.js アプリケーションを最適化し、必要に応じて Node.js と NGINX のパートナーシップを実現するのに役立ちます。


「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"