常见问题:并发

在本页面

更改了 version 3.0.

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

MongoDB 使用什么类型的锁定?

MongoDB 使用 multi-granularity 锁定[1],允许操作锁定 global,数据库或集合 level,并允许各个存储引擎在集合 level(e.g. ,WiredTiger 中的 document-level)下实现自己的并发控制。

MongoDB 使用 reader-writer 锁,允许并发 readers 共享访问资源(如数据库或集合),但在 MMAPv1 中,允许对单个写操作进行独占访问。

除了用于读取的共享(S)锁定模式和用于写入操作的独占(X)锁定模式之外,意图共享(IS)和意图独占(IX)模式指示使用更精细的粒度锁定来读取或写入资源的意图。 。以某个粒度锁定时,使用意图锁定锁定所有更高级别。

例如,在锁定集合以进行写入时(使用模式 X),必须在 intent exclusive(IX)模式下锁定相应的数据库锁和 global 锁。单个数据库可以同时锁定在 IS 和 IX 模式,但是独占(X)锁不能与任何其他模式共存,并且共享(S)锁只能与意图共享(IS)锁共存。

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

IS→IS→X→X→S→IS

在严格的 first-in,first-out(FIFO)ordering 中,只授予前两个 IS 模式。相反,MongoDB 实际上将授予所有 IS 和 S 模式,一旦它们全部耗尽,它将授予 X,即使新的 IS 或 S 请求在此期间已排队。由于授权将始终在队列中提前移动所有其他请求,因此任何请求都不可能存在饥饿。

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

锁定模式描述
R表示共享(S)锁。
W表示独占(X)锁定。
r表示意图共享(IS)锁。
w表示 Intent Exclusive(IX)锁。
[1]有关详细信息,请参阅多粒度锁定上的 Wikipedia 页面。

MongoDB 中锁的粒度有多精细?

更改了 version 3.0.

对于 WiredTiger

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

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

一些 global 操作,通常是涉及多个数据库的短期操作,仍然需要 global“instance-wide”锁定。其他一些操作(例如删除集合)仍需要独占数据库锁。

对于 MMAPv1

MMAPv1 存储引擎在 3.0 版本系列中使用 collection-level 锁定,这是对数据库锁定为 finest-grain 锁定的早期版本的改进。 Third-party 存储引擎可以使用 collection-level 锁定或实现自己的 finer-grained 并发控制。

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

如何在我的 mongod 实例上看到锁的状态?

要报告锁上的锁定利用率信息,请使用以下任一方法:

具体来说,serverStatus 的输出中的文档或当前的运营报告中的字段可以深入了解mongod实例中锁的类型和锁争用的数量。

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

锁定模式描述
R表示共享(S)锁。
W表示独占(X)锁定。
r表示意图共享(IS)锁。
w表示 Intent Exclusive(IX)锁。

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

读取或写入操作是否会锁定锁定?

在某些情况下,读写操作可以锁定它们的锁。

Long 在许多条件下运行读取和写入操作,例如查询,更新和删除,yield。 MongoDB 操作还可以在写入操作中的单个文档修改之间进行锁定,这些修改会影响多个文档,如update()multi参数。

对于支持文档 level 并发控制的存储引擎,例如WiredTiger,在访问存储时不需要屈服,因为意图锁,global,数据库和集合 level,不要阻止其他 readers 和 writers。但是,操作将定期 yield,例如:

  • 避免 long-lived storage transactions,因为这些可能需要在 memory 中保存大量数据;

  • 作为中断点,以便你可以杀死 long running 操作;

  • 允许需要独占访问集合的操作,例如 index/collection drop 和 creations。

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

一些 common client 操作会占用什么锁?

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

手术数据库采集
发出查询r(意图共享)r(意图共享)
Insert 数据w(意图独家)w(意图独家)
删除数据w(意图独家)w(意图独家)
更新数据w(意图独家)w(意图独家)
执行聚合r(意图共享)r(意图共享)
创建索引(前景)W(独家)
创建索引(背景)w(意图独家)w(意图独家)
列表集合R(共享)
Map-reduceW(独家)和R(共享)w(意图独占)和r(意图共享)

哪些管理命令锁定数据库?

某些管理命令可以在 time 的长时间内独占锁定数据库。在某些部署中,对于大型数据库,您可以考虑使mongod实例脱机,以便 clients 不受影响。例如,如果mongod副本集的一部分,则取消mongod离线,并在维护过程中加载设置服务的其他成员。

以下管理操作需要在数据库 level 上进行长时间的独占锁定:

命令方法
cloneCollectionAsCapped
紧凑
convertToCapped
COPYDB。此操作可能会锁定所有数据库。见MongoDB 操作是否锁定了多个数据库?db.copyDatabase()。此操作可能会锁定所有数据库。见MongoDB 操作是否锁定了多个数据库?
当_创建一个非常大(i.e.千兆字节)的上限集合时创建当_创建一个非常大(i.e.千兆字节)的上限集合时db.createCollection()
没有background的索引的createIndexes设置为true没有backgrounddb.collection.createIndex()db.collection.createIndexes()设置为true
REINDEXdb.collection.reIndex()
repairDatabasedb.repairDatabase()

以下管理操作会锁定数据库,但只能在非常短的时间内保持锁定:

命令方法
认证db.auth()
创建用户db.createUser()
dropIndexesdb.collection.dropIndex()
GetLastError 函数db.getLastError()
isMasterdb.isMaster()
replSetGetStatusrs.status()
renameCollectiondb.collection.renameCollection()
serverStatusdb.serverStatus()

也可以看看 MongoDB 操作是否锁定了多个数据库?

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

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

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

  • db.repairDatabase()获得 global 写锁定,并将阻止其他操作,直到它完成。

  • 用户认证需要admin数据库上的读锁定,以便使用2.6 用户凭据进行部署。对于使用 2.4 schema 进行用户凭据的部署,身份验证会锁定admin数据库以及用户正在访问的数据库。

  • 对副本集的的所有写入都会锁定接收写入的数据库,然后锁定local数据库一小段时间。 local数据库的锁允许mongod写入主要的OPLOG并占操作总 time 的一小部分。

  • 副本集成员state 过渡采取 global exlusive 锁。

分片如何影响并发?

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

在分片 cluster 中,锁定适用于每个单独的分片,而不是整个 cluster; i.e。每个mongod实例独立于分片 cluster 中的其他实例,并使用自己的。一个mongod实例上的操作不会阻止任何其他实例上的操作。

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

对于副本 sets,当 MongoDB 写入上的集合时,MongoDB 也会写入主要的OPLOG,这是local数据库中的特殊集合。因此,MongoDB 必须锁定集合的数据库和local数据库。 mongod必须在同一 time 锁定两个数据库以保持数据库一致,并确保即使使用复制,写操作也是“all-or-nothing”操作。

写入副本集时,锁的范围适用于

并发性如何影响次要?

复制中,MongoDB 不会将串行写入次级。辅助节点批量收集 oplog 条目,然后在 parallel 中应用这些批处理。辅助节点在应用写入操作时不允许读取,并且在它们出现在 oplog 中的 order 中应用写入操作。

MongoDB 是否支持 transactions?

因为单个文档可以包含相关数据,否则这些相关数据将在关系 schema 中的单独 parent-child 表中建模,MongoDB 的 atomic single-document 操作已经提供了 transaction 语义,以满足大多数 applications 的数据完整性需求。可以在单个操作中写入一个或多个字段,包括对多个 sub-documents 的更新和 array 的元素。 MongoDB 提供的保证确保在文档更新时完全隔离;任何错误都会导致操作回滚,以便 clients 获得文档的一致视图。

从 version 4.0 开始,对于需要原子性来更新多个文档或读取多个文档之间的一致性的情况,MongoDB 为复制_set 提供multi-document transactions,为 MongoDB 4.2 安排分片簇的 transactions。

重要 在大多数情况下,multi-document transaction 比单个文档写入产生更高的性能成本,multi-document transaction 的可用性不应该取代有效的 schema 设计。对于许多场景,非规范化数据 model(嵌入式文档和数组)将继续为您的数据和用例提供最佳选择。也就是说,对于许多场景,适当地建模数据将最大限度地减少对 multi-document transactions 的需求。

注意 我们产品描述的任何功能或功能的开发,发布和时间由我们自行决定。此信息仅用于概述我们的一般产品方向,不应依赖于做出购买决定,也不是承诺,承诺或法律义务来提供任何材料,编码或功能。

MongoDB 提供了哪些隔离保证?

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

有关信息,请参阅: