MongoDB:多处理更新和 '$inc' 操作

标签 mongodb pymongo

我有一个关于在 MongoDB 中同时执行 $inc 更新的问题。在 UpdateOnefindOneAndUpdate 的手册页中,提到了应用并发 upsert 的微妙之处,并且始终建议使用唯一索引进行更新匹配。基本思想是,如果两个进程尝试更新某个不存在的文档,并且一个在另一个执行更新插入之前完成查询,那么如果没有唯一索引,每个进程都会创建一个新文档,从而导致重复。在这种情况下,确实定义一个唯一索引将防止它发生。

另一方面,如果我的update是一个增量操作,我想知道单靠唯一索引是否可以挽救这一天。让我们考虑一个简化的投票示例,其中文档如下所示:

{'name': 'Alice', 'votes': 0}, 
{'name': 'Bob', 'votes': 0}
...

假设 name 已被唯一索引(假设没有同名候选人)。假设许多进程正在收集投票并进行以下更新:

collection.update_one({'name': name}, {'$inc': {'votes': 1}}, upsert=False)

其中 name 是一个在别处定义的 python 变量。我想知道手册 ( see example ) 中的相同论点是否适用于此。

想象一下,在某个时刻,爱丽丝获得了 5 票。进程 A 和进程 B 都想给爱丽丝增加 1 票。如果两个进程配合得当,我们预计爱丽丝将获得 7 票。但是,如果进程 A 在 B 找到 Alice 的文档之后但在 B 开始进行增量之前找到了 Alice 的文档,那么进程 A 应该知道 Alice 有 5 票,与进程 B 相同。因此,即使 A 会在 B 之后进行修改释放写入锁,它会将票数更改为 5+1=6 票,而不是 7 票。

我是不是搞错了?我认为这与 $inc 以及单文档更新的实际工作方式有关,但我不确定,因为:

  1. $inc 手册页中似乎没有提到这条信息,

  2. 为此设计一个实验并不容易,因为为了让两个进程发生碰撞,似乎有必要拥有一个大型数据集。对于小型数据集,一个进程很容易找到所需的文档并在另一个进程到来之前对其进行修改。事实上,我做了一个对 2 个候选人进行投票的实验,无论名字是否被唯一索引都没有错。

任何关于定位和更新如何与 updateOnefindOneAndUpdate 一起工作的见解,以及 $inc 操作如何工作的任何见解都值得赞赏。

干杯!

最佳答案

为了理解readwrite,你需要理解MongoDB中的locking机制。

Starting in MongoDB 3.2, the WiredTiger storage engine is the default storage engine.

要点

The WiredTiger storage engine brings document level locking to MongoDB, meaning that writes no longer block a collection or database. While MMAP in 3.0 brought collection level locking, multiple writes to the same collection will still cause the writes to be applied serially and can starve reads from the collection as reads have to wait for the writes to finish. WiredTiger gets rid of the limitation allowing multiple writes to happen concurrently against the same collection. This means that writes and reads scale with the CPU, whereas in MMAP there was a low ceiling for CPU scaling as the locks reduced the throughput.

根据 WiredTiger 存储引擎

once a write request comes in, all readers are blocked until the write completes for a particular collection.

引用链接:1. OverviewLink , 2. aboutStorageEngin

查找并修改行为

Upsert and Unique Index

When the findAndModify command includes the upsert: true option and the query field(s) is not uniquely indexed, the command could insert a document multiple times in certain circumstances.

要防止创建多个重复文档,请在名称字段上创建唯一索引。有了唯一索引,多个 findAndModify 命令将表现出以下行为之一:

Exactly one findAndModify successfully inserts a new document. Zero or more findAndModify commands update the newly inserted document. Zero or more findAndModify commands fail when they attempt to insert a duplicate. If the command fails due to a unique index constraint violation, you can retry the command. Absent a delete of the document, the retry should not fail.

引用链接:here

关于MongoDB:多处理更新和 '$inc' 操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52753333/

相关文章:

mongodb - 创建 ObjectId 与让 DB 创建它

mongodb - pymongo 无法连接到主节点

python - pymongo.errors.InvalidOperation : cannot set options after executing query

python - 在 Pycharm 中导入 PyMongo 失败

python - 在 pymongo 的字典中包含 NumberInt

python - 使用 MongoEngine 动态文档将 None 保存到 MongoDB 中

php - 如何在 MongoDB 中的 $in 查询中使用 ObjectId?

mongodb - 解析服务器:是否可以为 mongodb 连接提供根证书?

mongodb - 如何通过避免 mongodb 聚合中的空值来 $lookup

node.js - Mongoose:跨多个领域的独特性