MongoDB在CAP理论中的位置是什么?

158

到处都能看到 MongoDB 是 CP 的。 但是,当我深入了解后发现它实际上是最终一致的。 如果我使用 safe=true,它还是 CP 吗?如果是这样的话,这是否意味着当我使用 safe=true 写入时,所有复制品在获取结果之前都会得到更新?

8个回答

138

MongoDB默认具有很强的一致性 - 如果您进行写入,然后进行读取,假设写入成功,则始终可以读取刚刚读取的写入结果。这是因为MongoDB是单主系统,默认情况下所有读取都会转到主服务器。如果您选择启用从节点读取,则MongoDB变为最终一致性,其中可能会读取过时的结果。

通过副本集中的自动故障转移,MongoDB还获得了高可用性: http://www.mongodb.org/display/DOCS/Replica+Sets


19
根据 https://aphyr.com/posts/322-call-me-maybe-mongodb-stale-reads,即使你从副本集中的主节点读取数据,你也可能会得到旧的或脏数据。因此,MongoDB是否具有强一致性? - Mike Argyriou
4
Kyle的实验真是让人惊叹,它真的能够追踪Mongo。我想知道是否有生产系统,例如使用MongoDB进行支付交易?如果只是个人网站,那么谁会在乎强一致性呢。 - xin
10
仅供参考,MongoDB v3.4通过了Kyle设计的测试,因此,即使使用复制集和分片,MongoDB也是强一致的:https://www.mongodb.com/mongodb-3.4-passes-jepsen-test - Maxime Beugnet
4
由于MongoDB可以根据配置在某些时候牺牲可用性,因此这个答案可能过于简单。JoCa更好地解释了它表现为CA/CP/AP的情况。 - PaoloC
7
记录一下,我不再完全支持9年前在这里发表的原始评论。CAP理论是一种糟糕的方式来思考像这样的系统,因为它是对现实的极度简化。在网络分区存在的情况下,一致性和可用性是一个有很多小权衡的光谱,而不是单一的二进制。虽然这篇文章中所有的答案都有点过于简单化,包括我的,JoCa的可能最接近完整的图景。 - stbrody
显示剩余2条评论

73
我同意Luccas的帖子。你不能仅仅说MongoDB是CP/AP/CA,因为它实际上是C、A和P之间的权衡,这取决于数据库/驱动程序配置和灾难类型:下面是一个视觉总结,以及更详细的解释。
场景 主要关注点 描述
无分区 CA 系统可用并提供强一致性 分区,大多数连接 AP 旧主节点的未同步写入将被忽略 分区,大多数未连接 CP 仅提供读取访问以避免分离和不一致的系统
一致性:

当您使用单个连接或正确的写入/读取关注级别这将导致执行速度降低)时,MongoDB是强一致的。一旦不满足这些条件(特别是在从次要副本读取时),MongoDB就会变成最终一致性。

可用性:

MongoDB通过副本集实现高可用性。一旦主服务器下线或无法使用,那么副本将确定一个新的主服务器以便再次提供服务。但是这样做有一个缺点:所有由旧主服务器执行但未同步到副本的写操作将被回滚并保存到回滚文件中,一旦它重新连接到集合中(旧主服务器现在是副本),就会发生这种情况。因此,在这种情况下,为了可用性而牺牲了一些一致性。

分区容错性:

通过使用上述的副本集,MongoDB还实现了分区容错性:只要Replica-Set的服务器数量超过一半相互连接,就可以选择一个新的主服务器。为什么呢?为了确保两个分离的网络不能同时选择一个新的主服务器。当没有足够的副本服务器相互连接时,您仍然可以从它们中读取(但不保证一致性),但不能写入。为了保持一致性,该集合在实际上是不可用的。

如果我使用了正确的写入/读取关注级别,这意味着所有的写入和读取都会发送到 primary 节点(如果我理解正确的话),那么二级节点究竟是做什么的呢?只是待机等待主节点宕机吗? - tomer.z
@tomer.z 你可能想阅读手册中的此部分:您可以使用secondary进行读取。如果您正在使用“majority”读取级别,则只要大多数成员确认了读取,读取就是有效的。对于“majority”写入级别也是如此。如果您同时使用“majority”关注级别,则具有一致的数据库。您可能想在手册中了解更多信息。 - JoCa

24
作为一篇出色的新文章和Kyle在这个领域做了一些令人惊叹的实验,当你给MongoDB和其他数据库打上C或A的标签时,你需要小心谨慎。
当然,CAP有助于追踪数据库的优势,但人们经常忘记CAP中的C代表原子一致性(线性化),例如。当我试图进行分类时,这使我非常痛苦。因此,除了MongoDB提供强一致性之外,这并不意味着它是C。因此,如果要进行这些分类,我建议还要更深入地了解它的实际工作方式,以免留下任何疑问。

13

当使用 safe=true 时,数据已经被写入到主节点磁盘,这就是所谓的CP模式。

如果你想确保数据也已经被写入一些副本中,请查看 'w=N' 参数,其中N表示需要保存数据的副本数。

欲了解更多信息,请参见 此文档此问答


6

在出现分区(Partition)时,MongoDB会选择一致性(Consistency)而非可用性(Availability)。这意味着在分区情况下,它会选择保证数据一致性的方式。

为了更好地理解这个问题,让我们先了解 MongoDB 的副本集是如何工作的。一个副本集有一个主节点,提交数据的唯一“安全”方式是写入该节点并等待该数据提交到集合中大多数节点(发送写入请求时可以看到w=majority标志)。

分区可能发生在以下两种情况:

  • 当主节点宕机时:系统变得不可用,直到选出一个新的主节点。
  • 当主节点与太多次要节点失去连接时:系统变得不可用。其他次要节点将尝试选举新的主节点,当前主节点将被撤换。

总之,每当出现分区并需要做出决策时,MongoDB会选择一致性优先于可用性。它将停止接受对系统的写入操作,直到它相信它可以安全地完成这些写入操作。


它将停止接受对系统的写入,直到它相信可以安全地完成这些写入。那么读取呢?在此期间,它是否仍然保持可读状态? - Josh
如果您指定了“primaryPreferred”、“secondaryPrefered”、“secondary”或“closest”的读取偏好,则它仍将保持可读。 - OxygenThief

4

Mongodb从不允许在副本集的secondary节点上进行写操作,但是可以选择性地从secondary节点读取数据,如果你的primary节点出现故障,你就无法进行写操作,直到一个secondary节点成为primary节点。这就是你在CAP定理中牺牲高可用性的方式。通过只从primary节点读取数据,您可以实现强一致性。


3
我不确定Mongo的P是什么意思。想象一下这种情况:
- 您的副本被分成两个分区。 - 写入继续在两侧进行,因为新的主节点已经选举出来。 - 分区得到解决 - 所有服务器现在都重新连接了。 - 发生的是选举出了新的主节点 - 那个具有最高操作日志的节点,但来自另一个主节点的数据会被还原到分区之前的公共状态,并被转储到文件中以进行手动恢复。 - 所有从节点都追上了新的主节点。
问题在于转储文件大小是有限制的,如果您长时间处于分区状态,则可能永久丢失数据。
可以说这种情况不太可能发生 - 是的,除非在云中,那里比人们想象的更常见。
这个例子说明在给任何数据库分配任何字母之前,我会非常小心。有很多场景和实现并不完美。
如果有人知道这种情况是否在Mongo的后续版本中得到解决,请评论!(我有一段时间没有关注所有的事情了...)

5
MongoDB的选举协议旨在最多有一个Primary节点。只有经过配置的副本集投票成员的严格多数(n/2+1)才能选举(并保持)一个Primary节点。在网络分区的情况下,只有拥有大多数投票成员的分区可以选举出Primary节点;少数分区中的原Primary节点将会下台成为Secondary节点。这是副本集一直以来都采用的方式。如果前任Primary节点接受了未被复制的写入操作,在该节点重新加入副本集时,这些写入操作将被回滚(保存到磁盘)。 - Stennie

1
Mongodb放弃了可用性。当我们在CAP定理的背景下谈论可用性时,它是关于避免可能会崩溃的单点故障。在mongodb中,有一个主路由器主机。如果它崩溃了,那么在选举新的替代服务器来取代它的时间内就会有一些停机时间。实际上,这会很快发生。我们有几个热备份准备好了。因此,一旦系统检测到主路由器主机崩溃,它就会立即切换到一个新的主机。技术上来说,它仍然是单点故障。当这种情况发生时仍有可能出现停机时间。

enter image description here

有一个配置服务器,它是主服务器,我们还有一个应用服务器,在任何时候都是主服务器。即使我们有多个备份,如果其中任何一个服务器出现故障,系统仍然会有短暂的停机时间。系统必须先检测到故障,然后剩余的服务器需要重新选举一个新的主机来替代它。这可能需要几秒钟的时间,足以说明MongoDB正在权衡可用性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接