【问题标题】:ExpressJS - How to handle simultaneous requests? Requests seem to block one another.ExpressJS - 如何处理同时请求?请求似乎相互阻止。
【发布时间】:2014-02-10 20:31:51
【问题描述】:

我有以下代码

var express = require('express');
var routes = require('./routes');    
var http = require('http');
...
app.get('/a',function(){
  Card.findCards(function(err, result){  //Mongoose schema
    res.send(result); //Executes a query with 9000 records
  })  
});
app.get('/b', function(req, res){
  res.send("Hello World");
});

我发现当我在 localhost/a 上获取时,大约需要 2.3 秒才能完成。这并不奇怪,因为它从数据库中获取了相当多的数据。但是我发现如果在 /a 加载时获取 /b,b 将不会显示。就好像对 /a 的调用阻止了对 /b 的调用。

这是 express 应该如何工作的吗?我一直假设各个路由是异步的,因为它们接受回调,但似乎 express 一次只能处理一个请求。在调用 res.end() 之前,不会处理其他请求。我是否缺少任何我需要做的配置?

作为参考,这是我连接猫鼬的方式

mongoose.connect(dbConnectionString, {server:{poolSize:25}});

这是我的http服务器初始化部分

http.globalAent.maxSockets = 20; // or whatever

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

编辑:这是卡片模型和相关架构 + 函数的代码

//Card.js
var mongoose = require('mongoose')
  , Schema = mongoose.Schema;

var CardSchema = new Schema({
  _id : {type: String},
  stores : [{
        store: {type: Schema.Types.ObjectId, ref:'StoreModel', required: true}
      , points: {type: Number, required: true}
  }]
});

exports.findCards = function(callback){
  var query = Card.find({}, callback); 
}

【问题讨论】:

    标签: node.js asynchronous express


    【解决方案1】:

    您可以设置精益选项。

    启用了精简选项的查询返回的文档是纯 JavaScript 对象,而不是 MongooseDocuments。他们没有应用保存方法、getter/setter 或其他 Mongoose 魔法。

    例子:

    new Query().lean() // true
    new Query().lean(true)
    new Query().lean(false)
    
    Model.find().lean().exec(function (err, docs) {
      docs[0] instanceof mongoose.Document // false
    });
    

    mongoose documentation

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题,设置与您的类似。有两个问题,它们都有相同的根本原因:节点具有非阻塞 I/O 操作,但是(正如 bbozo 指出的那样)CPU 密集型操作确实阻塞了它。

      第一个问题在于你的猫鼬电话。在 mongoose 从您的集合中检索文档后,它将它们转换为 mongoose 对象。如果您获得 9000 条记录,它将执行 9000 次。有问题的行在猫鼬的query.js 库中;查看其completeMany 函数上的for 循环以查找相关的阻塞操作。

      第二个问题出现在 Express 对生成的 JSON 对象进行字符串化以发送您的响应时。罪魁祸首是 Express 的 response.js 库下的 res.json 函数。对于大型响应,stringify 的阻止性质将很明显。

      我不太确定如何解决这个问题。您可能会尝试使用 mongodb 的本机库,而不是 mongoose。您也可以尝试修补 Express,使其使用 JSON 流调用而不是阻塞字符串化。您的查询和响应的分页也会有所帮助,但我知道实现起来并不简单。

      【讨论】:

      • 我同意上述观点。 OP 似乎在代码方面做了正确的事情,除了提取 9k 条记录然后序列化为 JSON 并在线发送 9k 条记录。无论您如何看待它,这永远不会扩大。分页,这样您就可以始终控制您的响应时间。
      【解决方案3】:

      我会试试的:)

      Afaik Node.js 在一般意义上不是异步的,它只是非阻塞的,如果一个连接什么都不做,那么另一个做某事的连接不会被什么都不做的连接阻塞,

      需要大量 reactor cpu 时间的事情(例如加载大量数据)会阻塞事件循环,请尝试以较小的块获取数据

      【讨论】:

      • 所以猫鼬数据库调用被阻塞了?我一直认为数据库调用——比如输入——是非阻塞的,因此使用回调。
      • Moongoose db 调用是非阻塞的,因为您的应用程序不会因等待 mongo 响应而被阻塞,但您的应用程序仍然需要缓冲和处理从 mongo 到达的数千条记录这会占用反应堆中的 CPU 周期
      • 这可能是真的,但我做了一个测试,其中我调用 res.send("hello world") 在 CPU 消耗猫鼬调用之前。甚至用简单的睡眠替换了猫鼬呼叫,同样的事情仍然发生。即使在猫鼬呼叫发生时,Express 仍会处理请求。因此,我的结论是,在任何给定时间,express 只能处理一个请求/响应对象。 app.get('/a',function(){console.log("a");res.send("a");Card.findCards(function(err, result){ console.log("done");})});
      • 我猜mongo连接可能不支持并行调用,但你需要从其他人那里得到这样的答案:)
      猜你喜欢
      • 1970-01-01
      • 2011-06-18
      • 1970-01-01
      • 1970-01-01
      • 2021-12-02
      • 1970-01-01
      • 2014-05-06
      • 1970-01-01
      • 2017-03-01
      相关资源
      最近更新 更多