13

Node.js/Express RESTful API から JSON 文字列に変換された非常に大きなオブジェクトを返す必要があるシナリオがあります。

res.end(JSON.stringify(obj));

ただし、これはうまくスケーリングできないようです。具体的には、1 ~ 2 台のクライアントが接続しているテスト マシンでは問題なく動作しますが、多くのクライアントが大きな JSON オブジェクトを同時に要求している場合、この操作によって CPU とメモリの使用量が大幅に増加する可能性があると思われます。

非同期の JSON ライブラリを探し回ったのですが、見つかった唯一のライブラリに問題があるようです (具体的には、[RangeError] が発生しました)。それだけでなく、文字列を 1 つの大きなチャンクで返します (たとえば、コールバックは文字列全体で 1 回呼び出されるため、メモリ フットプリントは減少しません)。

私が本当に欲しいのは、JSON.stringify 関数の完全に非同期のパイピング/ストリーミング バージョンです。これにより、ストリームに直接パックされたデータを書き込むことができます。したがって、メモリ フットプリントを節約し、CPU を消費することもありません。同期ファッション。

4

2 に答える 2

10

理想的には、すべてを 1 つの大きなオブジェクトにバッファリングするのではなく、データをそのままストリーミングする必要があります。これを変更できない場合は、stringify を小さな単位に分割し、メイン イベント ループがsetImmediateを使用して他のイベントを処理できるようにする必要があります。コード例 (メイン オブジェクトには多くの最上位プロパティがあり、それらを使用して作業を分割すると仮定します):

function sendObject(obj, stream) {
    var keys = Object.keys(obj);
    function sendSubObj() {
       setImmediate(function(){
          var key = keys.shift();
          stream.write('"' + key + '":' + JSON.stringify(obj[key]));
          if (keys.length > 0) {
            stream.write(',');
            sendSubObj();
          } else {
            stream.write('}');
          }
       });
    })
    stream.write('{');
    sendSubObj();
} 
于 2012-11-22T00:09:32.813 に答える
5

It sounds like you want Dominic Tarr's JSONStream. Obviously, there is some assembly required to merge this with express.

However, if you are maxing out the CPU attempting to serialize (Stringify) an object, then splitting that work into chunks may not really solve the problem. Streaming may reduce the memory footprint, but won't reduce the total amount of "work" required.

于 2012-11-21T23:59:40.057 に答える