在MongoDB 2.6版本之前(包括2.6),只有一种存储引擎:MMAP(Memory mapping,内存映射引擎)。MongoDB 3.0以后,MMAP升级为MMAPv1, 同时提供了插件式引擎API,引入wiredTiger,mongoDB 3.2默认使用WiredTiger引擎,MongoDB 4.0版本删除了MMAP引擎。
文章目录
MMAPv1引擎
常规的文件系统操作(调用read等函数)为了提高读写效率和保护磁盘,采用的是页缓存机制,读文件时需要先将文件页从磁盘拷贝至页缓存中,页缓存处在内核空间,不能被用户进程直接寻址,还需要将页缓存中的数据再次拷贝到内存对应的用户空间中,所以需要通过两次数据拷贝的过程,才能完成进程对文件内容的获取。
在MMAP操作文件时,创建新的虚拟存储区域,建立文件磁盘地址与虚拟地址的映射关系,此时MMAP只是在虚拟内存分配了地址空间,所以32位的机器,最多支持2GB的文件映射。之后访问数据时,通过已建立好的映射关系,只使用一次数据拷贝,就从磁盘中将数据传入内存的用户空间中,供进程使用。
在MongoDB的MMAPv1引擎机制中,服务器启动时,其内存对所有数据文件进行映射,接下来完全由操作系统负责将数据刷新到磁盘,以及管理内存中数据页的交换。
命名空间与区段
MMAPv1引擎中,每个数据库由一个.ns文件和若干数据文件组成,数据文件从0开始编号,mydb.0、mydb.1、mydb.2等,文件大小从64MB起,依次倍增,最大为2GB。这一特性使得较小的数据库不会浪费过多的空间,而较大的数据库可使用连续的磁盘空间。图中,mydb.1、mydb.2、mydb.3(为便于理解,此处省略了mydb.0)分别是数据库mydb的三个数据文件,mydb.ns的文件用于保存mydb数据库的命名空间元数据,图中未给出。
每个数据库包含多个命名空间(namespace),存放在.ns文件中,单个命名空间128字节,数据库按照命名空间进行组织,每个命名空间中存放特定集合的数据,集合中的文档、索引都拥有自己的命名空间。mydb.ns文件实际是一个hash表,用于快速定位某个namespace的起始位置。
如下图,数据库mydb包含了两个集合c1、c2,对应两个命名空间mydb.c1、mydb.c2,mydb.$freelist是一个特殊的命名空间,用于跟踪记录不再使用的区段(如被删除的集合或索引所在的区段),最后,还有一个预分配命名空间。
每个命名空间的数据可以在磁盘上分为几组数据,即区段。这几个区段在磁盘上未必是连续的(图例中不连续)。
MongoDB也会预分配数据文件,数据文件一旦被填满,就开始预分配,这意味着MongoDB服务器总会为每个数据库维护一个额外的空白数据文件(如图中的mydb.3),以提前避免文件分配失败。使用 -- noprealloc
选项可以关闭预分配功能。
mydb.1、mydb.2,分成了分属于不同命名空间的区段,mydb.1有三个区段、mydb.2有四个区段、