如何解决节点js + redis + mongodb Web应用程序中的竞争条件

时间:2019-04-02 08:01:36

标签: node.js mongodb redis race-condition node-redis

我正在构建一个Web应用程序,它将每秒处理许多事务。我正在将Express Server与Node Js一起使用。在数据库方面,我正在使用Redis存储用户的属性,该属性将根据股票价格而持续波动。我正在使用MongoDB来存储半永久属性,例如订单配置,用户配置等,

当同时处理一个用户下的多个订单时,我遇到了竞争问题,但是只有一个可以作为对存储保证金的Redis属性的支票而不能进行这两项交易的条件。

另一个问题是我的应用程序逻辑交错了Redis和MongoDB的读写访问。那么我将如何解决两个数据库之间的竞争条件

我正在考虑尝试在Redis上进行WATCH和MULTI + EXEC,以确保给定用户一次仅发生一次事务。 或者,我可以在Node / Redis上设置一个队列,该队列将一个接一个地处理订单。我不确定哪种方法正确。或如何实施它。

这都是伪代码。在多个条件下,应用程序逻辑要复杂得多。 我觉得我的整个应用程序逻辑都是至关重要的部分(我认为这是一件坏事)


//The server receives a request from Client to place an Order
getAvailableMargin(user.username).then((margin) => { // REDIS call to fetch margin of user. This fluctuates a lot, so I store it in REDIS
            if (margin > 0) {
                const o = {  // Prepare an order
                    user: user.username,
                    price: orderPrice,
                    symbol: symbol
                }

                const order = new Order(o);
                order.save((err, o) => { // Create new Order in MongoDB
                        if (err) {
                            return next(err);
                        }
                        User.findByIdAndUpdate(user._id, {
                            $inc: {
                                balance: pl
                            }
                        }) // Update balance in MongoDB
                        decreaseMargin(user.username) //  decrease margin of User in REDIS
                    );

                }

            });



考虑保证金为1,而每笔新订单保证金减少1。

现在,如果同时接收到两个请求,则两个请求的Redis余量将为1,从而导致竞争状况。此外,由于这一结果,现在将在MongoDB中打开两个订单。实际上,在第一个订单末尾时,边距应为0,而第二个订单应已被拒绝。 另一个问题是,我们现在继续进行,并两次更新了MongoDB中用户的余额,每个订单一个。

期望不应该执行订单之一,而应该通过检查Redis中的新保证金来重试。用户的余额也应该只更新一次。

基本上,我是否需要在Redis和MongoDB上实现监视 并且如果任何受监视的字段/文档发生更改,则以某种方式重试事务? 那有可能吗?还是我可能会缺少一个更简单的解决方案?

0 个答案:

没有答案