我正在尝试使用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列表是aprox。每个10kb。因此,我不认为在处理项目之前将其保留在内存中是不可行的。 [/编辑]
(轻)依赖关系是:
我把它写成简单的函数,返回时它们应该回放它们使用的所有内存吗?
以下是整个脚本:
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);
此脚本中是否有明显的内存泄漏?如何查找所有已用内存的来源?
答案 0 :(得分:0)
我正在处理的项目是轮询许多不同的API服务(15+)并存储所有最新的更改。
我最初的想法是为每个不同的服务编写一个小脚本,里面有一个循环,应该永远保持不变。问题(如上所述)是每个服务的内存会以某种方式增长到40-120mb(取决于几件事),而我的系统会耗尽RAM。
这就是我现在解决的问题:
而不是保持每个服务的进程保持活动状态我重写了所有脚本只运行一次并写了一个主脚本,负责在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多个小时或现在几乎没有内存占用(我无法在顶部找到它)。