【问题标题】:Concurrent request handling in Node.js and MongoDBNode.js 和 MongoDB 中的并发请求处理
【发布时间】:2017-03-21 04:25:20
【问题描述】:

我有一个 Node.js 服务器,它必须处理 6 个并发请求。 每个请求都会从 MonogDB 数据库中读取一个文档,然后对其进行修改。

所以,当我们同时发送 6 个请求时,它们都读取相同的数据项并对其进行修改,但我希望第一个请求修改的值应该由第二个请求读取,然后它应该能够进一步修改它等等开。

例如, 我有一个名为 x 的数据项,初始值为“a”。 第一个请求将其修改为“ab”。所以,第二个请求现在应该是“ab”而不是“a”。但它总是读取“a”,因为它们是同时出现的。

我尝试应用信号量、互斥锁、async.series、async.waterfall、sleep 和 promise,但没有任何效果。可能我没有正确使用它们。那么,应该如何使用它们来同步处理这些并发请求呢?

或者还有其他方法吗?我们可以用时间戳排序协议做点什么吗?如果是,那么我如何在 Node.js 中应用它?

这是我要为这些并发请求运行的代码-

app.get('/urltest', function (req, res) {
    var q=require('url').parse(req.url,true).query;
    var s=q.s;

    MongoClient.connect(url, function(err, db) {
        if(err)
            throw err;
         db.collection( 'Comp' ).find({no:2}).snapshot().forEach(
            function (elem) {

                db.collection( 'Comp' ).findAndModify (
                    { no : elem.no },
                    [['no', 1]],
                    { $set : { age:elem.age+s } }, {new:true},
                    function( err, result ) {
                        if ( err ) console.log( err);

                        console.log("after update: "+result.value.age);
                        res.end("success");
                    }
                ); 
            });
    });
});

我在这里同时发送诸如 http://192.168.197.140:8081/urltest?s=bhttp://192.168.197.140:8081/urltest?s=chttp://192.168.197.140:8081/urltest?s=d 等请求。

现在,它们可以按任何顺序运行。但我希望附加所有“b”、“c”、“d”等。因此每个的输出应该看起来有点像 - 'ab'、'abc'、'abcd' 等等。

但我得到的输出是-'ab'、'ac'、'ad'。

我应该如何使用 Promise 来确保这些请求以同步方式执行?

【问题讨论】:

  • 如果大约同时有 6 个请求到达,你怎么知道应该先去哪一个,第二个,第三个,等等……?如果您需要有关您尝试过的某些特定代码解决方案的帮助,那么您必须向我们展示您尝试过的代码并解释您尝试它时发生的情况。让一项操作等待另一项操作完成并不难,但我们必须看看您到底想做什么(查看实际代码并了解实际算法)才能知道如何为您编写代码。
  • 您也可以创建一个访问队列。如果没有人在队列中访问特定数据项,那么它只会获取该项目。如果一个操作已经在进行中,那么下一个请求会进入队列,并在前一个请求完成后得到服务。使用 Promise 可以很容易地做到这一点。但是,要知道建议什么代码,我们需要查看您正在尝试执行的特定代码,并了解您如何知道哪些请求需要像这样序列化。
  • @jfriend00 我已经更新了问题并包含了我想要同步运行的基本代码。我尝试过使用 Promises,但它们也不起作用。对于访问队列,我尝试将这些传入请求存储在一个数组中,然后一个一个地访问它,但这也不起作用。那么,您能否详细说明我应该如何准确编写代码来实现我的结果?

标签: javascript node.js mongodb concurrency


【解决方案1】:

这听起来像是一个复杂的系统。我的建议是看看新的Mongo Node driver。 然后看看ECMAScript6 documentation。这涉及安装它使用的co 模块。像使用 Promise 一样使用 co(查看模块)。它为您提供返回承诺的 yield

听起来你还需要聚合(如果我没记错的话)。对于 a 然后 ab 然后 abc 等等。

并发问题显然应该通过等待yield返回来处理。新文档中的示例不是很好,但足以让您从中获得一个工作示例。

【讨论】:

    【解决方案2】:

    所以,我所要做的就是正确实现信号量。 这是代码的最终版本-

    var sem = require('semaphore')(1);      
    app.get('/urltest', function (req, res) {
    
        sem.take(function() {
    
            var q=require('url').parse(req.url,true).query;
            var s=q.s;                                  
    
            MongoClient.connect(url, function(err, db) {
                if(err)
                    throw err;
                db.collection( 'Comp' ).find({no:2}).snapshot().forEach(
                    function (elem) {                           
    
                        db.collection( 'Comp' ).findAndModify (
                            { no : elem.no },
                            [['no', 1]],
                            { $set : { x:elem.x+s } }, {new:true},          
                            function( err, result ) {
                                if ( err ) console.log( err);
    
                                console.log("after update: "+result.value.x);
                                res.end("success");
    
                                sem.leave();    
    
                            }
                        ); 
                    });
            });
        })
    });
    

    【讨论】:

      【解决方案3】:

      你需要实现一个semaphore

      阅读它here

      在您的情况下,您必须一次处理一个请求,尽管它们“一起”出现。所以

      var sem = require('semaphore')(1);
      var server = require('http').createServer(req, res) {
          sem.take(function() {
            // find, update and commit data before leaving the semaphore
            expensive_database_operation(function(err, res) {
              sem.leave();
      
              if (err) return res.end("Error");
      
              return res.end(res);
            });
          });
      });
      

      【讨论】:

      • 做到了。 Node.js 使用npm install semaphore 提供了一个信号量模块,但这也不起作用。我引用了这个链接-npmjs.com/package/semaphore。您能否详细说明如何在 node.js 中实现信号量?
      • 请告诉我你是如何实现信号量的。
      • var sem = require('semaphore')(1); sem.take(function() { var q=require('url').parse(req.url,true).query; var s=q.s; MongoClient.connect(url, function(err, db) { if(err) throw err; db.collection( 'Comp' ).find({no:2}).snapshot().forEach( function (elem) { db.collection( 'Comp' ).findAndModify ( { no : elem.no }, [['no', 1]], { $set : { age:elem.age+s } }, {new:true}, function( err, result ) { if ( err ) console.log( err); console.log("after update: "+result.value.age); res.end("success"); sem.leave();}); }); }); })
      • 仅以类似方式完成。刚刚添加了我的 MongoDB 查询来代替“expensive_database_operation”,并在其回调中执行了 sem.leave()。
      • 如果记录正确更新,您是否在更新后检查日志?因为这就是信号量正在做的事情。它使所有其他请求等到信号量离开。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多