0

nodejsを使用して、外部APIからmongodbにデータを保存しようとしています。スクリプトは非常に軽量に感じますが、何らかの理由で大量の RAM を使用しています (からtop):

 PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND 
 2626 root      20   0  756m 113m 7148 S  6.5 11.4   3:11.74 nodejs  

これは、疑似コードでスクリプトが行うことです。

each 5 seconds
  fetch 3 JSON lists through an API
    for all new items in list
      store in mongo

[編集] JSON リストはおよそです。それぞれ10kb。したがって、アイテムを処理するまでそれをメモリに保持する必要はないと思います。[/編集]

(軽い)依存関係は次のとおりです。

  • クエリ文字列
  • https
  • 下線
  • mongodb (ネイティブ クライアント)
  • 一瞬

私はそれを単純な関数として書きましたが、返すときに、使用したすべてのメモリを返す必要がありますか?

スクリプト全体は次のとおりです。

var querystring = require("querystring");
var https = require('https');

var fetch = function(cur, callback) {
  cur = cur.toLowerCase().replace('/', '_');
  var options = {
    host: 'data.fxbtc.com',
    path: '/api?op=query_last_trades&count=100&symbol=' + cur,
    method: 'GET',
    headers: {
      'User-Agent': 'Mozilla/4.0 (compatible; node.js client)'
    }
  };

  var req = https.request(options, function(res) {
    res.setEncoding('utf8');
    var buffer = '';
    res.on('data', function(data) {
      buffer += data;
    });
    res.on('end', function() {
      try {
        var json = JSON.parse(buffer);
      } catch (err) {
        return callback(err);
      }
      callback(null, json);
    });
  });
  req.end();
}

var currencies = [
  'BTC/CNY',
  'LTC/CNY',
  'LTC/BTC'
];

var LAST_TRADE = {
  'BTC/CNY': 0,
  'LTC/CNY': 0,
  'LTC/BTC': 0
}

var _ = require('underscore');
var mongo = require('mongodb');
var moment = require('moment');

var init = function(next) {
  mongo.connect('mongodb://127.0.0.1:27017/coindata', next);
}

var now = function() {
  return moment().format('YYYY-MM-DD HH:mm:ss');
}

console.log(now(), 'STARTING');

setInterval(function() {
  console.log(now(), 'alive')
}, 60000)

var collections = {};

var forever = function(err, db) {
  if(err) throw err;

  _.each(currencies, function(cur, i) {
    collections[cur] = db.collection('fxbtc_' + cur);
    collections[cur].ensureIndex({fid: 1}, {unique: true}, console.log);

    setTimeout(function() {
      console.log(now(), 'registering', cur);
      setInterval(check(cur), 5 * 1000);
    }, i * 1000);
  });
}

var check = function(cur) {
  return function() {
    fetch(cur, function(err, trades) {
      if(err) return console.log(now(), 'ERROR-FETCH', err);

      trades = _.map(trades.datas, function(trade) {
        return {
          date: new Date(trade.date * 1000),
          price: parseFloat(trade.rate),
          amount: parseFloat(trade.vol),
          fid: parseInt(trade.ticket)
        }
      });

      trades = _.filter(trades, function(trade) {
        return trade.fid > LAST_TRADE[cur];
      });

      var fids = _.pluck(trades, 'fid');
      fids.push(LAST_TRADE[cur]);

      LAST_TRADE[cur] = _.max(fids);

      if(!trades.length)
        return;

      console.log(now(), 'storing:', trades.length, 'in', cur);

      collections[cur].insert(trades, function(err, docs) {
        if(err && err.code !== 11000) console.log(now(), 'ERROR-STORE', err);
      });

    });
  }
}


init(forever);

このスクリプトに明らかなメモリ リークはありますか? 使用されているすべてのメモリのソースを見つけるにはどうすればよいですか?

4

1 に答える 1

0

私が取り組んでいるプロジェクトは、さまざまな API サービス (15 以上) をポーリングし、最新の変更をすべて保存しています。

私が最初に考えたのは、異なるサービスごとに小さなスクリプトを作成することでした。このスクリプトには、永久にアップし続けるループが含まれています。問題 (上記のとおり) は、どういうわけかメモリがサービスごとに 40 ~ 120 MB に増加し (いくつかの要因によって異なります)、システムの RAM が不足することです。

これが私が今それを解決した方法です:

サービスごとのプロセスを維持する代わりに、すべてのスクリプトを 1 回だけ実行するように書き直し、x 時間後にサービス スクリプトごとに各スクリプトを実行するマスター スクリプトを作成しました。

var cp = require('child_process');
var moment = require('moment');

var i = 0;

var watch = function(options) {
  i++;
  setTimeout(function() {
    var fid = 0;
    setInterval(function() {
      var worker = cp.fork('./process_' + options.exchange + '.js');
      worker.send(fid);
      worker.once('message', function(new_fid) {
        fid = new_fid;
        worker.kill();
      });
    }, options.interval);  
  }, i * 3000);

}

そして、次のようにすべての異なるサービスを登録します。

watch({exchange: 'bitcurex', interval: +moment.duration(9, 'minutes')});

10 時間強、または現在、メモリ フットプリントがほとんどまたはまったくない状態で実行されています (一番上に見つかりません)。

于 2013-08-01T11:59:32.813 に答える