MongoDB 文档操作是原子且隔离的,但它们是否一致?
我正在将应用程序从 App Engine 数据存储区移植到 MongoDB 后端,并对“文档更新”的一致性有疑问。我知道一个文档的更新都是原子的和隔离的,但是有没有办法保证它们在不同的副本集之间“一致”?
在我们的应用程序中,许多用户可以(并且将会)尝试通过在一次更新期间插入一些嵌入文档(对象)来同时更新一个文档。我们需要确保这些更新在所有副本中以逻辑一致的方式发生,即当一个用户将一些嵌入文档“放入”父文档中时,其他用户不能将其嵌入文档放入父文档中,直到我们确保他们已经阅读并收到第一个用户的更新。
所以我所说的一致性的意思是,我们需要一种方法来确保,如果两个用户尝试同时对一个文档执行更新,MongoDB 只允许其中一个更新进行,并丢弃另一个(或至少防止两者发生)。我们在这里不能使用标准的“分片”解决方案,因为单个更新不仅仅包含增量或减量。
保证一份特定文档的一致性的最佳方法是什么?
I'm in the process of porting my application from an App Engine Datastore to a MongoDB backend and have a question regarding the consistency of "document updates." I understand that the updates on one document are all atomic and isolated, but is there a way to guarantee that they're "consistent" across different replica sets?
In our application, many users can (and will) be trying to update one document at the same time by inserting a few embedded documents (objects) into it during one single update. We need to ensure these updates occur in a logically consistent manner across all replicas, i.e. when one user "puts" a few embedded documents into the parent document, no other users can put their embedded documents in the parent document until we ensure they've read and received the first user's updates.
So what I mean by consistency is that we need a way to ensure that if two users attempt to perform an update on one document at exactly the same time, MongoDB only allows one of those updates to go through, and discards the other one (or at least prevents both from occuring). We can't use a standard "sharding" solution here, because a single update consists of more than just an increment or decrement.
What's the best way of guaranteeing the consistency of one particular document?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
可能还有其他方法可以实现此目的,但一种方法是对文档进行版本控制,并仅针对用户之前阅读过的版本发布更新(即,确保自上次阅读以来没有其他人更新过该文档)。这是使用 pymongo 的此技术的一个简短示例:
请注意,上面的键“n”为 1,表明文档已
在此处更新,我们尝试针对错误的版本进行更新,键“n”为 0
请注意,此技术依赖于使用安全写入,否则我们不会收到指示已更新文档数量的确认。对此的一种变体是使用
findAndModify
命令,该命令将返回如果没有找到与查询匹配的文档,则返回None
(在 Python 中)。findAndModify
允许您返回文档的新版本(即应用更新后)或旧版本。There may be other ways to accomplish this, but one approach is to version your documents, and issue updates against only the version that the user had previously read (i.e., ensure that no one else has updated the document since it was last read). Here's a brief example of this technique using pymongo:
note in the above, key "n" is 1, indicating that the document was updated
here where we tried to update against the wrong version, key "n" is 0
Note that this technique relies on using safe writes, otherwise we don't get an acknowledgement indicating the number of documents updated. A variation on this would use the
findAndModify
command, which will either return the document, orNone
(in Python) if no document matching the query was found.findAndModify
allows you to return either the new (i.e. after updates are applied) or old version of the document.MongoDB 不提供主主复制或多版本并发。换句话说,写入总是到副本集中的同一台服务器。默认情况下,甚至禁用从辅助服务器的读取,因此默认行为是您一次仅与一台服务器通信。因此,如果使用原子修饰符(如
$inc、$push
等),则无需担心安全模式下结果不一致。如果您不想将自己限制在这些原子修饰符上,请按照 dcrosta 的建议进行比较和交换(以及 mongo docs)看起来是个好主意。然而,所有这些都与副本集或分片无关 - 在单服务器场景中是相同的。
如果您还需要在数据库/节点发生故障时确保读取一致性,则应确保在安全模式下写入大多数服务器。
如果允许不安全读取,这两种方法的行为会有所不同:原子更新操作仍然有效(但可能会产生意外结果),而比较和交换方法将会失败。
MongoDB does not offer master-master replication or multi-version concurrency. In other words, writes always go to the same server in a replica set. By default, even reads from secondaries are disabled so the default behavior is that you communicate only with one server at a time. Therefore, you do not need to worry about inconsistent results in safe mode if you use atomic modifiers (like
$inc, $push
, etc.).If you don't want to restrict yourself to these atomic modifiers, compare and swap as recommended by dcrosta (and the mongo docs) looks like a good idea. All this is not related to replica sets or sharding, however - it would be the same in a single-server scenario.
If you need to ensure read consistency also in case of a database/node failure, you should make sure you're writing to the majority of servers in safe mode.
The two approaches behave different if you allow unsafe reads: the atomic update operations would still work (but may give unexpected results), while the compare-and-swap approach would fail.