我正在使用Express 4 + Sequelize + Postgresql数据库构建NodeJs应用程序。 我正在使用Node v8.11.3。
我编写了一个脚本,用于将数据从JSON文件加载到数据库中。我用大约30个实体的样本对脚本进行了测试。效果很好。
实际上,在完整的JSON文件中,我要加载约100000个实体。我的脚本读取JSON文件,并尝试异步填充数据库(即同时填充10万个实体)。
结果是几分钟后:
<--- Last few GCs --->
[10488:0000018619050A20] 134711 ms: Mark-sweep 1391.6 (1599.7) -> 1391.6 (1599.7) MB, 1082.3 / 0.0 ms allocation failure GC in old space requested
[10488:0000018619050A20] 136039 ms: Mark-sweep 1391.6 (1599.7) -> 1391.5 (1543.7) MB, 1326.9 / 0.0 ms last resort GC in old space requested
[10488:0000018619050A20] 137351 ms: Mark-sweep 1391.5 (1543.7) -> 1391.5 (1520.2) MB, 1311.5 / 0.0 ms last resort GC in old space requested
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0000034170025879 <JSObject>
1: split(this=00000165BEC5DB99 <Very long string[1636]>)
2: attachExtraTrace [D:\Code\backend-lymo\node_modules\bluebird\js\release\debuggability.js:~775] [pc=0000021115C5728E](this=0000003CA90FF711 <CapturedTrace map = 0000033AD0FE9FB1>,error=000001D3EC5EFD59 <Error map = 00000275F61BA071>)
3: _attachExtraTrace(aka longStackTracesAttachExtraTrace) [D:\Code\backend-lymo\node_module...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
1: node_module_register
2: v8::internal::FatalProcessOutOfMemory
3: v8::internal::FatalProcessOutOfMemory
4: v8::internal::Factory::NewFixedArray
5: v8::internal::HashTable<v8::internal::SeededNumberDictionary,v8::internal::SeededNumberDictionaryShape>::IsKey
6: v8::internal::HashTable<v8::internal::SeededNumberDictionary,v8::internal::SeededNumberDictionaryShape>::IsKey
7: v8::internal::StringTable::LookupString
8: v8::internal::StringTable::LookupString
9: v8::internal::RegExpImpl::Exec
10: v8::internal::interpreter::BytecodeArrayRandomIterator::UpdateOffsetFromIndex
11: 0000021115A043C1
最后,已经创建了一些实体,但是该过程显然崩溃了。 我知道此错误是由于内存造成的。
我的问题是:为什么Node不花时间来管理所有事务而又不会过度占用内存?是否有“队列”来限制此类爆炸?
我确定了一些解决方法:
但是这些解决方案都不令我满意。这让我为自己的应用程序的未来感到恐惧,因为该应用程序有时会管理生产中的长时间操作。
您怎么看?
答案 0 :(得分:1)
使用async.eachOfLimit最多同时执行X次操作:
var async = require("async");
var myBigArray = [];
var X = 10; // 10 operations in same time at max
async.eachOfLimit(myBigArray, X, function(element, index, callback){
// insert element
MyCollection.insert(element, function(err){
return callback(err);
});
}, function(err, result){
// all finished
if(err){
// do stg
}
else
{
// do stg
}
});
答案 1 :(得分:0)
Node.js就是按照您所说的去做。如果进入某个大循环并启动大量数据库操作,那么这正是node.js试图做的。如果开始的操作太多而消耗太多的资源(内存,数据库资源,文件等),那么您将遇到麻烦。 Node.js不会为您管理。必须由您的代码来管理您同时进行多少次操作。
另一方面,node.js尤其擅长同时运行一堆异步操作,并且如果将其编码为具有多个操作,则通常会获得更好的端到端性能。一次去。您希望同时运行多少个,完全取决于特定的代码以及异步操作正在执行的操作。如果这是数据库操作,则可能取决于数据库以及最能同时处理多少个请求。
这里有一些参考资料,为您提供了控制一次执行多少操作的方法的思路,包括一些代码示例:
Make several requests to an API that can only handle 20 request a minute
Promise.all consumes all my RAM
Javascript - how to control how many promises access network in parallel
Fire off 1,000,000 requests 100 at a time
Nodejs: Async request with a list of URL
Loop through an api get request with variable URL
Choose proper async method for batch processing for max requests/sec
如果您显示了代码,我们可以更具体地建议哪种技术最适合您的情况。