MongoDB 存储和优化系列一
因工作的需要开始接触mongodb这个非关系型数据库,下面就将从mongoDb的存储机制和索引的使用俩方面来探究一下mongoDb的内部原理。
mongoDb在早期采用了MMAP存储引擎机制来实现数据的存储,直到mongoDb3.0 之后才引入了插件式的存储机制来支持更多的存储引擎,同时也升级MMAP到MMAP V1 ,并且MMAPV1作为默认的存储引擎 ,但是用户可以选择其它的存储引擎,例如 WiredTiger,InMemory 这些知名的插件存储引擎,到MongoDb 3.2的时候默认的存储引擎已经变更为Wired Tiger ,具体的架构如下图:
- MMAPV1 存储引擎是一种原始的存储引擎,它是基于内存映射文件来实现的,它擅长使用大容量插入,读取,更新工作负载,是出了名的耗内存,占资源,它会自动占有机器的全部可用内存来缓存数据,但是这个过程是动态的,当其它的进程要使用内存的时候,MMAPV1也会把Cache的内存分配给其它的进程 ,它采用的是操作系统的虚拟内存系统来管理自己的内存的
- 内部原理如图:
WT 存储引擎 我们将从如下的7方面就行介绍
- 文档级别的并发控制-乐观锁机制
- 检查点(Checkpoint)
- 预先记录日志
- WiredTiger 利用系统内存资源缓存两部分数据
- 调整WiredTiger内部缓存的大小
- 数据压缩
- Disk空间回收
- 上面我们介绍的MMAP存储引擎中所有的操作都是基于Collection级以上的互斥锁机制,这样的机制会使得整个数据库的并发的性能下降,然而WT存储引擎截然不同,在日常的使用中大多数对数据库的更新操作都只会对集合中少量的Document进行更新,同时对多个Collection进行更新情况特别的少,对多个DataBase对更新则是更为罕见了,由此可见仅支持Collection级别是远远不够的 ,相对于MMAPV1 ,WT采用了Document乐观锁机制。WT乐观锁机制与其它乐观锁实现机制大同小异,WT会在更新Document前记住即将被更新的所有Document当前版本号,并在更新前再次验证当前的版本号,若当前版本号没有发生改变,则说明该document在该原子事件中没有被其它请求更新,可以顺利写入,并且修改版本号;如果版本号发生改变,则说明该document在更新发生之前已经被其它的请求更新,由此触发一次写冲突,不过在遇到写冲突之后,WT会重试自动更新,但是这不代表WT对所有操作都采用如此宽松的的乐观锁机制,对于某些全局的操作,WT依然会在Collection级,Database级甚至是Instance级的互斥锁机制,但是这样的全局操作实际上很少发生,通常只在DBA维护的时候才触发。
- 在checkpoint操作开始时,WT提供指定时间点的数据库快照(Snapshot),该snapshot呈现的是内存中数据的一致性视图,当向Disk写入数据的时,WT将Snapshot中所有的数据以一致性的方式写入到数据文件Disk File中,一旦checkpint创建成功,WT保证了内存中的数据和磁盘中的数据保持一致性,因此CheckPoint充当的是还原点。 当WT创建Checkpoint的时,Mongo将数据刷新到数据文件中,默认情况下,WT创建还原点是60s,或者是产生2GB的journal文件,WT创建checkpoint期间,上一个checkpoint还依然有效,这意味的如果Mongo在创建新的Checkpoint期间遇到错误而终止,只要重启Mongo就能从上一个checkpoint中恢复过来。
- WT采用预写日志的机制,在数据更新的时候,向将数据写入到日志文件,然后在创建Checkpoint开始时,将日志文件中的记录操作,刷新到数据文件,就是说通过,预写日志和Checkpoint,将数据更新持久化到数据文件中,实现数据的一致性,WT日志文件会记录从上一次Checkpoint操作的之后发生的所有数据更新,在Mongo系统奔溃时通过日志文件能够还原到上次Checkpoint操作之后发生的数据更新。
- WT利用内存资源缓存俩部分数据,内部缓存,文件系统缓存,WT 内部缓存默认的使用量从1GB或60% of Ram,然而文件系统的缓存使用量不确定,Mongo 自动使用系统空闲内存,并且数据在文件系统缓存中压缩存储的。
- WT内部缓存的大小可以通过命令 -wiredtigercacheSizeDb来修改Mongo中WT缓存的大小,并且根据系统的RAM内存大小来计算合适的内存使用量
- 相比MMAPV1只是单纯的将Bson数据直接存储在磁盘上,WT则会在内存中的数据存储到磁盘前做一次压缩,这样的处理非常好的节省了磁盘的空间,但也增加了CPU的负担,目前WT采用来Snappy和前缀压缩俩种算法,其中snappy是默认的用于所有的Collection 的压缩算法,而前缀压缩则是用于对索引的压缩
- 当从mongodb中删除Document和或者是Collection的时候,Mongodb不会自动的释放磁盘的空间给操作系统,而是将在数据文件中维护一个Empty Records的列表,当数据重现插入时,Mongo将从Empty Records列表中分配新的存储空间给新的Document,不需要开辟新的存储空间,因此为了更有效的重用磁盘的空间,必须进行磁盘的碎片整理。WT中采用Compact命令来来移除Collection和索引的碎片,并将不实用的空间释放。
- In Memory 存储引擎
- InMemory存储引擎在执行写操作的时候,使用的是文件级别的并发控制,就是说在同一个时间多个写操作能够同时操作一个集合中的不同文档,当多个写操作修改同一个文件的时候,必须以序列化的方式进行,也就是说文档在被修改的时候,其它的操作只能等待。
- InMemory存储引擎将Data,Index,Oplog等存储到内存中,通过参数 --InMemorySizeDb设置占用的 内存量,默认是50%,单位是GB。
- InMemory不会持久化数据的存储,数据只保存在内存当中,读写操作都在内存中完成,不会把数据写到数据文件,如果Mongo停止或者关机,内存中的数据全部丢失。
- InMemory虽然不做持久化的操作,但是它会记录Oplog,该Oplog是存储在内存中的集合,MongoDb通过replication将Primary成员中的Oplog推送到其它的副本集中,这样在其它的副本中就可以重做Oplog中记录的操作,从而将Primary中的数据持久化存储。
介绍完mongodb的存储,我们在来看看mongodb的索引,mongodb中索引和其它的关系型数据库一样采用B-Tree的方式来存储的,如下图
参考文档如下
Mongodb存储引擎的变化https://docs.mongodb.com/manual/core/wiredtiger/WiredTiger Storage EngineWiredTiger Storage Enginehttps://docs.mongodb.com/manual/core/journaling/相关文章