我编写了一个小的node.js应用程序,它遍历一个1.8GB的xml文件,并对不同的元素执行一些数据库操作。但是我遇到了记忆问题。
var fs = require('fs')
, path = require('path')
, XmlStream = require('xml-stream')
, pg = require('pg')
, conString = "postgres://user:pass@localhost:5432/db"
, schema = 'public'
;
function storeInDB(data){
pg.connect(conString, function(err, client, done) {
if(err) {
return console.error('error fetching client from pool', err);
}
var sql = 'INSERT INTO '+schema+'.table (field1, field2) VALUES ($1, $2) ';
client.query(sql,data, function(err, result) {
done();
if(err) {
return console.error('error running query', err);
}
});
})
}
var stream = fs.createReadStream('../path/to/some_large.xml');
var xml = new XmlStream(stream);
// Find the certificate entry and do things with it.
xml.on('endElement: certificate', function(item) {
var data = [item.field1, item.field2, ......];
storeInDB(data);
});
虽然这可行,但它开始逐渐消耗更多RAM。在htop中,我看到记忆的稳定增长百分比;直到我使用完整的RAM并且SWAP文件启动。由于IO,这会导致相当大的延迟。这是400.000处理过的证书;该文件包含大约2.5密耳的证书。
有些东西在吃记忆,但我不知道是什么。随着内存的构建证明,XML流不应该将数据加载到内存中。但看起来处理的数据不会以某种方式从内存中刷新。有没有办法每个x证书刷新内存?或者应用程序错误'?
答案 0 :(得分:0)
你绑定的事件:
xml.on('endElement: certificate')
会一遍又一遍地快速触发,而无需等待DB的写入完成。更新storeInDB以调用它:
xml.pause() // Put this as the first line in storeInDB to prevent too many events
并将其放入查询回调中:
xml.resume(); // Resume parsing
done();
如果正在进行超过5个查询等,您可以改进此选项以仅调用暂停和恢复事件,但您明白了。
也可能值得研究不使用pg模块的连接池,而是通过client.connect使用单个连接。