MongoDB:4.2+
在以前的版本中,MongoDB的索引,类似下面这样的写法:
db.people.ensureIndex({x:1,y:1},{background:1})
索引的创建,分为,前台创建和后台创建。
前台创建索引:构建速度快并且产生了更有效的索引数据结构,但是需要在构建期间阻止对要建立索引的集合所在的数据库的所有读写访问。
后台创建索引:构建速度较慢且构建的索引数据结构不理想,但允许在构建过程中对数据库及其集合进行读写访问。
根据前台创建索引的特点:经常容易出现线上的安全事故;
所以在4.2版本以后,MongoDB这里统一做了优化:
取消了前台创建索引,后台创建保留,但不在是通过background保留,而是MongoDB自己做了内部优化:
从MongoDB 4.2开始,索引构建仅在构建过程的开始和结束期间对正在建立索引的集合获得排他锁,以保护元数据更改。 其余的构建过程将使用后台索引构建的交替行为来最大化构建期间对集合的读写访问。 尽管具有更宽容的锁定行为,但4.2索引生成仍可产生有效的索引数据结构。
交替行为:就是 读写 操作交替,而不是像前台创建索引那样阻止对要建立索引的集合所在的数据库的所有读写访问。
4.2一个重点的强调点就是索引构建仅在构建过程的开始和结束期间对正在建立索引的集合获得排他锁,以保护元数据更改。
那么这个构建过程,到底有哪些呢?
mongod在要建立索引的集合上获得独占X锁。这将阻止对集合的所有读取和写入操作,包括应用任何针对该集合的复制的写入操作或元数据命令。 mongod
独占此锁,不会退让。
mongod
在此初始状态下创建三个数据结构:
side writes table
),用于存储在构建过程中对索引的集合进行写操作时生成的key
。constraint violation table
约束违反表”),当生成key时,如果出现错误,就把该key记录到这张表里。错误的产生:当文档的索引字段无效时,会发生key
生成错误。例如,①当构建唯一索引时,文档具有重复的字段值;或者,② 在构建2dsphere
索引时,GeoJSON
对象的文档格式不正确。2dsphere Indexes是地理位置索引。
mongod
将排它X集合锁降级为意向排他IX锁
。 mongod
定期将此锁交替的读写操作。
对于集合中的每个文档,mongod
都会为该文档生成一个key
,并将该key
转储到外部分类器中。
如果mongod在集合扫描期间生成key时,遇到key生成错误,则它将该key存储在约束违例表
(constraint violation table
)中以供以后处理。
如果mongod在生成key时遇到任何其他错误,则构建会失败并显示错误。
mongod完成集合扫描后,会将已排序的键转储到索引中。
Side Writes Table 这张表,存储的都是每个文档生成的key。
mongod
使用先进先出优先级消耗side write table
。
如果mongod
在side write table
中处理key时,遇到key生成错误,它将该key存储在约束违例表中以供以后处理。
如果mongod
在处理key
时遇到任何其他错误,则构建将失败并显示错误。
对于在构建过程中写入集合的每个文档,mongod
都会为该文档生成一个key,并将其存储在side write table
中以供以后处理。 mongod
使用快照系统为要处理的key
数设置限制。
投票并等待提交法定人数
不属于副本集的mongod会跳过此阶段。
从MongoDB 4.4开始,mongod向主数据库提交“投票”以提交索引。 具体来说,它将“投票”写入主数据库上的内部复制集合。
如果mongod是primary,它会一直等到拥有一定的投票定额(默认情况下,所有具有投票数据的成员)才继续进行索引构建过程。
如果mongod是从数据库的,它将等到复制“ commitIndexBuild”或“ abortIndexBuild”操作日志条目:
4.1. 如果mongod复制“ commitIndexBuild”操作日志条目,则它完成了耗尽side writes 表并进入索引构建过程的下一个阶段。
4.2. 如果mongod复制“ abortIndexBuild”操作日志条目,它将中止索引构建并放弃构建作业。
在等待提交仲裁时,mongod将由写操作生成的所有其他键添加到要索引的side writes 表的集合中,并定期清空该表。
Mongod将集合上的独占意向IX锁
升级到共享的S锁。这会阻止到集合的所有写入操作,包括应用于目标集合的任何复制的写操作或元数据命令。
mongod继续清空side writes表中的剩余记录。 在此阶段,mongod可能会暂停复制。
如果mongod在side writes表中处理key时遇到key生成错误,它将该key存储在约束违例表中以供以后处理。
如果mongod在处理key时遇到任何其他错误,则构建将失败并显示错误。
mongod将集合上的共享S锁
升级为集合上的独占X锁
。 这将阻止对集合的所有读取和写入操作,包括应用任何针对该集合的复制的写入操作或元数据命令。 mongod不会交出此锁。
mongod在删除它之前,会在side writes表中应用所有剩余的操作。
如果mongod在side writes表中处理key时遇到key生成错误,它将该key存储在约束违例表中以供以后处理。
如果mongod在处理key时遇到任何其他错误,则构建将失败并显示错误。
此时,索引包括写入集合的所有数据。
处理约束违规表。
如果mongod是primary,它将使用先进先出优先级清空约束违规表。
如果约束违规表中没有key产生key生成错误,或者如果该表为空,则mongod会删除该表并创建一个“ commitIndexBuild”操作日志条目。 在复制oplog条目后,从数据库可以完成关联的索引构建。
如果约束违规表中的任何key仍然产生key生成错误,则mongod会中止构建并引发错误。 mongod创建一个关联的“ abortIndexBuild”操作日志条目,以指示从数据库应中止并放弃索引构建作业。
如果mongod是从数据的,它将删除约束违规表。 由于主数据库必须在创建“ commitOplogEntry”操作日志条目之前成功清除约束违规表,因此从数据库可以安全地假定不存在任何违例。
Mongod更新索引元数据以将索引标记为准备使用。
Mongod在集合上释放X锁。
排他X锁,存在的情况:
所以将Side Write table
,翻译成边写表
,感觉没问题:允许一边创建索引,一遍写入数据。
参考地址:
https://docs.mongodb.com/manual/core/index-creation/#std-label-index-operations