1

我们通过 Node.js 应用程序插入数据并使用node-mongodb-native库连接到 mongodb。Mongo DB 共有 5 个分片。节点和 mongos 实例包含在具有 14980MB RAM 的四核 AWS 实例上。两个分片和配置服务器包含在一个单核实例中,其余三个分片位于具有单核处理器的不同实例上。

我们可以使用 Node.js 测试脚本在 9 秒内有效地同时插入 1000 条记录。

对于 10000 个并发插入,其中大约 2000 个失败并返回以下错误消息:

    [Error: failed to connect to [ip address of mongos]]

在这 10000 次插入过程中,前 5000 或 6000 次插入是成功的,没有错误。在此期间,CPU 使用率保持相对较低(13% 的使用率)。然后一个核心上的 CPU 跳到 75% 左右,MongoDB 抛出错误消息拒绝连接。在一些插入失败之后,一些写入间歇性地成功。

我们在 linux 上将 ulimit -n 设置为 20000。我们在 Node.js api 的插入函数中传递了 poolSize=5 参数。

var responseHandlers = require('./responseHandlers')
    ,schemaValidation = require('./schemaValidation')
    ,mongoDb = require('mongodb')
    ,md5 = require('MD5')
    ,ObjectID = require('mongodb').ObjectID;

function insert(data, timestamp, response) {
  // validating the data to be inserted
  schemaValidation.validate(data, function(err) {
    if(err) {
      console.log(err);
      responseHandlers.invalidRequest(response, 2); 
    } else {
      //console.log("opening db..");
      server = new mongoDb.Server(mongoConfig.host,mongoConfig.port,{'auto_reconnect': true, 'poolSize': 5});
      db = new mongoDb.Db(mongoConfig.database, server, {w: 1});
      db.open(function(err, db) {
        if(err) { 
          console.log(err);
          responseHandlers.invalidRequest(response, 2); 
        } else {
          db.collection(mongoConfig.collection, function(err, collection) {
            if(err) {
              console.log(err);
              responseHandlers.invalidRequest(response, 2); 
            } else {
              //going to instantiate document fields
              var time = new Date().getTime(),
              oid = new ObjectID(),
              hash = md5(oid.toHexString()),
                            obj = {'data_utc' : timestamp, 'server_utc' : time, '_id' : oid,    'hash' : hash}; 
                            obj.data = data;
              //inserting..
              collection.insert(obj, {w:1}, function(err, result) {
                if(err) {
                  console.log(err);
                  responseHandlers.invalidRequest(response, 2); 
                } else {
                  console.log('Insert successful');
                  responseHandlers.validRequest(response, false, result);
                }   
              db.close();
              }); 
            }   
          }); 
        }   
      });   
    }   
  }); 
}   
exports.insert = insert;

谁能帮忙解释为什么它会拒绝连接,无法插入?为什么它对一部分插入有效,然后在中途失败?

4

2 回答 2

1

您似乎在循环中创建了太多连接。最好的方法是创建一个 mongoDB 客户端的单例实例,并为每次更新使用相同的对象,并在集合中插入。MongoDB 对连接池有限制,默认大小为 5 个连接。之后的任何尝试都将简单地拒绝服务器,但是您可以增加默认连接池大小,但这不是一个好主意。
另一点需要注意的是 MongoDB:在执行并发写入的线程数量有限的情况下表现更好。对于集合中的写入(使用最新的驱动程序 3.2),mongoDB 对集合执行行级锁定。它一次获取 1000 条记录的锁,并随着记录的更新而滑动锁。所以如果你把更多的并发线程做并行操作,它最终会等待锁被释放。最好使用 2 个线程进行写入,或者最多使用 4 个,块大小为 20k 或 40K。

您可以考虑实现受控读写的生产者/消费者模式。

有关详细信息,请在此处阅读:https ://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html

于 2016-08-08T15:22:59.910 回答
0

要解决此问题,您应该观察在 mongod 控制台中打开的连接数。根据您提供的代码示例,您可能会在每次插入时打开一个新的 mongodb 连接。要纠正此问题,请尝试将“服务器”的实例化移动到您用来调用此函数的控制循环范围之外。

于 2013-06-09T20:17:34.690 回答