在mongodb文档中,它说:
从版本2.2开始,MongoDB在每个数据库的基础上实现了大多数读写操作的锁。一些全局操作(通常是涉及多个数据库的短期操作)仍然需要全局“实例”广泛锁定。在2.2之前,每个mongod实例只有一个“全局”锁。
这是否意味着在我拥有3个与mongodb:// localhost / test的连接的情况下,来自网络上运行的不同应用程序 - 一次只能写一个?或者只是每个连接?
IOW:它是每个连接,还是整个/测试数据库在写入时被锁定?
答案 0 :(得分:237)
在MongoDB中锁定不像锁定RDBMS那样工作,因此需要进行一些解释。在早期版本的MongoDB中,只有一个全局读/写锁存器。从MongoDB 2.2开始,每个数据库都有一个读/写锁存器。
闩锁是多读者,单一作家,并且是作家贪婪的。这意味着:
请注意,我将其称为“闩锁”而不是“锁定”。这是因为它是轻量级的,并且在正确设计的模式中,写锁定保持在十几个微秒的量级。有关读者 - 作者锁定的更多信息,请参阅here。
在MongoDB中,您可以根据需要运行任意数量的同步查询:只要相关数据在RAM中,它们都将得到满足而不会发生锁定冲突。
回想一下,在MongoDB中,事务级别是单个文档。对单个文档的所有更新都是Atomic。 MongoDB通过只保留更新RAM中的单个文档所需的写锁存器来实现这一点。如果存在任何缓慢运行的操作(特别是,如果需要从磁盘中分页文档或索引条目),则该操作将产生写锁存器。当操作产生锁存器时,则可以继续下一个排队操作。
这意味着对单个数据库中所有文档的写入进行序列化。如果您的架构设计很差,并且您的写入需要很长时间,那么这可能是一个问题,但在正确设计的架构中,锁定不是问题。
还有一些关于作家贪婪的话:
只有一位作家可以同时握住闩锁;多个读卡器可以一次握住闩锁。在一个天真的实现中,如果有一个读者在运行,作者可能会无限期地饿死。为了避免这种情况,在MongoDB实现中,一旦任何单个线程对特定锁存器发出写请求
实际的行为是复杂的,因为这种作家贪婪的行为以不明显的方式与屈服相互作用。回想一下,从2.2版开始,每个数据库都有一个单独的锁存器,因此写入数据库'A'中的任何集合将获得一个单独的锁存器,而不是写入数据库'B'中的任何集合。
关于具体问题:
虽然这听起来像是一个很大的性能问题,但在实践中它并没有减慢速度。通过适当设计的架构和典型的工作负载,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个存储引擎:
答案 3 :(得分:9)
我知道这个问题已经很老了但仍有些人感到困惑....
从MongoDB 3.0开始,WiredTiger存储引擎(使用文档级并发性)在64位版本中可用。
WiredTiger使用文档级并发控制进行写操作。因此,多个客户端可以同时修改集合的不同文档。
对于大多数读写操作,WiredTiger使用乐观并发控制。 WiredTiger仅在全局,数据库和集合级别使用意图锁。当存储引擎检测到两个操作之间发生冲突时,会发生写入冲突,导致MongoDB透明地重试该操作。
某些全局操作(通常是涉及多个数据库的短期操作)仍然需要全局“实例范围”锁定。其他一些操作(例如删除集合)仍然需要独占数据库锁。