常见问题:并发

guwj
发布于 2022-11-23 11:49
浏览
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()输出中,锁定模式被表示如下:


常见问题:并发-鸿蒙开发者社区


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


MongoDB中锁的粒度有多细?

在版本3.0中更改。

对于WiredTiger

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

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

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

对于MMAPv1

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

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


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

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

·   db.serverStatus(),

·   db.currentOp(),

·   mongotop,

·   mongostat,和/或

·  ​​MongoDB Cloud Manager​​​或 ​​Ops Manager,MongoDB企业版提供的先进的解决方案​

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

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


常见问题:并发-鸿蒙开发者社区


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


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

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

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

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

l  避免长时间执行的存储性事务,因为这些可能需要在内存中保存大量数据;

l  作为中断响应点(interruption points),以便你可以杀死长时间运行的操作;

l  允许需要对集合进行排它访问的操作得到执行,例如索引/集合的删除和创建。

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


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

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


常见问题:并发-鸿蒙开发者社区


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

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

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


常见问题:并发-鸿蒙开发者社区


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


常见问题:并发-鸿蒙开发者社区


参考:

​ MongoDB会锁定多个数据库吗?​


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

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

l  db.copyDatabase()获取全局排它锁(global exclusive (W) lock),将阻塞其他操作直到该操作完成。

l  db.repairDatabase()获取全局排它锁(global exclusive (W) lock),将阻塞其他操作直到该操作完成。

l  从MongoDB 4.0开始,db.collection.reIndex()获取 获取全局排它锁(globalexclusive (W) lock),将阻塞其他操作直到该操作完成。

l  用户身份验证对于使用 2.6用户凭据的部署,需要在admin库上获取一个读锁。对于使用2.4模式进行用户凭据的部署,身份验证会锁定 admin数据库同时也会锁定用户正在访问的数据库。

l  对副本集primary节点的所有写入操作,会短时间锁住写入的目标数据库以及local数据库。锁定local数据库,允许 mongod占用操作总时间的一小部分来写入primary节点的oplog。

l  副本集成员状态转换采用全局排它锁。


分片如何影响并发?

分片通过将集合分布在多个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选项。

有关信息,请参阅:

·  读取隔离,一致性和因近原则

·  原子性和事务

·  Read Concern




文章转载自公众号: Mongoing中文社区

分类
标签
已于2022-11-23 11:49:33修改
收藏
回复
举报
回复
    相关推荐