我试试看.js与mongodb(2.2.2)一起使用本机 node .js drive by 10gen.

起初一切都很顺利.但在并发基准测试部分,出现了很多错误.频繁连接/关闭1000次并发可能会导致mongodb拒绝任何进一步的请求,错误如下:

Error: failed to connect to [localhost:27017]

Error: Could not locate any valid servers in initial seed list

Error: no primary server found in set

此外,如果很多客户端在没有显式关闭的情况下关闭,mongodb需要几分钟来检测并关闭它们.这也会导致类似的连接问题.(使用/var/log/mongodb/mongodb.log判断连接状态)

我试了很多.根据手册,mongodb没有连接限制,但poolSize选项似乎对我没有影响.

由于我只在node mongodb本机模块中使用过它,所以我不太确定最终是什么导致了这个问题.其他语言和驱动程序的性能如何?

PS:目前,使用自维护池是我想出的唯一解决方案,但使用它不能解决副本集的问题.根据我的测试,副本集似乎比独立的mongodb占用更少的连接.但我不知道为什么会这样.

并发测试代码:

var MongoClient = require('mongodb').MongoClient;

var uri = "mongodb://192.168.0.123:27017,192.168.0.124:27017/test";

for (var i = 0; i < 1000; i++) {
    MongoClient.connect(uri, {
        server: {
            socketOptions: {
                connectTimeoutMS: 3000
            }
        },
    }, function (err, db) {
        if (err) {
            console.log('error: ', err);
        } else {
            var col = db.collection('test');
            col.insert({abc:1}, function (err, result) {
                if (err) {
                    console.log('insert error: ', err);
                } else {
                    console.log('success: ', result);
                }
                db.close()
            })
        }
    })
}

通用池解决方案:

var MongoClient = require('mongodb').MongoClient;
var poolModule = require('generic-pool');

var uri = "mongodb://localhost/test";

var read_pool = poolModule.Pool({
    name     : 'redis_offer_payment_reader',
    create   : function(callback) {
        MongoClient.connect(uri, {}, function (err, db) {
            if (err) {
                callback(err);
            } else {
                callback(null, db);
            }
        });
    },
    destroy  : function(client) { client.close(); },
    max      : 400,
    // optional. if you set this, make sure to drain() (see step 3)
    min      : 200, 
    // specifies how long a resource can stay idle in pool before being removed
    idleTimeoutMillis : 30000,
    // if true, logs via console.log - can also be a function
    log : false 
});


var size = [];
for (var i = 0; i < 100000; i++) {
    size.push(i);
}

size.forEach(function () {
    read_pool.acquire(function (err, db) {
        if (err) {
            console.log('error: ', err);
        } else {
            var col = db.collection('test');
            col.insert({abc:1}, function (err, result) {
                if (err) {
                    console.log('insert error: ', err);
                } else {
                    //console.log('success: ', result);
                }
                read_pool.release(db);
            })
        }
    })
})

推荐答案

自 node .js是单线程的,您不应该在每次请求时打开和关闭连接(就像在其他多线程环境中一样)

这是编写MongoDB node 的人的一句话.js客户端模块:

"当你的应用启动并重新使用时,你打开do MongoClient.connect一次

Mongodb相关问答推荐

Mongoose 排除数组中包含特定嵌套对象的文档

如何对 MongoDB setWindowFields 中当前文档以外的文档进行操作

如何在mongodb中级联删除文档?

如何将 MongoDB 集合中的 _id 字段更改为 User_id?

当属性确实存在时,为什么mongoose模型的 hasOwnProperty 返回 false?

如何将查询结果(单个文档)存储到变量中?

如何检索 MongoDb 集合验证器规则?

mongodump 是否锁定数据库?

MongoDB 1.6.5:如何重命名集合中的字段

从性能Angular 来看 MongoDB 嵌入式与参考

Mongoose:填充填充字段

如何在 Mongoose 中更新数组值

如何使用node.js http服务器从mongodb返回大量行?

Ruby 按键值分组哈希

多次使用位置 `$` 运算符来更新嵌套数组

判断字段是否存在于数组的子文档中

python + pymongo:如何从 for 循环中在 mongo 中的现有文档上插入新字段

Mongoose upsert 不创建默认模式属性

对象不是 JSON 可序列化的

Meteor `Deps.autorun`与`Collection.observe`