MongoDB锁定写入的级别是多少? (或:“每个连接”是什么意思

时间:2013-07-03 19:35:24

标签: mongodb concurrency locking

在mongodb文档中,它说:

  

从版本2.2开始,MongoDB在每个数据库的基础上实现了大多数读写操作的锁。一些全局操作(通常是涉及多个数据库的短期操作)仍然需要全局“实例”广泛锁定。在2.2之前,每个mongod实例只有一个“全局”锁。

这是否意味着在我拥有3个与mongodb:// localhost / test的连接的情况下,来自网络上运行的不同应用程序 - 一次只能写一个?或者只是每个连接?

IOW:它是每个连接,还是整个/测试数据库在写入时被锁定?

4 个答案:

答案 0 :(得分:237)

MongoDB锁定不同

在MongoDB中锁定不像锁定RDBMS那样工作,因此需要进行一些解释。在早期版本的MongoDB中,只有一个全局读/写锁存器。从MongoDB 2.2开始,每个数据库都有一个读/写锁存器。

读者 - 作家闩锁

闩锁是多读者,单一作家,并且是作家贪婪的。这意味着:

  • 数据库中可以有无限数量的同时读者
  • 任何一个数据库中的任何集合中一次只能有一个编写器(稍后会详细介绍)
  • 作家封锁读者
  • 通过“作家贪婪”,我的意思是一旦写入请求进入,所有读者都会被阻止,直到写入完成(稍后会详细介绍)

请注意,我将其称为“闩锁”而不是“锁定”。这是因为它是轻量级的,并且在正确设计的模式中,写锁定保持在十几个微秒的量级。有关读者 - 作者锁定的更多信息,请参阅here

在MongoDB中,您可以根据需要运行任意数量的同步查询:只要相关数据在RAM中,它们都将得到满足而不会发生锁定冲突。

原子文档更新

回想一下,在MongoDB中,事务级别是单个文档。对单个文档的所有更新都是Atomic。 MongoDB通过只保留更新RAM中的单个文档所需的写锁存器来实现这一点。如果存在任何缓慢运行的操作(特别是,如果需要从磁盘中分页文档或索引条目),则该操作将产生写锁存器。当操作产生锁存器时,则可以继续下一个排队操作。

这意味着对单个数据库中所有文档的写入进行序列化。如果您的架构设计很差,并且您的写入需要很长时间,那么这可能是一个问题,但在正确设计的架构中,锁定不是问题。

作家贪婪

还有一些关于作家贪婪的话:

只有一位作家可以同时握住闩锁;多个读卡器可以一次握住闩锁。在一个天真的实现中,如果有一个读者在运行,作者可能会无限期地饿死。为了避免这种情况,在MongoDB实现中,一旦任何单个线程对特定锁存器发出写请求

  • 所有需要该锁存器的后续读者将阻止
  • 那位作家将等到所有现有读者完成
  • 写入器将获取写锁存器,执行其工作,然后释放写锁存器
  • 所有排队的读者现在都将继续

实际的行为是复杂的,因为这种作家贪婪的行为以不明显的方式与屈服相互作用。回想一下,从2.2版开始,每个数据库都有一个单独的锁存器,因此写入数据库'A'中的任何集合将获得一个单独的锁存器,而不是写入数据库'B'中的任何集合。

具体问题

关于具体问题:

  • 锁定(实际上是锁存)由MongoDB内核保留,只要更新单个文档即可。
  • 如果您有多个连接进入MongoDB,并且每个连接正在执行一系列写入,则锁存器将基于每个数据库保留,只要该写入完成所需的时间
  • 执行写入(更新/插入/删除)的多个连接都将被交错

虽然这听起来像是一个很大的性能问题,但在实践中它并没有减慢速度。通过适当设计的架构和典型的工作负载,MongoDB将使磁盘I / O容量饱和 - 即使对于SSD - 在任何数据库的锁定百分比超过50%之前也是如此。

我所知道的最高容量的MongoDB集群目前每秒执行200万次写入。

答案 1 :(得分:36)

不是每个连接,它是mongod。换句话说,锁将存在于该服务器上test数据库的所有连接上。

它也是一个读/写锁,所以如果发生写,那么读必须等待,否则MongoDB怎么知道它是一致的读?

但是我应该提到MongoDB锁与你得到的SQL /普通事务锁非常不同,通常锁定将在平均更新之间保持大约一微秒。

答案 2 :(得分:20)

Mongo 3.0现在支持集合级锁定。

除此之外,现在Mongo创建了一个允许创建存储引擎的API。 Mongo 3.0附带2个存储引擎:

  1. MMAPv1 :默认存储引擎和以前版本中使用的存储引擎。附带集合级锁定。
  2. WiredTiger :新的存储引擎,带有文档级锁定和压缩功能。 (仅适用于64位版本)
  3. MongoDB 3.0 release notes

    WiredTiger

答案 3 :(得分:9)

我知道这个问题已经很老了但仍有些人感到困惑....

  

从MongoDB 3.0开始,WiredTiger存储引擎(使用文档级并发性)在64位版本中可用。

     

WiredTiger使用文档级并发控制进行写操作。因此,多个客户端可以同时修改集合的不同文档。

     

对于大多数读写操作,WiredTiger使用乐观并发控制。 WiredTiger仅在全局,数据库和集合级别使用意图锁。当存储引擎检测到两个操作之间发生冲突时,会发生写入冲突,导致MongoDB透明地重试该操作。

     

某些全局操作(通常是涉及多个数据库的短期操作)仍然需要全局“实例范围”锁定。其他一些操作(例如删除集合)仍然需要独占数据库锁。

Document Level Concurrency