【问题标题】:NodeJS Heap out of memory with long process with database accessNodeJS Heap out of memory with long process with database access
【发布时间】:2019-01-09 07:19:00
【问题描述】:

我正在使用 Express 4 + Sequelize + Postgresql 数据库构建 NodeJs 应用程序。 我正在使用 Node v8.11.3。

我编写了一个脚本来将数据从 JSON 文件加载到我的数据库中。我用大约 30 个实体样本测试了脚本。效果很好。

实际上,在完整的 JSON 文件中,我有大约 100 000 个实体要加载。我的脚本读取 JSON 文件并尝试异步填充数据库(即同时填充 100 000 个实体)。

几分钟后结果是:

<--- 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 不花时间管理所有事情而不超出内存?有没有“队列”来限制这种爆炸?

我发现了一些解决方法:

  • 将种子分割成几个 JSON 文件
  • 使用 --max_old_space_size=8192 选项使用更多内存
  • 按顺序进行(使用同步调用)

但是这些解决方案都没有让我满意。这让我担心我的应用程序的未来应该在生产中管理有时很长的操作。

你怎么看?

【问题讨论】:

  • 如果您需要帮助,您可能需要向我们展示您的代码。如果您在一个循环中一次启动 100,000 个数据库操作,那就太多了。如果您向我们展示您的特定代码,我们只能为您提供具体建议。
  • Node 做你告诉它的事情。如果你指示它做一些占用大量内存的事情,这就是它试图做的事情。很有可能是您的代码需要修复。欢迎来到编程和编写优秀代码的需求。
  • @jfriend00 感谢您的回答。实际上我不想让你调试我的代码,这就是我没有发布它的原因。我的意思是了解 NodeJs 如何处理大量异步计算/IO。你回答了我的问题:“Node 做你告诉它的事情。如果你指示它做一些需要大量内存的事情,那它就是它试图做的事情。”所以我知道我必须将异步调用限制在一个限度内。

标签: node.js


【解决方案1】:

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

如果您展示了您的代码,我们可以更具体地建议哪种技术最适合您的情况。

【讨论】:

  • 谢谢,实际上我更多的是在寻找这样的答案,而不是代码审查。自从我提出要求的那天起,我通过一次限制飞行中的请求成功地在我的数据库中创建了我的条目。它完美地工作。感谢您的解释和链接
【解决方案2】:

使用 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
     }

});

【讨论】:

  • 感谢@Daphoque 的回答。它不符合我的代码,但您无法知道它,因为我没有发布它。我会人为地做这样一个“队列”来限制一次T时间的内存使用量。
猜你喜欢
  • 1970-01-01
  • 2018-08-01
  • 2019-06-18
  • 2021-09-02
  • 1970-01-01
  • 2014-02-21
  • 2012-03-09
  • 2017-05-21
  • 2022-12-12
相关资源
最近更新 更多