node.js内存使用在做~500k mongodb插入时爆炸

时间:2015-01-15 19:23:08

标签: mysql node.js performance mongodb

我正在将数据从MySQL迁移到MongoDB。

MySQL根本没有优化(没有索引)所以我的操作,1个普通的sql查询和1个sql sequelize查询每个需要大约30秒,每个返回~300k文件。

我并不担心MySQL部分,但关于node / mongo部分。

将它们插入MongoDB时,我尝试了几件事:

  • 使用本机驱动程序和数组插入,我没有看到任何问题,它很快。我只是将查询结果聚合到几个中型数组(<16MB)并插入它们。但是我想要进行upsert而不是插入以不破坏修改后的数据,并且不支持批量操作。
  • 使用mongoose和单个upserts,节点进程慢慢走向我给它的mem限制(3GB)然后似乎停在那里。 30分钟后,几乎没有可见的进展,mongodb进程处于0%CPU。 (我认为如果它有足够的内存用于给定数量的数据,它通常会在很长一段时间后完成。)
  • 使用本机驱动程序和单个upserts,整个过程运行非常缓慢,但至少完成。在任务管理器(Windows系统)中查看CPU使用情况,我可以看到mysql正在使用CPU时(当我启动2个查询时,第一个查询完成后第二个,并且所有结果都已插入到mongodb中) (至少从节点方面来说,因为它们实际上还没有到达))并且Mongod在开始时短暂地显示CPU负载,但是它保持在0%,而node.js正在抓取越来越多的内存。只是很久以后,mongod似乎再次回升,并且在某些时候节点的内存使用量反转并且在mongod也回到0%CPU时恢复正常。 奇怪的是,到那个时候,我所有的查询/ upsert都很久以前完成了,实际的工作(从我的CPU使用情况以及mongodb中的实际数据中可以看到,同时打开shell并计算预期的对象)只会发生在巨大的内存和CPU负载之后(在大多数操作期间,节点进程最大化1个内核和CPU负载)。

嗯,上面的第三个案例对我来说最有意思,因为它正在工作,给我我想要的东西,它只是表现得不太可理解。

为什么&#34;真实&#34;工作只在我调用更新后很久才完成?

我还消除了写入关注/回调以加快这个过程,而且它似乎有所帮助。

典型的upsert看起来像这样:

 connectionb.update({ isbn13: book.isbn13 },
     { $addToSet: { ratedByUsers: insertuserrating } },
     { w: 0 });

    connectionu.update(insertuser,
    { $addToSet: { ratedBooks: insertbookrating } },
    { upsert: true, w: 0 });

另外,我不认为我有内存泄漏,因为整体而言,后来我发现内存再次回落到几个100MB。 (不是这里 - 我把它归咎于GC是懒惰的。我确实重复运行了操作,并且看到内存再次大幅下降。)


我尝试更好地说明行为:你可以看到MySQL CPU消耗中的2个峰值,这是我预期的,因为我进行了2次查询。

MongoD不稳定地达到峰值。

MongoD和MySQL一直使用非常少的内存。

节点一直在运行全1-CPU,内存先快速增加然后慢慢减少。

cpu and mem consumption

我希望node.js可以减少工作量并且mongod会一直忙于尝试插入数据。此外,我对时间感到惊讶:节点表示它在大约2分钟后完成所有操作(我的所有代码都已经完成) - 但是那时候mongodb中几乎没有任何数据。

我做错了吗?

如何减少节点的内存和CPU消耗,加快数据最终到达mongodb的时间?


添加了真实代码

(删除了很​​多,比如我认为无关的模型和查询)。 connectionu和connectionb是与用户和书籍集合的mongodb连接。

首先,导入所有书籍,然后导入所有用户 - 由于mysql DB结构,我使用评级来确定我感兴趣的用户,并再次使用评级更新书籍集。

    sequelize.query(qstring).success(function (result) {
        var len = result.length;
        result.forEach(function ProcessRatingResult(oneresult) {

            var insertobject = {
                isbn13: oneresult.isbn13,
                title: oneresult.title,
            };
            cntwrite++;
            connectionb.update({ isbn13: oneresult.isbn13 }, insertobject, { upsert: true, w: 0 });
            // only start 2nd part if first part is completely finished - 135s runtime
            if (cntwrite == (len - 1)) {
                // start with slight delay - give mongo/node time to catch up
                setTimeout(ImportRating, 10000); //2500);
            }
        });
    });

    function ImportRating() {
        SQLRating.findAll({ where: {}, include: [SQLUser, SQLBook] }).success(function (sqlresult) {
            async.each(sqlresult, function ProcessRatingResult(oneresult) {
                var book = oneresult.book;
                var user = oneresult.user;
                var rating = oneresult.rating;
                (function (book, user, rating) {
                    var insertuser = {
                        joined: user.created,
                        external_id: user.external_id
                    };

                    var insertbookrating = {
                        book: book.isbn13,
                        rating: rating
                    }

                    connectionu.update(insertuser,
                                { $addToSet: { ratedBooks: insertbookrating } },
                                { upsert: true, w: 0 });

                    var insertuserrating = {
                        user: user.external_id,
                        rating: rating
                    }

                    connectionb.update({ isbn13: book.isbn13 },
                            { $addToSet: { ratedByUsers: insertuserrating } },
                            { w: 0 });
                })(book, user, rating);
            }
                ,
                function (err) {
                throw err;
            }
            );
        });
    }

0 个答案:

没有答案