[翻译]常见问题-并发

数据库 Quarterback 44℃ 0评论

常见问题:并发

  • MongoDB使用何种类型的锁?
  • MongoDB中锁的粒度有多细?
  • 如何在我的mongod实例上看到锁的状态?
  • 读取或写入操作是否会让渡(yield)锁?
  • 一些常见的客户端操作会采取什么样的锁定?
  • 哪些管理命令锁定数据库?
  • MongoDB操作是否锁定多个数据库?
  • 分片如何影响并发?
  • 并发性如何影响副本集的primay节点?
  • 并发性如何影响副本集的secondary节点?
  • MongoDB是否支持事务?
  • MongoDB提供了什么样的隔离保证?

在3.0版本中更改。

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

MongoDB使用何种类型的锁?

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

MongoDB使用读-写锁,允许并发读操作以共享的方式访问资源(如一个数据库或一个集合),但在MMAPv1中,对单个写入操作采取独占(排它)的访问方式。

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

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

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

IS→IS→X→X→S→IS

在严格的先进先出(FIFO)排序中,只授予前两种IS模式。然而,MongoDB实际上将授予所有IS和S模式,一旦它们全部完成,它将授予X,即使新的IS或S请求在此期间已进入排队。由于授权将始终在队列中提前移动所有其他请求,因此任何请求都不可能存在饥饿等待问题。

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

 

锁模式 描述
R 代表共享锁(S)
W 代表排它锁(X)
r 代表意向共享锁(IS)
w 代表意向排它锁(IX)

 

[1] 在wiki上查看 多粒度锁 相关的更多信息.

MongoDB中锁的粒度有多细?

在版本3.0中更改。

对于WiredTiger

从版本3.0开始,MongoDB可以使用WiredTiger存储引擎。

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

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

对于MMAPv1

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

举个例子,如果一个使用MMAPv1存储引擎的数据库中有六个集合,有一个采用集合级写锁的操作,则其他五个集合仍可用于读取和写入操作。一个排它数据库级别锁使得所有六个集合在持有锁的操作期间不可用。

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

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

具体来说,serverStatus输出中locks子文档或当前操作报告中current operation reporting)的locks字段 ,提供了可以深入了解实例中锁的类型和锁争用的数量。

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

 

 

锁模式 描述
R 代表共享锁(S)
W 代表排它锁(X)
r 代表意向共享锁(IS)
w 代表意向排它锁(IX)

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

读取或写入操作是否会让渡(yield)锁?

在某些情况下,读写操作可以让渡(yield)它们持有的锁。

长时间运行的读写操作(例如查询,更新和删除)在许多条件下都会进行让渡(yield)。MongoDB如果单个修改文档的操作,影响带有multi参数修改多个文档update()操作,MongoDB也会让渡锁。

对于支持文档级并发控制的存储引擎,例如WiredTiger,当使用意向锁访问存储时不需要让渡(yield),因为该锁是全局,数据库和集合级别,不会阻止其他读写操作。但是,操作会定期产生让渡(yield),例如:

  • 避免长时间执行的存储性事务,因为这些可能需要在内存中保存大量数据;
  • 作为中断响应点(interruption points),以便你可以杀死长时间运行的操作;
  • 允许需要对集合进行排它访问的操作得到执行,例如索引/集合的删除和创建。

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

一些常见的客户端操作会采取什么样的锁定?

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

操作 数据库级别锁 集合级别锁
查询(query) r (意向共享锁(IS)) r (意向共享锁(IS))
插入数据(insert) w (意向排它锁(IX)) w (意向排它锁(IX))
删除数据(remove) w (意向排它锁(IX)) w (意向排它锁(IX))
更新数据(update) w (意向排它锁(IX)) w (意向排它锁(IX))
执行聚合操作(aggregation) r (意向共享锁(IS)) r (意向共享锁(IS))
创建索引(前台创建Foreground) W (排它锁(X))  
创建索引(后台创建Background) w (意向排它锁(IX)) w (意向排它锁(IX))
列出集合列表(List collections) r (意向共享锁(IS))

版本4.0中修改.

 
Map-reduce操作 W (排它锁(X) 和R 共享锁(IS) w (意向排它锁(IX)) and r (意向共享锁(IS))

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

某些管理命令可以在很长一段时间内排它锁定数据库。在某些部署中,对于大型数据库,您可以考虑使mongod实例脱机,以便客户端不受影响。例如,如果 mongod副本集的一部分,请执行mongod脱机操作,并在维护过程中,让副本集的其他成员服务请求负载。

以下管理操作需要在数据库级别进行长时间的排它锁定:

命令 方法
cloneCollectionAsCapped  
compact  
convertToCapped  
copydb. 该操作可能锁定所有的数据库. 查看 MongoDB会锁定多个数据库吗? db.copyDatabase(). 该操作可能锁定所有的数据库. 查看 MongoDB会锁定多个数据库吗?
create 当创建一个特别大的定容集合(capped collection,例如数GB级别) db.createCollection() 当创建一个特别大的定容集合(capped collection,例如数GB级别)
createIndexes (没有设置background参数时) db.collection.createIndex() anddb.collection.createIndexes() (没有设置background参数时)
repairDatabase db.repairDatabase()

以下管理操作会锁定数据库,但是只会锁定很短的时间:

命令 方法
authenticate db.auth()
createUser db.createUser()
dropIndexes db.collection.dropIndex()
getLastError db.getLastError()
isMaster db.isMaster()
replSetGetStatus rs.status()
renameCollection db.collection.renameCollection()
serverStatus db.serverStatus()

参考:

MongoDB会锁定多个数据库吗?

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

以下MongoDB操作采用全局排它锁(译者注:即会锁定所有的数据库):

分片如何影响并发?

分片通过将集合分布在多个mongod实例,提高并发的能力,允许分片服务器(即mongos进程)来并发的执行针对下游mongod 实例的任意数量的操作。

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

并发性如何影响副本集的primay节点

对于副本集,当MongoDB写入节点上的集合时 ,MongoDB还会写入主节点oplog—local数据库中的特殊集合。因此,MongoDB必须锁定集合所在的数据库和local 数据库。mongod必须同时锁定这两个库来保持数据库一致性,并确保写入操作,甚至包括复制,是“all-or-nothing”的操作。

写入副本集时,锁的范围适用于节点(primary)。

并发性如何影响副本集的secondary节点

在进行副本复制同步时,MongoDB不会将写入连续的应用到从节点(secondaries)。从节点批量收集oplog记录,然后并行应用这些批处理。从节点在应用写入操作时不允许读取,并按照它们在oplog中出现的顺序应用这些写入操作。

MongoDB是否支持事务

因为单个文档可以包含关联数据(译者注:通过内嵌文档或数组的方式),而这些关联数据在关系模型中是使用单独父子表进行建模的,MongoDB的单文档原子操作已经提供了满足大多数应用程序的数据完整性需求的事务语义。可以在单个操作中写入一个或多个字段,包括对多个子文档和数组元素的更新。MongoDB提供的单文档操作原子性保证确保在文档更新时完全隔离; 任何错误都会导致操作回滚,以便客户端收到文档的一致视图。

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

重要

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

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

MongoDB提供了什么样的隔离保证?

根据ReadConcern参数设置,客户端可以在写入持久化之前查看写入结果。要控制是否可以回滚读取的数据,客户端可以使用readConcern选项。

有关信息,请参阅:

 

原文:https://docs.mongodb.com/manual/faq/concurrency/

 

/* 本文属于原创文章,转载请注明作者和出处 quarterback.cn,请勿用于任何商业用途 */




喜欢 (0)or分享 (0)
Quarterback.cn 打赏作者
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址