私は重大な問題に直面しました。
私のアプリケーションアーキテクチャは次のように記述されています:
nginx -> Web アプリ (express/nodejs) -> api (jetty/java) -> mysql
API アプリケーションは十分に最適化されているため、そのパフォーマンスについてここで言及する必要はありません。(100 リクエスト/秒で ~200 ミリ秒/リクエスト)
私のウェブアプリケーション:
プロファイル ログを実行しているときに、Swig テンプレート エンジンによる HTML レンダリング時間が I/O をブロックしすぎることに気付きました。そのため、保留中の他のリクエストの待機時間が大幅に増加します。
1MB の text/html レスポンスをレンダリングする場合、Swig テンプレートは最大 250 ミリ秒かかります。
これが私のストレステストの出力です:
$ node stress.js 20
Receive response [0] - 200 - 431.682654ms
Receive response [1] - 200 - 419.248099ms
Receive response [2] - 200 - 670.558033ms
Receive response [4] - 200 - 920.763105ms
Receive response [3] - 200 - 986.20115ms
Receive response [7] - 200 - 1521.330763ms
Receive response [5] - 200 - 1622.569327ms
Receive response [9] - 200 - 1424.500137ms
Receive response [13] - 200 - 1643.676996ms
Receive response [14] - 200 - 1595.958319ms
Receive response [10] - 200 - 1798.043086ms
Receive response [15] - 200 - 1551.028243ms
Receive response [8] - 200 - 1944.247382ms
Receive response [6] - 200 - 2044.866157ms
Receive response [11] - 200 - 2162.960215ms
Receive response [17] - 200 - 1941.155794ms
Receive response [16] - 200 - 1992.213563ms
Receive response [12] - 200 - 2315.330372ms
Receive response [18] - 200 - 2571.841722ms
Receive response [19] - 200 - 2523.899486ms
AVG: 1604.10ms
ご覧のとおり、リクエストが遅いほど、待ち時間が長くなります。
いくつかのコードを変更して、HTML をレンダリングする代わりに応答コードを返す場合:
function render(req, res, next, model) {
return res.status(200).end(); // add this line
res.render('list', model);
}
ストレス テストの出力は次のように変わります。
$ node stress.js 20
Receive response [0] - 200 - 147.738725ms
Receive response [1] - 200 - 204.656645ms
Receive response [2] - 200 - 176.583635ms
Receive response [3] - 200 - 218.785931ms
Receive response [4] - 200 - 194.479036ms
Receive response [6] - 200 - 191.531871ms
Receive response [5] - 200 - 265.371646ms
Receive response [7] - 200 - 294.373466ms
Receive response [8] - 200 - 262.097708ms
Receive response [10] - 200 - 282.183757ms
Receive response [11] - 200 - 249.842496ms
Receive response [9] - 200 - 371.228602ms
Receive response [14] - 200 - 236.945983ms
Receive response [13] - 200 - 304.847457ms
Receive response [12] - 200 - 377.766879ms
Receive response [15] - 200 - 332.011981ms
Receive response [16] - 200 - 306.347012ms
Receive response [17] - 200 - 284.942474ms
Receive response [19] - 200 - 249.047099ms
Receive response [18] - 200 - 315.11977ms
AVG: 263.30ms
以前に実装しようとした解決策がいくつかありますが、応答時間を短縮できるものはありません。
node-clusterを使用します(サーバーに 2 つのワーカー)
if (conf.cluster) {
// cluster setup
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', function(worker, code, signal) {
console.log('Worker ' + worker.process.pid + ' died');
// create new worker
cluster.fork();
});
} else {
rek('server').listen(conf.port, function() {
console.log('Application started at port ' + conf.port + ' [PID: ' + process.pid + ']');
});
}
} else {
rek('server').listen(conf.port, function() {
console.log('Application started at port ' + conf.port + ' [PID: ' + process.pid + ']');
});
}
JXCoreを 16 スレッドで使用する(最大スレッド数なし)
jx mt-keep:16 app.js
NGINX 負荷分散を使用する
4 つのノード プロセスを開始する
$ PORT=3000 forever start app.js
$ PORT=3001 forever start app.js
$ PORT=3002 forever start app.js
$ PORT=3003 forever start app.js
nginx.conf
upstream webapp {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002;
server 127.0.0.1:3003;
}
server {
listen 80;
location / {
proxy_pass http://webapp;
}
[...]
}
上記のすべてのソリューションは、HTML レンダリングなどの重いタスクを実行するときに相互にブロックしない複数のプロセス/スレッドを提供すると考えましたが、結果は私の期待と同じではありません: 待ち時間は短縮されません. ログには、リクエストが実際には複数のプロセス/スレッドによって処理されていることが示されています。
ここで見逃しているポイントはありますか?
または、待ち時間を短縮するための別の解決策を教えてください。