NodeJS和Mongo - 多个用户同时发送请求时出现意外行为

时间:2014-03-07 22:42:52

标签: node.js mongodb mongoose

我们一直在使用NodeJS和mongo(通过mongoose)来做一个非常简单的save()。我们有一个名为“highlight”的模型,它包含一个引用“response”的ObjectId数组。

这是高亮模型声明的相关部分

var highlightSchema = Schema({
  [...]
  , responses: [{type: ObjectId, ref: 'Response'}]
  [...]
});

我们通过先保存一个Response对象,然后将其推入一个Highlight对象,然后保存Highlight对象,将一个Response插入一个Highlight。非常简单,如下:

      Highlight.findOne({[...]}, function(err, highlight) {
        var response = new Response({[...]});
        response.save(function(err) {
          if(!err) {
            highlight.responses.push(response)
            highlight.save(function(err) {
              [...]
            })
          }
        });
      });

这大约99%以上的时间完全符合预期。 (注意:您可以放心地假设上面代码中的'highlight'变量确实包含有效的Highlight对象)

然而,我们在高峰时段越来越多地遇到孤立的问题,因为许多同样的要求是同时进行的。在一种情况下,成功创建了响应,但是将一个不同的响应推送到highlight.responses数组中。

这两个响应的时间戳显示它们相隔大约30毫秒创建。除了Highlight对象内的数组内容外,所有内容都完全按照预期创建。

由于我目前也正在深入研究很多操作系统的东西,我首先想到的是这可能是某种同步问题。但是节点是单线程的,我不觉得我对nodejs的事件循环如何工作有很好的理解,我甚至不能完全相信这是问题所在。

如果您有任何想法,或者我能够清楚地解释清楚,请告诉我。我很高兴详细说明。

谢谢!

2 个答案:

答案 0 :(得分:4)

您遇到了并发问题。您对模式进行建模的方式无法确保原子性,因此也是您遇到的问题。

避免此类问题并确保原子性的最佳选择是将Responses模型嵌套到Highlights模型中。

这样,您只能通过将Response元素直接推送到Highlight模型的Responses属性中来使用Highlights模型。

这是确保MongoDB原子性的唯一方法。

所以你会有这样的事情:

   +----------------------+
   |  Highlight model     |
   +----------------------+
   | _id 1                |
   |                      |
   | property 1: 'abc'    |
   | property 2: 'bla'    |
   | property 3: 123      |
   | responses:[          |
   |   +----------------+ |
   |   | Response _id 1 | |
   |   +----------------+,|
   |   | Response _id 2 | |
   |   +----------------+,|
   |   | Response _id 3 | |
   |   +----------------+,|
   |   | Response _id n | |
   |   +----------------+]|
   +----------------------+

不确定如何使用Mongoose,但在mongo shell中,如果你想用_id ObjectId('1234')添加对Highlight对象的响应,你可以这样做:

    db.highlights.update({_id: ObjectId('1234')},{$push:{Responses: {"Your response object"}}});

$push reference from MongoDB documentation

我很确定你必须能够以更简单的方式用Mongoose来完成它,可能只是浏览它的文档。

答案 1 :(得分:1)

要嵌套模型,您可以像这样编写Schema

const ResponseSchema = require('../where your schema file is')

var highlightSchema = Schema({
  [...]
  , responses: [ResponseSchema]
  [...]
});