FAQ: Concurrency

在本页面

在版本 3.0 中更改。

MongoDB 允许多个 Client 端读取和写入相同的数据。为了确保一致性,它使用锁定和其他concurrency control措施来防止多个 Client 端同时修改同一数据。这些机制共同保证了对单个文档的所有写入全部发生或完全不发生,并且 Client 永远不会看到不一致的数据视图。

MongoDB 使用哪种类型的锁定?

MongoDB 使用多粒度锁定[1],它允许操作锁定在全局,数据库或集合级别,并允许各个存储引擎在集合级别以下(例如 WiredTiger 中的文档级别)实现自己的并发控制。

MongoDB 使用读取器-写入器锁,允许并发的读取器共享对资源(例如数据库或集合)的访问,但在 MMAPv1 中,它对单个写入操作具有独占访问权。

除了用于读取的共享(S)锁定模式和用于写操作的互斥(X)锁定模式之外,意图共享(IS)和意图互斥(IX)模式还表明使用更精细的粒度锁来读取或写入资源的意图。 。当以一定的粒度锁定时,所有较高级别都使用intent lock锁定。

例如,当锁定一个集合以进行写入时(使用模式 X),相应的数据库锁和全局锁都必须被锁定为意图排他(IX)模式。单个数据库可以同时以 IS 和 IX 模式锁定,但是独占(X)锁不能与任何其他模式共存,共享(S)锁只能与意图共享(IS)锁共存。

锁是公平的,读取和写入按 Sequences 排队。但是,为了优化吞吐量,当一个请求被授予时,所有其他兼容请求将同时被授予,有可能在冲突请求之前释放它们。例如,考虑一种情况,其中刚刚释放了 X 锁,并且冲突队列包含以下各项:

IS→IS→X→X→S→IS

在严格的先进先出(FIFO)Sequences 中,仅前两种 IS 模式将被授予。相反,MongoDB 实际上将授予所有 IS 和 S 模式,并且一旦它们全部耗尽,它将授予 X,即使与此同时新的 IS 或 S 请求也已排队。由于授予将始终将所有其他请求移到队列中,因此任何请求都不会饿死。

db.serverStatus()db.currentOp()输出中,锁定模式表示如下:

Lock ModeDescription
R表示共享(S)锁。
W表示排他(X)锁。
r表示共享意图(IS)锁。
w表示 Intent Exclusive(IX)锁。
[1]有关更多信息,请参见多重粒度锁定上的 Wikipedia 页面。

MongoDB 中的锁的粒度如何?

在版本 3.0 中更改。

For WiredTiger

从 3.0 版开始,MongoDB 附带了WiredTiger存储引擎。

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

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

For MMAPv1

MMAPv1 存储引擎从 3.0 版本开始使用集合级锁定,这是对早期版本的改进,在早期版本中,数据库锁定是最细粒度的锁定。第三方存储引擎可以使用集合级锁定,也可以实现自己的更细粒度的并发控制。

例如,如果使用 MMAPv1 存储引擎在数据库中有六个集合,并且某个操作采取了集合级别的写锁定,则其他五个集合仍可用于读取和写入操作。独占数据库锁使持有锁的操作期间所有六个集合都不可用。

如何查看 mongod 实例上的锁状态?

要报告有关锁的锁利用率信息,请使用以下任何一种方法:

具体而言,serverStatus 的输出中的locks文档或当前运营报告中的locks字段提供了有关mongod实例中的锁类型和锁争用量的信息。

db.serverStatus()db.currentOp()输出中,锁定模式表示如下:

Lock ModeDescription
R表示共享(S)锁。
W表示排他(X)锁。
r表示共享意图(IS)锁。
w表示 Intent Exclusive(IX)锁。

要终止操作,请使用db.killOp()

读或写操作是否会产生锁定?

在某些情况下,读和写操作可以产生其锁。

长时间运行的读写操作(例如查询,更新和删除)在许多情况下都会产生。在写操作中,MongoDB 操作还可以在单个文档修改之间产生锁定,这些操作会影响带有multi参数的多个文档,例如update()

对于支持文档级别concurrency control的存储引擎(例如WiredTiger),在以全局,数据库和集合级别保存的intent locks作为存储访问存储时,不必屈服,不会阻塞其他读取器和写入器。但是,操作将定期产生,例如:

  • 避免长期存储 Transaction,因为这些 Transaction 可能需要在内存中保存大量数据;

  • 充当中断点,以便您可以取消长时间运行的操作;

  • 允许需要排他访问集合的操作,例如索引/集合放置和创建。

MongoDB 的MMAPv1存储引擎基于其访问模式使用启发式算法来预测执行读取之前物理内存中是否可能存在数据。如果 MongoDB 预测数据不在物理内存中,则在 MongoDB 将数据加载到内存时,操作将产生其锁定。一旦内存中的数据可用,该操作将重新获取该锁以完成操作。

一些常见的 Client 端操作会采取什么锁?

下表列出了一些操作以及它们用于文档级锁定存储引擎的锁定类型:

OperationDatabaseCollection
发出查询r(共享意图)r(共享意图)
Insert dataw(意图专用)w(意图专用)
Remove dataw(意图专用)w(意图专用)
Update dataw(意图专用)w(意图专用)
Perform Aggregationr(共享意图)r(共享意图)
创建索引(前景)W(独家)
创建索引(背景)w(意图专用)w(意图专用)
List collectionsR(共享)
Map-reduceW(独家)和R(共享)w(意图专用)和r(意图共享)

哪些 Management 命令可以锁定数据库?

某些 Management 命令可以排他地锁定数据库较长时间。在某些部署中,对于大型数据库,您可以考虑使mongod实例脱机,以便不影响 Client 端。例如,如果mongodreplica set的一部分,则使mongod脱机,并在维护进行时让设置的服务的其他成员加载。

以下 Management 操作需要长时间在数据库级别上以独占方式锁定:

CommandsMethods
cloneCollectionAsCapped
compact
convertToCapped
copydb。此操作可能会锁定所有数据库。参见MongoDB 操作是否会锁定多个数据库?db.copyDatabase()。此操作可能会锁定所有数据库。参见MongoDB 操作是否会锁定多个数据库?
create创建上限(即数 GB)的上限集合时db.createCollection()创建上限(即数 GB)的上限集合时
createIndexes用于索引(无*)background设置为true发出db.collection.createIndex()db.collection.createIndexes(),而未将background设置为true
reIndexdb.collection.reIndex()
repairDatabasedb.repairDatabase()

以下 Management 操作将锁定数据库,但仅在很短的时间内保持锁定:

CommandsMethods
authenticatedb.auth()
createUserdb.createUser()
dropIndexesdb.collection.dropIndex()
getLastErrordb.getLastError()
isMasterdb.isMaster()
replSetGetStatusrs.status()
renameCollectiondb.collection.renameCollection()
serverStatusdb.serverStatus()

MongoDB 操作是否曾经锁定多个数据库?

以下 MongoDB 操作可锁定多个数据库:

  • db.copyDatabase()必须一次锁定整个mongod实例。

  • db.repairDatabase()获取全局写锁定,并将阻止其他操作,直到完成为止。

  • User authentication要求admin数据库具有读锁定,才能使用2 .6 用户凭据进行部署。对于使用 2.4 模式作为用户凭据的部署,身份验证会锁定admin数据库以及用户正在访问的数据库。

  • 所有对副本集primary的写操作都会锁定接收写操作的数据库,然后在短时间内锁定local数据库。 local数据库的锁允许mongod写入主数据库的oplog并占该操作总时间的一小部分。

  • 副本集成员state transitions取得全局排他锁。

分片如何影响并发性?

Sharding通过在多个mongod实例上分布集合来提高并发性,从而允许分片服务器(即mongos进程)同时对各种下游mongod实例执行任意数量的操作。

在分片群集中,锁适用于每个单独的分片,而不适用于整个群集。也就是说,每个mongod实例都独立于分片群集中的其他实例,并使用自己的locks。一个mongod实例上的操作不会阻止任何其他实例上的操作。

并发性如何影响主副本集?

对于副本集,当 MongoDB 写入primary上的集合时,MongoDB 也写入主数据库的oplog,这是local数据库中的特殊集合。因此,MongoDB 必须锁定集合的数据库和local数据库。 mongod必须同时锁定两个数据库,以保持数据库的一致性,并确保写操作(即使带有复制)也是“全有或全无”操作。

写入replica set时,锁的作用域适用于primary

并发性如何影响次级?

replication中,MongoDB 不会将写入 Sequences 应用于secondaries。二级服务器分批收集 oplog 条目,然后并行应用这些批次。辅助文件在应用写操作时不允许读取,并且按照它们出现在操作日志中的 Sequences 应用写操作。

MongoDB 是否支持事务?

因为单个文档可以包含相关数据,否则它们将在关系模式中的各个父子表之间建模,因此 MongoDB 的原子单文档操作已经提供了满足大多数应用程序数据完整性需求的事务语义。一个或多个字段可以在单个操作中编写,包括对多个子文档和数组元素的更新。 MongoDB 提供的保证可确保在文档更新时完全隔离。任何错误都会导致操作回滚,以便 Client 端获得文档的一致视图。

从版本 4.0 开始,对于需要原子性来更新多个文档或读取多个文档之间保持一致性的情况,MongoDB 为副本集提供multi-document transactions,而分片群集的事务则计划在 MongoDB 4.2 中进行。

Important

在大多数情况下,与单文档写入相比,多文档事务产生的性能成本更高,并且多文档事务的可用性不应替代有效的架构设计。在许多情况下,非规范化数据模型(嵌入式文档和数组)将 continue 是您的数据和用例的最佳选择。也就是说,在许多情况下,适当地对数据建模将最大程度地减少对多文档 Transaction 的需求。

Note

我们为产品描述的任何功能的开发,发布和时间安排均由我们自行决定。此信息仅用于概述我们的总体产品方向,在做出购买决策时不应以该信息为依据,也不是提供任何材料,代码或功能的承诺,承诺或法律义务。

MongoDB 提供什么隔离保证?

根据读取的关注点,Client 端可以在写入为durable之前查看写入的结果。要控制是否可以回滚读取的数据,Client 端可以使用readConcern选项。

有关信息,请参阅: