node.js + mongo +多个实体的原子更新=头痛

mar*_*ark 5 concurrency mongodb node.js

我的设置:

  1. Node.js的
  2. Mongojs
  3. 一个包含两个集合的简单数据库 - 库存和发票.
  4. 用户可以同时创建发票.
  5. 发票可以指几个库存物品.

我的问题:

保持库存完整性.想象一下,一个场景是两个用户提交了两个重叠项目集的发票.

一个天真(和错误)的实现将执行以下操作:

  1. 对于发票中的每个项目,请阅读清单集合中的相应项目.
  2. 修正库存物料的数量.
  3. 如果任何项目数量低于零 - 请将相关消息的请求放弃给用户.
  4. 保存库存物料.
  5. 保存发票.

显然,这种实现很糟糕,因为两个用户的动作将相互交错并相互影响.在典型的阻塞服务器+关系数据库中,这通过复杂的锁定/事务方案来解决.

什么是解决这个问题的点头+ mongoish方式?node.js平台是否提供了这些东西的工具?

Ale*_*Gad 5

您可以查看MongoDB的两阶段提交方法,或者您可以完全忘记事务并通过服务总线方法解耦您的流程.以亚马逊为例 - 他们将允许您提交订单,但他们无法确认,直到他们能够保护您的库存物品,收取您的卡等等.这不会发生在一次交易中 - 这是一个可以单独进行的一系列步骤,并且可以在必要时应用补偿步骤.

一个简单的总线实现将执行以下操作(请记住,这只是一个通用的建议供您使用,确切的实现将取决于您对并发的特定需求等):

  1. 将订单放在队列上.此时,您可以继续让您的客户等待,或者您可以感谢他们的订单,并让他们知道他们将在处理完成后收到电子邮件.
  2. "库存工人"将获取订单并锁定其需要保留的库存物料.这可以通过许多不同的方式完成.使用Mongo,您可以创建一个每个orderid都有一个文档的集合.该文档的ID是库存物品ID和合理的TTL(比如说30秒).只要工作人员具有锁定,它就可以管理其锁定的项目的库存级别.一旦进行了更改,它就可以删除"锁定"文档.
  3. 如果另一个工作人员想要在锁定时管理同一个项目,您可以将阻止的工作人员置于睡眠模式X秒然后重试,或者更好的是,您可以将请求放回到消息总线上以便接收后来由另一名工人.
  4. 一旦工人解决了所有库存物品,它就可以在服务总线上放置另一条消息,表明应该向卡收费,或者处理应该收到通知以提取库存,或者可以将电子邮件发送给制作者订单等等

听起来很复杂,但是一旦你有一个消息总线设置,它实际上相对简单. 可在此处找到节点消息总线实现列表.

一些开发人员甚至会完全跳过正式的消息总线并使用数据库作为他们的消息传递引擎,它可以在简单的实现中工作.谷歌Mongo和队列.

如果您不期望超过1个服务器并且消息总线实现过于庞大,节点可以为您处理锁定和消息传递.例如,如果您确实想要使用节点锁定,则可以创建一个存储库存项目ID的数组.坦率地说,我认为消息总线是最好的方式.无论如何,这里是我过去使用的一些代码,用于处理与Node的简单外部资源锁定.

// attempt to take out a lock, if the lock exists, then place the callback into the array.
this.getLock = function( id, cb ) {

        if(locks[id] ) {
            locks[id].push( cb );
            return false;
        }
        else {
            locks[id] = [];
            return true;
        }
    };

// call freelock when done
 this.freeLock = function( that, id ) {
            async.forEach(locks[id], function(item, callback) {
                item.apply( that,[id]);
                callback();
            }, function(err){
                if(err) {
                  // do something on error
                }

                locks[id] = null;

            });
        };
Run Code Online (Sandbox Code Playgroud)