首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在MongoDB中使用事务锁定防止争用条件

在MongoDB中使用事务锁定防止争用条件
EN

Stack Overflow用户
提问于 2022-07-11 04:29:43
回答 1查看 403关注 0票数 0

我有一个REST (分布在多个主机/容器中),它使用MongoDB作为数据库。在我的数据库中的集合中,我想关注本例中的UsersGames集合。

假设我有一个名为/join_game的端点(由用户/客户端调用)。此端点将逐步通过以下逻辑:

  1. 检查游戏是否打开(查询Games模型)
  2. 如果游戏是开放的,允许用户加入(继续使用下面的逻辑)
  3. 将player添加到Games模型中的参与者字段并更新该文档
  4. 更新Users文档中的一些字段(stats等)

并让另一个端点(由服务器上的cron作业调用)称为/close_game,它通过以下逻辑执行:

  1. 关闭游戏(更新Games模型)
  2. 确定获胜者并更新他们的统计数据( Users模型中的更新)

现在,我知道在每个端点处理的两个并发请求之间可能存在以下争用条件:

  1. 客户端- /join_game控制器调用的请求A到/join_game检查游戏是否是打开的(因此它继续进行端点逻辑的其余部分)
  2. 服务器内部调用的请求B到/close_game - /close_game控制器将游戏设置为在游戏文档中关闭

如果这些请求是并发的,请求A在请求B之前被调用,那么剩余的/join_game逻辑可能会被执行,尽管游戏技术上是锁定的。现在,这是我不想看到的明显的行为,可以带来许多错误/意想不到的结果。

为了防止这种情况,我研究了使用transaction,因为它使事务中的所有数据库操作都是原子化的。但是,我不确定事务是否真的解决了我的问题,因为我不确定它们是否对被查询和修改的文档设置了完整的锁(我看到mongodb使用共享锁进行读取,而使用排他锁进行写入)。如果它们确实设置了一个完整的锁,那么对事务中那些文档的其他数据库调用是否会等待这些事务完成呢?我还读到,如果事务在一段时间后等待(这也会导致不必要的行为),事务就会中止。

如果事务不是防止跨多个不同端点的竞争条件的方法,我想知道有什么好的替代方法。

最初,我使用内存中的队列来处理这些争用条件,这些条件似乎是在一个节点上运行REST的服务器上工作的。但是随着我的扩展,在分布式服务器中管理这个队列将成为一个更大的问题,所以如果可能的话,我想直接在mongo中处理这些竞争条件。

谢谢!

EN

回答 1

Stack Overflow用户

发布于 2022-07-11 08:48:39

据我理解,您似乎不需要使用MongoDB中的事务,但可以使用MongoDB原子更新操作

文档的每个操作一次只执行一个,这意味着如果您加入一个游戏,而关闭游戏被调用并首先执行,那么您就无法加入。

这就是为什么模式设计很重要的原因,您需要弄清楚如何对文档建模以允许原子更新来解决并发问题。用于更新其他集合,即视图,这可能是玩家赢/输/加入游戏的次数。我会让这一切最终在事件背后一致。

您还可以使用FindOneAndModify操作,它可以在更新完成后返回文档的新状态。这对于处理并发性非常有用。

代码语言:javascript
复制
db.test.insert({ _id: 1, name: "Game 1", players : [ ], isClosed: false})
db.test.insert({ _id: 2, name: "Game 2", players : [ ], isClosed: false})
db.test.insert({ _id: 3, name: "Game 2", players : [ ], isClosed: false})

db.test.update({ _id: 1, isClosed: false}, {$push: { players: 20} })
db.test.update({ _id: 1, isClosed: false}, {isClosed: true, players : [] })
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72933736

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档