3.0版本以前,MongoDB只有一个存储引擎——MMAP,MongoDB3.0引进了一个新的存储引擎——WiredTiger,同时对原有的MMAP引擎进行改进,产生MMAPv1存储引擎,并将其设置为MongoD3.0的默认存储引擎。然而MMAP引擎的一些弊端在MMAPv1引擎依旧存在,3.2版本开始,MongoDB已将默认的存储引擎设置为WiredTiger。

  作为MongoDB原生的存储引擎,MMAPv1也是有它自己的优势的。MMAPv1基于内存映射文件,它擅长于大容量插入、读取和就地更新的工作负载。本文就先对MMAPv1存储引擎进行介绍。

一、MMAPv1存储引擎的数据组织方式

  使用MMAPv1存储引擎,每个数据库由一个.ns文件和一个或多个数据文件组成,假设数据库名称为mydb,则.ns文件名称为mydb.ns,数据文件名称为:mydb.0,mydb.1,mydb.2....,文件编号从0开始,文件大小从64MB开始,依次倍增,最大为2GB。

  .ns文件实际上是一个hash表,用于快速定位某个集合在数据文件中存储的起始位置。每个数据文件被划分成多个extent,每个extent只包含一个集合的数据,同一个集合的所有extent之间使用双向链表连接,一个extent包含多个文档,同一个extent中的所有文档也使用双向链表连接,所以,同一个集合中所有文档是使用双向链表连接的。

.ns文件的数据组织结构如下:

数据文件的数据组织结构如下:

说明:以上关于.ns文件和数据文件的数据组织结构图是学习另一篇博文之后总结归纳出来的,原文连接:https://yq.aliyun.com/articles/60

  基于这样的数据组织结构,MMAPv1数据的增删改操作实现过程分别如下(各个步骤按优先顺序排列):

1. 新增文档:

(1)优先使用大小合适的已删除文档的空间。

(2)若没有合适的已删除文档空间,则使用大小合适的空闲extent。

(3)若没有大小合适的空闲extent,则创建新的extent,创建过程若数据文件空间不足则创建新的数据文件。

2. 删除文档:

  将删除文档文档插入对应集合的已删除文档链表中,删除文档的空间可以被以后新增的新文档使用,但也有可能因为空间大小不适合新文档而一直无法回收利用,从而产生存储空间碎片造成存储空间的浪费,这种情况可以对集合执行compact命令来整理存储碎片:

db.runCommand({compact: '<collection>'})

3. 更新文档:

(1)若更新后文档变小或不变,直接使用原来空间存放,若有多余空间且足够多,还会将多余空间插入集合的已删除文档链表中以回收利用。

(2)若更新后文档变大,则更新执行过程相当于删除原来文档+新增更新后文档。

二、MMAPv1相对于MMAP的改变

1. 文件空间分配方式不变

  改进后的MMAPv1还是和MMAP一样在数据库级别分配文件,每个数据库中所有的集合和索引都混合存储在数据文件中,磁盘空间无法及时自动回收的问题还是没有得到解决。

  MMAPv1数据文件预分配策略:为了保证连续的存储空间,避免产生磁盘碎片,MMAPv1对数据文件的使用采用预分配策略:数据库创建之后,先创建一个编号为0的文件,大小为64M,当这个文件有一半以上被使用时,再创建一个编号为1的文件,大小是上一个文件的两倍,即128M,依此类推,直到创建文件大小达到2G,以后再创建的文件大小就都是2G了。

2. 锁粒度由库级别锁提升为集合级别锁

  在MMAP中,锁粒度是库级别锁,MMAPv1将其提升为集合级别锁,即同一时刻同一个集合中只能进行一个写操作,在一定程度上提升了数据库的并发处理能力。

3. 文档空间分配方式改变

在MMAP存储引擎中,文档是按照写入顺序排列存储在硬盘中的。如果文档更新后长度变长且原有存储位置后面没有足够的空间放下增长部分的数据,那么文档就要移动到文件中的其他位置,导致集合中所有的索引都要同步修改文档新的存储位置,严重降低了写性能。

  若想避免这种情况的发生,需要在文档后保留一定空间用于存放文档更新后可能增大的部分,为此,MMAP采用两种策略进行文档空间分配:

(1)基于paddingFactor(填充因子)的自适应分配方式

  这种方式会基于每个集合中的文档更新历史计算文档更新的平均增长长度,然后根据平均增长长度设置一个paddingFactor(填充因子,大小大于1), 以后在新文档插入或旧文档移动时分配的空间=文档实际长度×paddingFactor。

(2)基于usePowerOf2Sizes的预分配方式

  这种方式则不考虑更新历史,直接为文档分配比文档大小大而又最接近文档大小的2的N次方大小的存储空间(当大小超过2MB时则变为2MB的倍数增长),例如若文档大小为200Bytes则直接分配256Bytes的空间。

  对于第一种策略,由于每个文档大小不一,经过填充后的空间大小也不一样,如果集合上的更新操作很多,那么因为记录移动而导致的空闲空间会因为大小不一而难以重用。而第二种策略就不一样了,它分配的空间大小都是2的N次方,因此更容易维护和利用。所以,改进后的MMAPv1便抛弃了第一种策略,只使用较优的第二种策略。另外,MongoDB还提供了一个“No Padding Allocation”策略,按照数据的实际尺寸分配空间,如果某个集合上绝大多数情况下执行的都是insert或者in-place update(更新后文档size不会变大),还有极少数的delete,那么可以在这个集合使用这个策略,提高磁盘空间利用率。

三、MMAPv1日志记录

  为了确保对MongoDB数据集的所有修改都持久化到硬盘上,MongoDB默认会将所有的操作日志记录到硬盘上,MMAPv1存储引擎的默认配置是每隔60秒写一次数据文件(可以使用storage.syncPeriodSecs改变写数据文件的时间间隔),每隔100毫秒写一次到日志文件,写日志的频率比写数据文件的频率更高!

四、MMAPv1内存使用

使用MMAPv1存储引擎,MongoDB会自动使用所有机器的空闲的内存作为它的cache,即MongoDB会使用尽可能多的空闲的内存。但MongoDB使用的内存由系统资源监视器监视,由系统控制,可随时回收,如果其他的进程突然需要服务器大量的内存,MongoDB将会让出内存给其他的进程。当然,使用MMAPv1存储引擎的时候,分配的内存越大,MongoDB的性能就越好。

MongoDB存储引擎(上)——MMAPv1的更多相关文章

  1. MongoDB 存储引擎和数据模型设计

    标签: MongoDB NoSQL MongoDB 存储引擎和数据模型设计 1. 存储引擎 1.1 存储引擎是什么 1.2 MongoDB中的默认存储引擎 2. 数据模型设计 2.1 内嵌和引用 2. ...

  2. MongoDB存储引擎选择

    MongoDB存储引擎选择 MongoDB存储引擎构架 插件式存储引擎, MongoDB 3.0引入了插件式存储引擎API,为第三方的存储引擎厂商加入MongoDB提供了方便,这一变化无疑参考了MyS ...

  3. MongoDB学习笔记(五、MongoDB存储引擎与索引)

    目录: mongoDB存储引擎 mongoDB索引 索引的属性 MongoDB查询优化 mongoDB存储引擎: 目前mongoDB的存储引擎分为三种: 1.WiredTiger存储引擎: a.Con ...

  4. MongoDB 存储引擎选择

    MongoDB存储引擎选择 MongoDB存储引擎构架 插件式存储引擎, MongoDB 3.0引入了插件式存储引擎API,为第三方的存储引擎厂商加入MongoDB提供了方便,这一变化无疑参考了MyS ...

  5. MongoDB 存储引擎:WiredTiger和In-Memory

    存储引擎(Storage Engine)是MongoDB的核心组件,负责管理数据如何存储在硬盘(Disk)和内存(Memory)上.从MongoDB 3.2 版本开始,MongoDB 支持多数据存储引 ...

  6. MongoDB 存储引擎Wiredtiger原理剖析

    今天开始看MongoDB 3.2的文档,发现了这么两句话 Support for Multiple Storage Engines MongoDB supports multiple storage ...

  7. MongoDB存储引擎(中)——WiredTiger

    上一篇博文介绍了MongoDB的MMAPv1存储引擎,本文接着介绍MongoDB另一个存储引擎--WiredTiger,WiredTiger是在MongoDB3.0版本引入的,并且在MongoDB3. ...

  8. mongodb存储引擎

    存储引擎(Storage Engine)是MongoDB的核心组件,负责管理数据如何存储在硬盘(Disk)和内存(Memory)上.从MongoDB 3.2 版本开始,MongoDB 支持多数据存储引 ...

  9. MongoDB存储引擎、索引 原

    wiredTiger MongoDB从3.0开始引入可插拔存储引擎的概念.目前主要有MMAPV1.WiredTiger存储引擎可供选择.在3.2版本之前MMAPV1是默认的存储引擎,其采用linux操 ...

随机推荐

  1. Node.js连接mysql报加密方式错误解决方案

    本人在学习全栈开发过程中做一个Node的web项目在连接本地MySQL8.0版本的数据库时,发现Navicat连接不上,它报了一个数据库的加密方式导致连接不上的错误,错误如下: MySQL8.0版本的 ...

  2. Asp.Net Core 入门(六)—— 路由

    Asp.Net Core MVC的路由在Startup.cs文件中的Configure方法中进行配置,使其加入到Http请求管道中,如果不配置,那么我们所发送的请求无法得到象应. 那么该怎么配置Asp ...

  3. 一个小笔记(5):A*算法

    A-Star算法是一种静态路网中求解最短路径最有效的直接搜索方法其实百科有 http://baike.baidu.com/link?url=CvmkWQIAmztYgMq3Nk1WyWkDiC0koV ...

  4. Navicat 复制多条数据

  5. pseudogene|鉴定功能基因|expressed se|quence tag

    基因 (鉴定DNA:可以直接利用DNA序列鉴别基因,但存在3个问题) 1.intron太长(使用用来连接的算法不可及) 2.因为通常功能基因的第一个oxen中有非编码区和启动子最后一个oxen中有终止 ...

  6. oracle中group by的高级用法

    简单的group by用法 select c1,sum(c2) from t1 where t1<>'test' group by c1 having sum(c2)>100; ro ...

  7. 洛谷 P2921 在农场万圣节

    https://www.luogu.org/problemnew/show/P2921 开始感觉这题30行代码就可以搞定,还是太菜啦,还是乖乖地写了tarjan. 对图进行缩点,那么这个强联通分量中的 ...

  8. 浮动的label

    在web项目中,有一个很重的模块就是登陆/注册模块,这个模块的主体部分就是一个form表单,这个form表单包含两个重要input组(用户名/密码),每个input组都包含label和input,而关 ...

  9. 一次下载多个文件的解决思路-JS

    一次下载多个文件的解决思路(iframe) - Eric 真实经历 最近开发项目需要做文件下载,想想挺简单的,之前也做过,后台提供下载接口,前端使用window.location.href就行了呗.不 ...

  10. Django REST framework 五种增删改查方法

    Django-DRF-视图的演变   版本一(基于类视图APIView类) views.py: APIView是继承的Django View视图的. 1 from .serializers impor ...