65

在 mongodb 文档中,它说:

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

这是否意味着在我有 3 个从网络上运行的不同应用程序到 mongodb://localhost/test 的连接的情况下 - 一次只能写入一个?还是只是每个连接?

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

4

4 回答 4

263

MongoDB 锁定是不同的

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

读写器锁存器

锁存器是多读、单写的,并且是写贪心的。这意味着:

  • 数据库上可以有无限数量的同时阅读器
  • 任何一个数据库中的任何集合一次只能有一个作家(稍后会详细介绍)
  • 作家挡住了读者
  • “writer-greedy”,我的意思是一旦写入请求进来,所有的读者都会被阻塞,直到写入完成(稍后会详细介绍)

请注意,我将其称为“闩锁”而不是“锁”。这是因为它是轻量级的,并且在适当设计的模式中,写锁定保持在十几微秒左右。有关读写器锁定的更多信息,请参见此处。

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

原子文档更新

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

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

作家-贪婪

关于作家贪婪还有几句话:

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

  • 所有后续需要该锁存器的读取器都将阻塞
  • 该作家将等到所有当前读者完成
  • 写入器将获取写锁存器,完成它的工作,然后释放写锁存器
  • 所有排队的读者现在将继续

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

具体问题

关于具体问题:

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

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

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

于 2013-07-03T23:04:42.290 回答
40

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

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

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

于 2013-07-03T19:51:00.673 回答
22

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

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

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

MongoDB 3.0 发行说明

连线老虎

于 2015-03-04T18:07:36.637 回答
10

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

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

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

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

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

文档级并发

于 2017-03-27T08:32:17.413 回答