在v4真正意味着什么之前,MongoDB不符合ACID标准?

Lan*_*ard 223 sql database acid mongodb nosql

我不是数据库专家,也没有正式的计算机科学背景,所以请耐心等待.我想知道如果你使用v4之前的旧版MongoDB,可能会发生现实世界的负面情况,这些版本不符合ACID标准.这适用于任何ACID不合规数据库.

我知道MongoDB可以执行Atomic Operations,但它们不支持"传统锁定和复杂事务",主要是出于性能原因.我也理解数据库事务的重要性,以及数据库何时用于银行的示例,并且您正在更新所有需要同步的多个记录,您希望事务恢复到初始状态(如果有)停电所以信贷等于购买等

但是当我开始讨论MongoDB时,我们这些不了解数据库实际实现方式的技术细节的人开始抛出以下语句:

MongoDB比MySQL和Postgres更快,但是有一个很小的机会,比如百万分之一,它"无法正确保存".

"无法正确保存"部分指的是这样一种理解:如果在您写入MongoDB的那一刻就出现断电,那么就有机会获得特定记录(比如你在跟踪具有10个属性的文档中的综合浏览量)每个),其中一个文件只保存了5个属性...这意味着随着时间的推移,你的网页浏览计数器将"略微"关闭.你永远不会知道多少,你知道他们将是99.999%正确,但不是100%.这是因为,除非您特意将其作为mongodb原子操作,否则操作不能保证是原子操作.

所以我的问题是,对于何时以及为什么MongoDB可能无法"正确保存"的正确解释是什么?ACID的哪些部分不满足,在什么情况下,以及您如何知道0.001%的数据何时关闭?不能以某种方式解决这个问题吗?如果没有,这似乎意味着您不应该users在MongoDB中存储像表这样的内容,因为记录可能无法保存.但话说回来,1/1,000,000用户可能只需要"再次尝试注册",不是吗?

我只是在寻找一个列表,列出了何时/为什么会出现像AIOD不合规数据库(例如MongoDB)的负面情况,理想情况下是否有标准的解决方法(比如运行后台作业来清理数据,或者只使用SQL等等) .

Wil*_*m Z 132

实际上,MongoDB不符合ACID标准是不正确的.相反,MongoDB 在文档级别是ACID-compilant .

对单个文档的任何更新都是

  • 原子:它要么完全完成要么完全没有
  • 一致:没有读者会看到"部分应用"的更新
  • 隔离:再次,没有读者会看到"脏"读
  • 耐用:(有适当的写作关注)

MongoDB没有的是事务 - 即可以回滚且符合ACID的多文档更新.

请注意,您可以使用两阶段提交在单个文档的ACID兼容更新之上构建事务.

  • 将ACID放在单个文档的级别上,这在某种程度上等同于RDBMS中的单个记录在许多情况下是没有用的.事务的术语与单个表无关,你甚至可以有一个两阶段提交的机制并涉及几个XAResource,因此将单个文档称为ACID兼容有些问题,恕我直言. (9认同)
  • 同意Yair."在文档级别符合ACID"并不是卖点.它基本上只是意味着"不符合ACID".ACID从来就不是"只有一行/文档/实体".它是关于在整个数据库中保持数据一致. (5认同)
  • 请注意,两阶段提交的事务不符合ACID.出于某种原因,我推断了反面,直到我按照链接. (3认同)

Bry*_*isi 131

MongoDB失去的一件事是多集合(表)事务.MongoDB中的原子修饰符只能对单个文档起作用.

如果您需要从库存中删除项目并同时将其添加到某人的订单 - 您不能.除非这两件事 - 库存和订单 - 存在于同一文件中(他们可能不会).

我在我正在处理的应用程序中遇到了同样的问题,并有两种可供选择的解决方案:

1)尽可能地构建您的文档并尽可能使用原子修饰符,对于剩余的位,使用后台进程来清除可能不同步的记录.例如,我从库存中删除项目,并使用原子修饰符将它们添加到同一文档的reservedInventory数组中.

这让我总是知道清单中没有项目(因为它们是由客户保留的).当客户检查出来时,我会从reservedInventory中删除这些项目.它不是一个标准的交易,因为客户可以放弃购物车,我需要一些后台流程来查找废弃的购物车并将预留的库存移回可用的库存池.

这显然不太理想,但它是mongodb不能完美满足需求的大型应用程序的唯一部分.此外,它迄今为止完美无瑕.对于许多场景来说,这可能是不可能的,但由于我使用的文档结构,它很适合.

2)将事务数据库与MongoDB结合使用.通常使用MySQL为绝对需要它们的东西提供事务,同时让MongoDB(或任何其他NoSQL)做它最擅长的事情.

如果#1的解决方案从长远来看不起作用,我将进一步研究将MongoDB与MySQL结合起来,但现在#1非常适合我的需求.

  • "*MongoDB中的原子修饰符只能用于单个集合*"=>我认为你的意思是"针对单个**文档**". (27认同)
  • 缺乏多文档ACID交易不再是这种情况.MongoDB宣布他们将进入v4.0.请参阅https://www.mongodb.com/blog/post/multi-document-transactions-in-mongodb (5认同)
  • 优秀的信息,除了建议使用 MySQL 之外,通常是一个很好的答案。 (2认同)
  • 就目前而言,由于 MongoDB 4.0 是 ACID 兼容的 https://www.mongodb.com/transactions ,具有多文档事务。看看https://www.mongodb.com/blog/post/mongodb-multi-document-acid-transactions-general-availability (2认同)

duf*_*ymo 34

"星巴克不使用两阶段提交"中包含了一个很好的解释.

它不是关于NoSQL数据库,但它确实说明了有时您可以承担丢失事务或暂时使数据库处于不一致状态的问题.

我不认为它是需要"修复"的东西.修复是使用符合ACID的关系数据库.当其行为符合您的应用程序要求时,您选择NoSQL替代方案.


小智 16

我认为其他人已经给出了很好的答案.但是,我想补充说有ACID NOSQL数据库(如http://ravendb.net/).因此,不仅是决定NOSQL - 没有ACID与ACID的关系....


Ser*_*gey 12

"无法正确保存"可能意味着:

  1. 默认情况下,MongoDB不会立即将更改保存到驱动器.因此,您可能会告诉用户"更新成功",发生断电并且更新丢失.MongoDB提供了控制更新级别"持久性"的选项.它可以等待其他副本接收此更新(在内存中),等待写入发生在本地日志文件等.

  2. 多个集合甚至同一集合中的多个文档都没有简单的"原子"更新.在大多数情况下,这不是问题,因为它可以通过两阶段提交来规避,或者重构您的模式,以便对单个文档进行更新.请参阅此问题:文档数据库:冗余数据,引用等(MongoDB专门)


Gri*_*nik 9

从MongoDB v4.0开始,将支持多文档ACID事务.通过快照隔离,事务将提供全局一致的数据视图,并强制执行全有或全无执行以维护数据完整性.

他们感觉像来自关系世界的交易,例如:

with client.start_session() as s:
    s.start_transaction()
    try:
        collection.insert_one(doc1, session=s)
        collection.insert_one(doc2, session=s)
        s.commit_transaction()
    except Exception:
        s.abort_transaction()
Run Code Online (Sandbox Code Playgroud)

请参阅https://www.mongodb.com/blog/post/multi-document-transactions-in-mongodb


小智 5

对单个集合进行原子修改工作的唯一原因是 mongodb 开发人员最近用集合范围的写锁交换了数据库锁。认为增加并发性是值得进行权衡的。从本质上讲,mongodb 是一个内存映射文件:它们将缓冲池管理委托给机器的虚拟机子系统。因为它总是在内存中,所以他们能够摆脱非常粗粒度的锁:您将在持有它的同时执行仅内存中的操作,这将非常快。这与传统的数据库系统有很大不同,传统的数据库系统有时被迫在持有页锁或行锁的情况下执行 I/O。


Ely*_*Ely 5

请阅读ACID 属性以获得更好的理解。

同样在 MongoDB 文档中,您可以找到一个问题和答案

MongoDB 不符合 ACID。阅读以下内容,了解有关 ACID 合规性的讨论。

  1. MongoDBA仅在文档级别是主题。它不符合我们从关系数据库系统中知道的原子的定义,特别是上面的链接。从这个意义上说,MongoDB 不符合 ACID 中的 A。
  2. C默认情况下,MongoDB 是现场的。 但是,您可以从副本集中的辅助服务器读取。在这种情况下,您只能具有最终一致性。如果您不介意阅读稍微过时的数据,这将非常有用。
  3. MongoDB 不保证I隔离(再次根据上面的定义):
  1. 对于具有多个并发读写器的系统,MongoDB 将允许客户端在写操作返回之前读取写操作的结果。
  2. 如果 mongod 在日志提交之前终止,即使写入成功返回,查询可能会读取在 mongod 重新启动后将不存在的数据。

但是,MongoDB 会单独修改每个文档(用于插入和更新);仅在文档级别,而不是多文档交易。

  1. 关于D可用性 - 您可以使用该write concern选项配置此行为,但不确定。也许有人知道得更好。

我相信正在进行一些研究,以将 NoSQL 转向 ACID 约束或类似的约束。这是一个挑战,因为 NoSQL 数据库通常更快(更)并且 ACID 约束会显着降低性能。


小智 5

“在 MongoDB 中,对单个文档的操作是原子的” -这就是过去的事情

\n\n

在新版本的 MongoDB 4.0中您可以:

\n\n
\n

然而,对于需要更新多个文档的原子性或多个文档的读取之间的一致性的情况,MongoDB 提供了针对副本集执行多文档事务的能力。多文档事务可以跨多个操作、集合、数据库和文档使用。多文档事务提供\xe2\x80\x9call-or-nothing\xe2\x80\x9d 命题。当事务提交时,事务中所做的所有数据更改都会被保存。如果事务中的任何操作失败,事务将中止,并且事务中所做的所有数据更改都将被丢弃,并且不会变得可见。在事务提交之前,事务中的任何写操作在事务外部都是不可见的。

\n
\n\n

尽管对于如何执行操作和执行什么操作几乎没有限制。

\n\n

检查 Mongo 文档。\n https://docs.mongodb.com/master/core/transactions/

\n