【问题标题】:Why my nodejs insert to mongoDB stops after a while为什么我的 nodejs 插入到 mongoDB 会在一段时间后停止
【发布时间】:2015-04-02 23:42:54
【问题描述】:

我正在使用以下代码测试我的 nodejs 插入到我的 MongoDB 中。当我插入类似 10000 行的内容时,一切正常。但是,如果我尝试插入类似 100 万的内容,则插入操作会停止一段时间,并且不会在 nodejs 控制台或 MongoDB 上打印出错误。

我在下面附上了我的代码和控制台,请帮助我,非常感谢!!

--- 更新 ---

为了回答回复中的问题,我还检查了我的 mongostat,插入会在一段时间后停止。但是,我观察到两个现象:

1) 在我的笔记本电脑上,mongodb 解析器是通过“npm install mongodb”安装的,并且“node my.js”通过以下服务器输出“服务器已启动”启动。

观察结果:insert正在进行中,mongostat显示,大部分时间insert为零,但有时可以显示插入的记录。

2) 在我的 PC 上,通过“npm --registry http://registry.npmjs.eu/ install mongodb”安装 mongodb 解析器,并以以下服务器输出“服务器已启动。-> 失败”启动“node my.js”加载c++ bson扩展,使用纯JS版本"

观察结果:插入只运行了一段时间,然后什么也没有发生,一段时间后 mongostat 总是显示零插入。

“npm --registry http://registry.npmjs.eu/ install mongodb”也会有问题吗?


我的nodejs代码:

mongoClient.connect("mongodb://localhost:27017/testdb", { db : { native_parser : true } }, function(err, database) {

        if (err) { console.log(err.message); throw err; }

        // create new collection under database
        var collection = database.collection('gm_std_measurements_coveringindex');
        date = new Date();

        // add all Documents
        for (var i = 0; i < 1000000; i++) {
            var ranNumber = Math.floor((Math.random() * 1000) + 1);

            // insert objects after table and index creation
            var istObject = {
                fkDataSeriesId : ranNumber,
                measDateUtc : date,
                measDateSite : date,
                project_id : ranNumber,
                measvalue : ranNumber,
                refMeas : false,
                reliability : 1.0
            };

            collection.insert(istObject, { w : 1 }, function(err, docs) {
                if (err) {
                    console.log(err.message);
                    throw err;
                } else {
                    // do noting to responsed inserted Document
                }
            });
        }
        console.log("* Documents created!");
    });

MongDB 服务器输出:

Thu Apr 17 15:32:18.942 [initandlisten] connection accepted from 127.0.0.1:33228 #70 (3 connections now open)
Thu Apr 17 15:32:18.949 [conn70] end connection 127.0.0.1:33228 (2 connections now open)
Thu Apr 17 15:32:18.951 [initandlisten] connection accepted from 127.0.0.1:33229 #71 (3 connections now open)
Thu Apr 17 15:32:18.952 [initandlisten] connection accepted from 127.0.0.1:33230 #72 (4 connections now open)
Thu Apr 17 15:32:18.952 [initandlisten] connection accepted from 127.0.0.1:33231 #73 (5 connections now open)
Thu Apr 17 15:32:18.953 [initandlisten] connection accepted from 127.0.0.1:33232 #74 (6 connections now open)
Thu Apr 17 15:32:18.953 [initandlisten] connection accepted from 127.0.0.1:33233 #75 (7 connections now open)
Thu Apr 17 15:32:28.520 [FileAllocator] allocating new datafile /var/lib/mongodb/testdb.2, filling with zeroes...
Thu Apr 17 15:32:28.563 [FileAllocator] done allocating datafile /var/lib/mongodb/testdb.2, size: 256MB,  took 0.042 secs
Thu Apr 17 15:32:31.517 [conn75] insert testdb.gm_std_measurements_coveringindex ninserted:1 keyUpdates:0 locks(micros) w:23 129ms
Thu Apr 17 15:32:31.517 [conn72] insert testdb.gm_std_measurements_coveringindex ninserted:1 keyUpdates:0 locks(micros) w:37 129ms
Thu Apr 17 15:32:31.517 [conn74] insert testdb.gm_std_measurements_coveringindex ninserted:1 keyUpdates:0 locks(micros) w:31 129ms
Thu Apr 17 15:32:31.517 [conn73] insert testdb.gm_std_measurements_coveringindex ninserted:1 keyUpdates:0 locks(micros) w:19 129ms

【问题讨论】:

  • 你对每个请求都创建一个连接,我认为连接数是有限的,这就是问题
  • 感谢您的回复!我不太明白,我认为从“mongoClient.connect”获取的“数据库”是一个连接池,其中LOOP内部的“collection.insert”应该在内部重用这个连接池?如果我的理解是错误的,那么正确的应该是怎样的呢?

标签: node.js mongodb


【解决方案1】:

我想我自己已经弄明白了。

从 Nodejs 向 MongoDB 中插入数百万条数据的问题在于,nodejs 忙于生成这些记录并立即将它们发送出去。百万数据立即出现,一会nodejs本身就卡住了,此时MongoDB还没有收到多少传入的insert。

我通过设置一次插入10000条记录的间隔方法来“摆脱”这个问题,并且每秒调用一次这个间隔,以便nodejs有机会移动到下一个 事件将生成的插入发送出去,然后再次开始插入的生成。

interval_checkId = setInterval(createSomeInsert, 1000);

还有 createSomeInsert 方法:

function createSomeInsert() {

    console.log("* Starting to insert another 10K records, current count: " + counter);

    var collection = dbPool.collection('gm_std_measurements_coveringindex');

    var date = new Date();
    var amount = 10 * 1000;
    for(var i = 0; i < amount; i++) {

        var ranNumber = Math.floor((Math.random() * 1000) + 1);

        // insert objects after table and index creation
        var istObject = {
            fkDataSeriesId : ranNumber,
            measDateUtc : date,
            measDateSite : date,
            project_id : ranNumber,
            measvalue : ranNumber,
            refMeas : false,
            reliability : 1.0
        };

        collection.insert(istObject, { w : 0 }, function(err, docs){
            if(err) {console.log(err); throw err;}
            counter++;
        });

    }

    if(counter >= totalTarget) {
        clearInterval(interval_checkId);
        console.log("Completed Insert, in total : " + counter);
        counter = 0;
    }
}

但是我还是不明白为什么nodejs在生成了很多insert请求之后会被阻塞,为什么大部分都没有在后台发给mongodb。

【讨论】:

    【解决方案2】:

    您可以使用 mongostat 检查脚本的进度或查看是否发生了任何事情。

    打开 cmd,导航到 /mongodb/bin 目录并执行 mongostat --host localhost

    这将为您提供有关您的 mongodb 服务器当前正在发生的情况的信息。第一列是插入操作,您必须检查。这表示每秒在数据库中插入多少项目。 还要查看“locked db”列,它显示了数据库的写锁定百分比。较高的百分比意味着写入操作速度较慢,因为有许多插入,并且每个插入都在等待前一个完成并解锁数据库。 另请注意,connection.insert 是异步操作,基本上您正在尝试一次向数据库发送 100 万个插入请求,因为您无需等待任何插入完成。 我在 10 分钟前开始了你的脚本,我目前有 400k 个项目

    【讨论】:

    • 嗨@d1mitar,我也在问题更新中回答了你的建议。顺便说一句,10分钟后插入400k,nodejs和mongodb是不是有点慢? -- 我想我的笔记本电脑(2G i7、4G DDR3)已经证明了你的结果,并且它有类似的结果, -- 真的没有我预期的那么快。
    • 如果你想插入 100 万条记录,你最好把它们分成 10k 的块。它在我的机器上工作了几秒钟。当您逐个插入项目时,您会在每次插入时锁定数据库,这真的很糟糕。对于 mongodb,通过将数组传递给 collection.insert 方法一次插入 10000 个项目要容易得多,而不是一次添加一个项目
    • 真的!对于大规模插入现实,它应该是块插入。但是,我模拟的场景是大量未知客户端在不可预测的时间发出大量请求,这就是为什么我要测试 nodejs 的能力来回答对 MongoDB 的大量单次插入。
    最近更新 更多