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. 利用python进行数据分析1_numpy的基本操作,建模基础

    import numpy as np # 生成指定维度的随机多维数据 data=np.random.rand(2,3) print(data) print(type(data)) 结果: [[0.11 ...

  2. Hopfield 网络(上)

    讲的什么 这部分主要对 Hopfield 网络作一大概的介绍.写了其模型结构.能量函数和网络的动作方式.主要参考了网上搜到的一些相关 PPT.   概述 早在 1982 年,Hopfield 发表的文 ...

  3. WINDOWS-API:操作网络映射盘-WNetAddConnection2

    首先在VC项目属性,开发依赖项里添加MPR.lib:然后,配置文件里填入以下信息.  //本地映射盘符 MapDriver=T: //目标根目录 //MapSharedPath=\\192.168.0 ...

  4. 6.python

    最早的'密码本' ascii 涵盖了英文字母大小写,特殊字符,数字.01010101ascii 只能表示256种可能,太少,创办了万国码 unicode 16表示一个字符不行,32位表示一个字符. A ...

  5. javase(1)_基础语法

    一.java概述 1.Java语言特点:纯面向对象(一切皆对象),平台无关(JVM屏蔽底层运行平台的差异),不同的平台有不同的JVM,JVM将程序翻译成当前操作系统能执行的程序,一次编译到处运行),健 ...

  6. LeetCode 字符串的排列

    给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列. 换句话说,第一个字符串的排列之一是第二个字符串的子串. 示例1: 输入: s1 = "ab" s2 ...

  7. 【树状数组 离散化】bzoj1573: [Usaco2009 Open]牛绣花cowemb

    解方程题! Description Bessie学会了刺绣这种精细的工作.牛们在一片半径为d(1 <= d <= 50000)的圆形布上绣花. 它们一共绣了N (2 <= N < ...

  8. docker系列之基础命令-1

    1.docker基础命令 docker images 显示镜像列表 docker ps 显示容器列表 docker run IMAGE_ID 指定镜像, 运行一个容器 docker start/sto ...

  9. requests库的学习——跟随官方文档

    发送GET请求: import requests r=requests.get("http://www.kekenet.com/") 如果需要传递参数可以有以下几种方法: impo ...

  10. shell-code-6-输入输出重定向

    解释: 1. 文件描述符0通常是标准输入(STDIN,终端),1 是标准输出(STDOUT,终端),2 是标准错误输出(STDERR). 2. 如果希望 stderr 追加到 file 文件末尾,可以 ...