Node.js を使用するときに従う 10 のパフォーマンス ルールを次に示します。
1. 同期コードの使用を避ける
仕様上、Node.js はシングルスレッドです。単一のスレッドが多数の同時リクエストを処理できるようにするには、スレッドをブロック操作、同期操作、または長時間実行操作を待機させることはできません。 Node.js の特徴は、非同期実装を実現するために上から下まで設計および実装されることです。これは、イベントベースのプログラムに最適です。
残念ながら、同期/ブロック呼び出しが発生する可能性は依然としてあります。たとえば、writeFile や writeFileSync など、多くのファイル システム操作には同期バージョンと非同期バージョンの両方があります。コードを使用して同期方法を制御した場合でも、呼び出しをブロックする外部関数ライブラリを誤って使用してしまう可能性があります。これを行うと、パフォーマンスへの影響は大きくなります。
// Good: write files asynchronously fs.writeFile('message.txt', 'Hello Node', function (err) { console.log("It's saved and the server remains responsive!"); }); // BAD: write files synchronously fs.writeFileSync('message.txt', 'Hello Node'); console.log("It's saved, but you just blocked ALL requests!");
初期化ログの実装には、内容をディスクに書き込むための同期呼び出しが誤って含まれていました。パフォーマンス テストを行わない場合、この問題は無視されがちです。開発者向けボックスの Node.js インスタンスに対してテストすると、この同期呼び出しによりパフォーマンスが 1 秒あたり数千リクエストからわずか数十リクエストに低下します。
2. ソケットプールを閉じる
Node.js http クライアントは自動的にソケット プーリングを使用します。デフォルトでは、各ホストが 5 つのソケットに制限されます。ソケットの再利用によりリソースの増加は抑制される可能性がありますが、同じホストからのデータに対する多数の同時リクエストを処理する必要がある場合、一連のボトルネックが発生する可能性があります。この場合、maxSockets の値を増やすか、ソケット プールをオフにすることをお勧めします。
// Disable socket pooling var http = require('http'); var options = {.....}; options.agent = false; var req = http.request(options)
3. 静的リソースに Node.js を使用させない
CSS や画像などの静的リソースの場合は、Node.js ではなく標準の WebServer を使用します。たとえば、LinkedIn モバイルは nginx を使用します。また、静的資産を世界中のサーバーにコピーできるコンテンツ配信ネットワーク (CDN) も利用しています。これには 2 つの利点があります。(1) Node.js サーバーの負荷を軽減できます。(2) CDN により、静的コンテンツをユーザーに近いサーバーに配信できるため、待ち時間を短縮できます。
4. クライアントでのレンダリング
サーバー レンダリングとクライアント レンダリングの違いを簡単に比較してみましょう。サーバー側でのレンダリングにnode.jsを使用する場合、リクエストごとに次のようなHTMLページを送り返します:
<!-- An example of a simple webpage rendered entirely server side --> <!DOCTYPE html> <html> <head> <title>LinkedIn Mobile</title> </head> <body> <div class="header"> <img src="http://mobile-cdn.linkedin.com/images/linkedin.png" alt="LinkedIn"/> </div> <div class="body"> Hello John! </div> </body> </html>
ユーザー名を除くこのページのすべてのコンテンツは静的コンテンツであることに注意してください。コンテンツは各ユーザーとページのリロードごとに同じです。したがって、Node.js がページに必要な動的コンテンツのみを JSON 形式で返すようにする方が効率的です。
{"名前": "ジョン"}
ページの残りの部分 (すべて静的 HTML マークアップ) は、JavaScript テンプレート (underscore.js テンプレートなど) に配置できます。
<!-- An example of a JavaScript template that can be rendered client side --> <!DOCTYPE html> <html> <head> <title>LinkedIn Mobile</title> </head> <body> <div class="header"> <img src="http://mobile-cdn.linkedin.com/images/linkedin.png" alt="LinkedIn"/> </div> <div class="body"> Hello <%= name %>! </div> </body> </html>
パフォーマンスの向上は次の場所から得られます。 3 番目のポイントで述べたように、静的 JavaScript テンプレートは、Web サーバー (nginx など) を通じてサーバー側で提供することも、より優れた CDN を使用して実装することもできます。さらに、JavaScript テンプレートはブラウザーにキャッシュすることも、ローカルに保存することもできます。最初のページがすべて読み込まれた後、クライアントに送信する必要があるのは JSON だけです。これが最も効果的です。この方法により、CPU、IO、Node.js の負荷を大幅に軽減できます。
5. gzip を使用します
多くのサーバーとクライアントは、リクエストとレスポンスを圧縮するために gzip をサポートしています。クライアントに応答する場合でも、リモート サーバーにリクエストを送信する場合でも、最大限に活用してください。
6. 並列化
リモート サービスへのリクエスト、DB 呼び出し、ファイル システム アクセスなど、すべてのブロック操作を並列化してみてください。これにより、すべてのブロック操作の待機時間ではなく、最も遅いブロック操作の待機時間が短縮されます。コールバックとエラー処理をクリーンに保つために、Step を使用してフローを制御します。
7.セッションの自由化
LinkedIn Mobile は、Express フレームワークを使用してリクエスト/レスポンス サイクルを管理します。多くの高速例には次の構成が含まれています:
app.use(express.session({ Secret: "keyboard cat" }));
デフォルトでは、セッション データはメモリに保存されるため、特にユーザー数が増加すると、サーバーに大きなオーバーヘッドが追加されます。 MongoDB や Redis などの外部セッション ストアを使用できますが、リクエストごとにセッション データを取得するためのリモート呼び出しのオーバーヘッドが発生します。可能であれば、すべてのステートレス データをサーバー側に保存することが最善の選択肢です。上記の高速構成を含めずにセッションを解放すると、パフォーマンスが向上します。
8. バイナリモジュールの使用
可能であれば、JavaScript モジュールをバイナリ モジュールに置き換えます。たとえば、JavaScript で書かれた SHA モジュールから Node.js 用にコンパイルされたバージョンに切り替えると、パフォーマンスが大幅に向上します。
// Use built in or binary modules var crypto = require('crypto'); var hash = crypto.createHmac("sha1",key).update(signatureBase).digest("base64");
9. クライアント ライブラリを標準の V8 JavaScript に置き換えます
多くの JavaScript ライブラリは、JavaScript 環境が異なるため、Web ブラウザーで使用するために作成されています。たとえば、一部のブラウザーは forEach、map、reduce などの関数をサポートしていますが、一部のブラウザーはサポートしていません。そのため、クライアント ライブラリはブラウザの違いを克服するために多くの非効率なコードを使用することがよくあります。一方、Node.js では、どの JavaScript メソッドが有効であるかを正確に把握できます。V8 JavaScript エンジンは、ECMA-262 第 5 版で規定されている ECMAScript の Node.js 実装をサポートします。クライアント ライブラリを標準の V8 JavaScript 関数に置き換えるだけで、パフォーマンスが大幅に向上します。
10. コードは小さくて軽いものにしてください
モバイル デバイスを使用すると、アクセスが遅くなり、レイテンシが高くなる可能性があるため、コードを小さく軽量に保つ必要があります。サーバーコードについても同じ哲学を維持してください。時々、自分の決定を振り返り、「このモジュールは本当に必要ですか?」、「なぜこのフレームワークを使用するのですか?、オーバーヘッドはそれだけの価値がありますか?」、「もっと簡単な方法で実現できないでしょうか?」などの質問を自問してください。 」通常、コードが小さくて軽いほど、効率が高く、高速になります。
試してみる
私たちはモバイルアプリを高速化するために熱心に取り組んでいます。 iPhone アプリ、Android アプリ、HTML5 モバイル バージョンで試してみて、その結果をお知らせください。