具有node.js的MongoDB在Docker中运行明显的死锁但在Windows

时间:2017-03-15 19:50:31

标签: node.js mongodb docker mongoose integration-testing

问题

我在运行针对MongoDB实例的node.js服务器应用程序的集成测试时出现类似死锁的行为。我们的测试代码和服务器代码都使用Mongoose和node.js驱动程序来访问MongoDB。

测试框架删除数据库,并在每个测试套件的开头(或有时是单个测试)为每个集合重新创建索引。这种情况在测试过程中会多次发生。

类似死锁的行为似乎发生在对db.collection.ensureIndex的一系列调用期间。一旦发生这种情况,所有执行都将停止,直到测试超时到期,这将中止测试。如果我在没有超时的情况下运行测试,那么挂起似乎是永远的。

在这一点上,我觉得自己很挣扎,并希望听到关于调试方法或寻找线索的方向的建议。非常感谢。

详细

根据MongoDB Concurrency FAQensureIndex在没有background:true选项的情况下调用时需要独占数据库写锁('W')。但是,我已通过Mongoose调试日志验证,在这些调用期间使用了background:true,例如:

mails.ensureIndex({ expires: 1, mailType: 1, readOn: 1 }) { background: true }

但是,MongoDB日志(至少对我来说)显示尝试了的独占锁

command: createIndexes { createIndexes: "mails", indexes: [ { name: "expires_1_mailType_1_readOn_1", key: { expires: 1, mailType: 1, readOn: 1 }, background: true } ], writeConcern: { w: 1 } } numYields:0 reslen:113 locks:{ Global: { acquireCount: { r: 1, w: 1 } }, Database: { acquireCount: { w: 1, W: 2 }, acquireWaitCount: { w: 1, W: 2 }, timeAcquiringMicros: { w: 1027663, W: 193312 } }, Collection: { acquireCount: { w: 1 } } } protocol:op_query 1289ms

同时,当系统处于此状态时,我无法使用任何客户端连接到数据库,包括mongo CLI,mongotop,mongostat或node.js驱动程序。因此,我无法运行db.currentOp()db.serverStatus()来收集有关数据库状态的信息。一旦我终止测试,客户端就可以连接并且数据库恢复正常状态。我不知道这是否是由全局独占锁引起的,但确定似乎全局。

当node.js客户端代码在docker容器(运行Linux)中执行时,此问题会100%出现。但是,在Windows上针对完全相同的MongoDB实例运行相同的客户端代码时,它永远不会发生。

这让我想知道问题可能出在MongoDB的node.js驱动程序的Linux版本上。我在某种程度上对此进行了研究,但还没有找到任何结论。我正在设置容器外的另一个Linux环境,看看我是否可以重现那里的行为。

(编辑)我无法在我的Linux机器上重新解决问题,直接通过shell运行,或者在docker容器中运行。所以,我已经更新了这个问题的标题以反映这一点。此外,我已经在另一台Windows 10 Pro计算机上遇到了问题。

代码

删除数据库

mongoose.connection.db.dropDatabase(callback);

重建索引

// (inside a larger async.waterfall block)    
// Loop through all schemas and recreate all indexes.
_.each(mongoose.connection.base.modelSchemas, function (schema, key) {
    asyncFunctions.push(function (cb) {
        mongoose.model(key, schema).ensureIndexes(err => {
            return cb(err);
        });
    });
});

async.parallel(asyncFunctions, function (err) {
    return callback(err);
});

上下文

  • mongoose@4.4.20(mongodb@2.1.18)
  • connect-mongodb-session@1.3.0(mongodb@2.2.24)< - 不同的mongodb版本
  • node --version => v6.9.1
  • mongod --version => v3.2.12(来自https://hub.docker.com/_/mongo/
  • 主机操作系统:Windows 10专业版1607(OS Build 14393.693)
  • 访客操作系统:Linux 4.9.12-moby
  • Docker v.17.03.0-ce

其他

我并不是说这是一个真正的数据库死锁。我还不确定。它就像一个僵局。

我也尝试过使用 * mongoose@4.9.0(mongodb@2.2.24) * mongod --version => v3.4.2 这增加了驱动程序级别的超时,但是当我将它们设置为高时,类似死锁的行为仍然存在。

我尝试用每个集合调用collect.remove()来替换调用以删除数据库,但这花了很长时间才导致在该操作阶段超时。

我也尝试用每个集合的collection.drop()替换数据库drop,但这会将死锁移动到此操作阶段(而不是ensureIndex)。

最后,我尝试使用async.series()替换async.parallel()调用ensureIndexes(上面),但这只是延迟了死锁。

0 个答案:

没有答案