【问题标题】:MongoDB Concurrency Question - FindOne, then FindOneAndUpdate AtomicityMongoDB 并发问题 - FindOne,然后 FindOneAndUpdate 原子性
【发布时间】:2021-02-27 15:57:05
【问题描述】:

感谢您在我将其提交给某些代码之前回答这个问题。

我已经查看了 MongoDB 上的多个文档和各种论坛来寻找这个问题的答案,但是,我想根据我的具体情况确切地知道某些系列操作是如何执行的。

基本上,我想在其自己的分片内对集合中的特定文档执行读取(findOne)操作,以获取其当前值,对其进行修改,然后将其存储回该文档(findOneAndUpdate)。这听起来很容易,但是,如果我理解正确的话,这个特定的文档可能会在读取和写入操作之间的延迟期间被写入。

有关更多上下文,这是一个基于股票市场的应用程序。我在这里指的分片和集合是用户的投资组合,其中包含诸如股票代码、拥有该股票的股票数量以及他们历史上为此支付的总成本等信息。这里的问题是,当玩家出售股份时,我必须通过乘以 (formerOwnedShares - executedSoldShares)/(formerOwnedShares) 的比率来按比例调整历史总成本,其中,formerOwnedShares 是需要读取、处理、然后更新的信息(即用户当前拥有 10 股,并随着时间的推移支付了 10 美元,他们卖出 5 股,现在他们拥有 5 股并支付 5 美元以维持一致的每股平均成本)。

我担心读取和更新操作之间的延迟。其他几个代码区域可以从其他用户(例如其他用户与他们购买/出售股票)对该投资组合文档进行操作,因此第一个读取操作很有可能从该文档的旧版本中提取信息,该版本具有最近才更新。

有没有办法在一个原子操作中处理这种情况以保持完美的并发性?问题显然是必须根据文档的最新值更新文档值的结果 - 我认为您无法在单个 findOneAndUpdate 操作中完成。

非常感谢您的宝贵时间。

【问题讨论】:

    标签: javascript database mongodb performance concurrency


    【解决方案1】:

    使用带有读取关注快照的事务,它是MVCC 的实现,以对两个操作(查找和查找并修改)使用相同的基本文档版本。

    有没有办法在一个原子操作中处理这种情况以保持完美的并发性?

    这个问题毫无意义。首先,“完美并发”是什么意思。其次,并发和序列化不一样(其实它们是完全相反的)。

    在并发环境中执行多个按顺序执行的操作的基线方法是 1) 在文档中维护“版本”字段,2) 在第二次和后续操作时,以版本不变为条件更新,3)如果更新失败,则重试整个过程,直到成功。

    具有快照读取问题的事务有望为您自动完成所有这些操作。

    【讨论】:

    • 谢谢,我试试这个。我对交易相当陌生,所以我还在学习它。调用会话时,这是否有效地将“锁定”在当前连接到分片上?假设多个会话从一个分片开始,这些会话本质上是排队等待在块中执行全有还是全无?我很难理解它是如何诚实执行的。
    • 不,会话不锁定。事务也不锁定。见en.wikipedia.org/wiki/Multiversion_concurrency_control
    • 我明白了。最后一个问题,例如:const session = client.startSession() await session.withTransaction(async () => {...,当在这里开始会话时,它对连接的分片有效地做了什么,允许跨多个其他分片、集合等进行多个原子查询?
    • 会议本身并没有多大作用,但这个问题的答案不适合评论,所以请在自己的问题中提问。
    • 您还继续使用“shard”这个词,但是 1)如果您从分片集群开始,这只会使事情变得复杂,并且 2)如果您不在分片集群中,正确的术语是是副本集的“节点”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多