使用mongodb在nodejs中使用锁定/事务读取和插入文档

问题描述 投票:0回答:4

在预订系统中,只有5个不同的用户可以创建预订。如果 100 个用户同时调用预订 api,如何使用锁定处理并发。我正在使用nodejs和mongodb。我浏览了 mongo 并发文章和 mongodb 中的事务,但找不到任何带有锁定的示例编码解决方案。

我已经通过乐观并发控制实现了解决方案(当资源争用较低时 - 这可以使用 versionNumber 或 timeStamp 字段轻松实现)。

提前感谢您向我建议锁定解决方案。

现在的算法是:

第 1 步:从 userSettings 集合中获取 userAllowedNumber。

//Query
db.getCollection('userSettings').find({})

//Response Data
{ "userAllowedNumber": 5 }

第2步,从预订集合中获取当前的bookedCount。

//Query
db.getCollection('bookings').count({ })

//Response Data
2

第3步,如果

bookedCount <= userAllowedNumber
则插入预订。

//Query
db.getCollection('bookings').create({ user_id: "usr_1" })
node.js mongodb mongoose mongodb-query
4个回答
4
投票

我在mongodb社区深入讨论了事务加锁的问题。在结论中,我了解到并发现了交易的局限性。我们没有可以使用锁来处理此任务的并发请求。

您可以在此链接查看完整的 Mongodb 社区对话 https://www.mongodb.com/community/forums/t/implementing-locking-in-transaction-for-read-and-write/127845

使用 Jmeter 测试的 Github 演示代码显示了限制,无法处理此任务的并发请求。 https://github.com/naisargparmar/concurrencyMongo

新的建议仍然欢迎和赞赏


1
投票

对于事务的简单示例,首先您需要有一个客户端连接到 MongoDB。

const client = new MongoClient(uri);
await client.connect();

一旦拥有客户端,您就可以创建一个可以进行交易的会话:

const session = await client.startSession();
const transactionResults = await session.withTransaction( async () => {
     await client.db().collection("example").insertOne(example);
}, transactionOptions);

随着

transactionOptions
是:

const transactionOptions = {
   readPreference: 'primary',
   readConcern: { level: 'majority' },
   writeConcern: { w: 'majority' }
};

在 MongoDb 文档中查找有关读/写问题的信息。 根据您的用例,您还可以考虑

findAndModify
在更改时锁定文档。


1
投票

为了解决您的问题,您还可以尝试使用Redlock(https://redis.com/redis-best-practices/communication-patterns/redlock/)进行分布式锁定或使用互斥锁进行实例锁定。


0
投票

另一种方法是自己编写或导入 https://github.com/Zurili/mongo-distributed-locks with

npm i mongo-distributed-locks

然后使用项目中的示例来包装您的代码:

import DLocks from 'mongo-distributed-locks'

async function createBooking(userId) {
  const lock = await DLocks.lock({
    resource: 'bookings',
    id: userId
  })

  try {
    await createBooking( userId )
  }
  finally {
    await DLocks.unlock(lock)
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.