0

私は重大な問題に直面しました。

私のアプリケーションアーキテクチャは次のように記述されています:

nginx -> Web アプリ (express/nodejs) -> api (jetty/java) -> mysql

API アプリケーションは十分に最適化されているため、そのパフォーマンスについてここで言及する必要はありません。(100 リクエスト/秒で ~200 ミリ秒/リクエスト)

私のウェブアプリケーション:

  1. 特急
  2. Swig テンプレート エンジン

プロファイル ログを実行しているときに、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 レンダリングなどの重いタスクを実行するときに相互にブロックしない複数のプロセス/スレッドを提供すると考えましたが、結果は私の期待と同じではありません: 待ち時間は短縮されません. ログには、リクエストが実際には複数のプロセス/スレッドによって処理されていることが示されています。

ここで見逃しているポイントはありますか?

または、待ち時間を短縮するための別の解決策を教えてください。

4

3 に答える 3

0

クラスターを作成しても応答時間が短縮されるわけではありませんが、IO をブロックすることなく応答を並行して実行できます。もちろん、クラスターを適切に使用するには、マスターがワーカーを効率的に制御するための独自のロジックをセットアップする必要があります。適切なロジックなしでクラスターを追加しても、実際のメリットは得られません。これを正しく機能させるには、マスターがすべての受信リクエストを処理し、それらをワーカーに配布して処理する必要があります。次に、ワーカーは結果をマスターに送り返し、マスターが残りを処理します。

于 2014-11-17T01:34:02.813 に答える
0

以下の点を確認する必要があると思います。

-> テンプレート キャッシングを使用して IO のブロックを回避する

-> テンプレートを多くのパーツに分割し、ロード オン デマンドを使用する

→データ収集時間は1回?

于 2014-11-19T13:27:09.817 に答える