MongoDB版本更改: 4.2
针对已填充集合的MongoDB索引构建需要针对该集合的排他性读写锁定。需要对集合进行读取或写入锁定的操作必须等待,直到mongod
释放锁定为止
。MongoDB 4.2使用了优化的构建过程,该过程仅在索引构建的开始和结束时持有排他锁。其余的构建过程将产生交错的读写操作。
构建过程总结如下:
初始化
在mongod
需要对收集的排他锁被索引。这将阻止对集合的所有读取和写入操作,直到mongod
释放锁为止。在此期间,应用程序无法访问集合。
数据提取与处理
在mongod
对被索引的集合采取一系列意向锁之前,释放索引构建过程所采取的所有锁。在这段时间内,应用程序可以对集合进行读写操作。
清理
在mongod
对要建立索引的集合采取排他锁之前,释放由索引构建过程获取的所有锁。这将阻止对集合的所有读取和写入操作,直到mongod
释放锁为止。在此期间,应用程序无法访问集合。
完成时间
将mongod
索引标记为可以使用,并释放索引构建过程占用的所有锁。
有关索引构建锁定行为的详细说明,请参见 索引构建过程。有关MongoDB锁定行为的更多信息,请参阅FAQ:并发。
MongoDB 4.2索引构建完全替代了先前MongoDB版本中支持的索引构建过程。MongoDB将忽略
background
索引构建选项(如果指定给
createIndexes
或其外壳帮助程序
createIndex()
和)
createIndexes()
。
需要featureCompatibilityVersion 4.2
对于从4.0升级到4.2的MongoDB集群,必须将
功能兼容性版本(fcv)设置4.2
为启用优化的构建过程。有关设置fCV的更多信息,请参见setFeatureCompatibilityVersion
。
使用fCV运行的MongoDB 4.2集群4.0
仅支持4.0索引构建。
MongoDB的早期版本在前台或后台支持构建索引。前景索引构建速度很快,并且产生的索引数据结构更有效,但是需要在构建期间阻止对要建立索引的集合的父数据库的所有读写访问。后台索引构建速度较慢且结果效率较低,但是允许在构建过程中对数据库及其集合进行读写访问。
MongoDB版本更改: 4.2
MongoDB 4.2索引构建仅在构建过程的开始和结束期间对正在建立索引的集合获得排他锁,以保护元数据更改。其余的构建过程将使用后台索引构建的屈服行为来最大化构建期间对集合的读写访问。尽管具有更宽松的锁定行为,但4.2索引生成仍可产生有效的索引数据结构。
MongoDB 4.2索引构建性能至少与后台索引构建相当。对于在构建过程中几乎没有或没有接收到任何更新的工作负载,4.2索引构建的构建可以与在相同数据上构建的前台索引一样快。
使用db.currentOp()
监测的进展不断建立索引。
对于对集合施加约束的索引(例如
唯一索引),在索引构建完成后,mongod
检查所有先前存在的并发编写的文档是否违反了这些约束。违反索引约束的文档可以在索引构建期间存在。如果在构建结束时有任何文档违反了索引约束,则终止构建并引发错误。mongod
例如,考虑一个填充的collection inventory
。管理员希望在该product_sku
字段上创建唯一索引。如果集合中的任何文档具有的重复值
product_sku
,则索引构建仍可以成功启动。如果在构建结束时仍然存在任何冲突,则mongod
终止将终止构建并引发错误。
同样,在索引构建过程中,应用程序可以inventory
使用重复值成功将文档写入
集合product_sku
。如果在构建结束时仍然存在任何冲突,则mongod
终止将终止构建并引发错误。
为了减轻因违反约束而导致索引构建失败的风险:
对于分布在多个分片上的分片集合,一个或多个分片可能包含带有重复文档的块。这样,创建索引操作可能会在某些分片(即没有重复的分片)上成功,但在其他分片(即具有重复的分片)上不会成功。为了避免在分片上留下不一致的索引,可以发出
db.collection.dropIndex()
from mongos
来从集合中删除索引。
为了减轻发生这种情况的风险,在创建索引之前:
也可以看看
在目标集合承受较大写负载的时间段内构建索引可能会导致写性能下降和更长的索引构建。
考虑指定一个维护时段,在该时段内应用程序停止或减少对集合的写入操作。在此维护时段内启动索引构建,以减轻构建过程的潜在负面影响。
createIndexes
支持在集合上构建一个或多个索引。createIndexes
使用内存和磁盘上的临时文件的组合来完成索引构建。默认的内存使用限制createIndexes
为500 MB,由单个createIndexes
命令建立的所有索引之间共享。达到内存限制后,请createIndexes
在目录_tmp
内
名为的子目录中使用临时磁盘文件--dbpath
来完成构建。
您可以通过设置maxIndexBuildMemoryUsageMegabytes
服务器参数来覆盖内存限制
。设置更高的内存限制可能会导致更快完成大于500 MB的索引构建。但是,将此限制相对于系统上未使用的RAM设置得太高会导致内存错误。
如果主机的可用可用内存有限,则可能需要安排维护周期以增加系统总RAM,然后才能修改mongod
RAM使用率。
为了最大程度地减少建立索引对以下方面的影响:
您也可以在primary上启动索引构建。索引构建完成后,辅助副本将复制并开始索引构建。开始复制索引构建之前,请考虑以下风险:
如果二级索引构建阻止了复制事务在分片群集上的应用,则该事务包括对要建立索引的集合的写操作。同样,针对要建立索引的集合的复制元数据操作也滞后于索引构建。将mongod
不能申请任何进一步OPLOG的条目,直到索引构建完成。
如果索引构建在操作或命令时持有排他锁,则对要建立索引的集合的复制写操作也可能滞后于索引构建。该
mongod
直到索引构建释放独占锁不能申请任何进一步OPLOG条目。如果复制停顿的时间比该辅助节点上的oplog窗口更长,则该辅助节点将不同步,需要
重新同步才能恢复。
使用rs.printReplicationInfo()
每个副本集合构件上验证由配置该成员的OPLOG尺寸覆盖的时间之前到开始索引构建。您可以
增加操作日志的大小,
以减轻辅助节点不同步的可能性。例如,设置一个可以覆盖72个小时的操作的操作日志窗口大小可确保辅助副本至少可以忍受那么多的复制滞后。
或者,在维护窗口期间建立索引,在该窗口中,应用程序停止发出影响正在索引的集合的分布式事务,写操作或元数据命令。
mongod
¶如果mongod
在索引构建期间关闭,则索引构建作业和所有进度都将丢失。重新启动
mongod
不会重新启动索引构建。您必须重新发出createIndex()
操作以重新启动索引构建。
mongod
¶如果在索引构建期间主数据库关闭或退出,则索引构建作业和所有进度都将丢失。重新启动
mongod
不会重新启动索引构建。您必须重新发出createIndex()
操作以重新启动索引构建。
mongod
¶如果辅助服务器在索引构建期间关闭,则索引构建作业将保留。重新启动mongod
恢复将恢复索引构建,并从头开始重新启动它。
启动过程停滞在任何恢复的索引构建之后。所有其他操作(包括复制)都将等到索引构建完成。如果辅助节点的操作日志未涵盖完成索引构建所需的时间,则辅助节点可能与其余副本集不同步,并需要 重新同步。
如果您mongod
以独立方式重新启动索引(例如,删除或注释掉replication.replSetName
或省略--replSetName
),则
mongod
仍然会从头开始恢复索引构建。您可以使用storage.indexBuildRetry
配置文件设置或
--noIndexBuildRetry
命令行选项在启动时跳过索引构建。
MongoDB 4.0以上
不能指定storage.indexBuildRetry
或
--noIndexBuildRetry
为
mongod
这是一个副本集的一部分。
如果分片集合在每个包含该分片块的分片上没有完全相同的索引(包括索引选项),则该索引的索引不一致。尽管在正常操作期间不应出现不一致的索引,但是可能会出现不一致的索引,例如:
unique
键约束的索引且一个分片包含具有重复文档的块时。在这种情况下,创建索引操作可能会在没有重复的分片上成功,但在没有重复的分片上不会成功。从MongoDB 4.2.6开始,配置服务器主服务器会定期检查分片集合中各分片之间的索引不一致。要配置这些定期检查,请参阅
enableShardedIndexConsistencyCheck
和
shardedIndexConsistencyCheckIntervalMS
。
当在配置服务器主服务器上运行时,该命令serverStatus
返回该字段
shardedIndexConsistency
以报告索引不一致情况。
要检查分片集合是否具有不一致的索引,请参阅 查找分片中的不一致索引。
要查看索引构建操作的状态,可以使用外壳程序中的
db.currentOp()
方法mongo
。要过滤索引创建操作的当前操作,请参阅
Active Indexing Operations作为示例。
该msg
字段包括索引构建过程中当前阶段的百分比完成度量。
要终止在主数据库或独立数据库上进行中的索引构建
mongod
,请使用外壳程序中的db.killOp()
方法
mongo
。终止索引构建时,的影响db.killOp()
可能不会立即产生,并且可能会在许多索引构建操作完成后立即发生。
您不能在副本集的辅助成员上终止复制索引构建。您必须首先drop
在主数据库上建立索引。二级服务器将复制删除操作,并在索引构建完成后删除索引。索引建立和删除之后的所有其他复制块。
为了最大程度地减少在具有副本集分片的副本集和分片群集上建立索引的影响,请参阅:
下表描述了索引构建过程的每个阶段:
阶段 | 描述 |
---|---|
锁 | 在mongod 获得独占X 被索引的集合锁。这将阻止对集合的所有读取和写入操作,包括应用任何针对该集合的复制的写入操作或元数据命令。在mongod 不产生这种锁。 |
初始化 |
|
锁 | 该mongod 降级的独家X
收集锁意图独占
IX 锁。将mongod 定期得到这个锁交错读取和写入操作。 |
扫描收集 | 对于集合中的每个文档,都会为该文档 如果 如果 一旦 |
流程端写入表 | 该 如果 如果 对于在构建过程中写入集合的每个文档 |
锁 | 将
集合上mongod 的意图互斥IX 锁升级为共享S 锁。这将阻止对集合的所有写操作,包括应用任何针对该集合的复制写操作或元数据命令。 |
完成处理临时面写入表 | 将 如果 如果 |
锁 | 将集合上mongod 的共享S 锁升级为集合上的独占X 锁。这将阻止对集合的所有读取和写入操作,包括应用任何针对该集合的复制的写入操作或元数据命令。在mongod
不产生这种锁。 |
下侧写表 | 在 如果 如果 此时,索引包括写入集合的所有数据。 |
流程约束违规表 | 该 如果约束违例表中的任何键仍然产生重复的键错误,则 该 |
将索引标记为就绪 | 该mongod 更新索引元数据标记索引为准备使用。 |
锁 | 该mongod 释放X 的集合锁。 |