多数情况下,MongoDB用户将其看做一个黑盒子。当试图理解性能特征或想对其系统有更深理解时,对MongoDB内部了解一些还是有帮助的。
1.BSON
MongoDB文档是一个抽象的概念——文档的具体表示方法取决于所用的驱动或语言。因为文档广泛用于MongoDB通信,因此,还需要有一个被MongoDB生态系统中所有驱动、工具和进程共享的文档表示方法。
该表示方法称为二进制JSON(BSON)。BSON是一个能用字节串表示任何MongoDB文档的轻量级二进制格式。数据库理解BSON,BSON是文档按照其存储到磁盘的格式。
当给驱动一个文档插入,用作查询等,将该文档发送给服务器前,它将该文档编码成BSON。同样,从服务器返回到客户端的文档也用BSON串发送。返回到客户端前,该BSON文档被驱动解码成本地文档表示方法。
BSON格式有三个主要目标:
1)高效
BSON被设计来高效的表示数据,而不用太多额外的空间。最糟糕的场景下,BSON的效率会比JSON稍差,但在最好的场景(例如:当存储二进制数据或大数值时),BSON要高效的多。
2)可遍历性
某些场景下,BSON缺失牺牲空间效率来使得格式容易遍历。例如:字符串前面冠以长度,而非依赖终止符来表示字符串结尾。当MongoDB服务器需要对文档内省时遍历性就很有用。
3)性能
最后,BSON被设计以更快的进行编码和解码。其使用C风格表示法来表示类型,该方法与大多数编程语言一起工作会很快。
2.线协议(Wire Protocol)
驱动用一种轻量级TCP/IP线协议来访问MongoDB服务器。该协议记录在MongoDB wiki上,但基本包含BSON数据的薄包装。例如:插入信息包含20个字节的头数据(其包含一个告诉服务器执行一个插入和信息长度的代码),插入的集合名和一列要插入的BSON文档。
3.数据文件
MongoDB数据目录中,默认为/data/db/,每个数据库都有单独的文件。每个数据库有一个.ns文件和几个数据文件,数据文件有单向增长的数字扩展名。因此,数据库foo将被存储于文件foo.ns,foo.0,foo.1,foo.2等。
每个新的数字数据文件的大小将会翻倍,直到达到最大2GB的文件大小。该行为可以防止小数据库浪费磁盘空间,同时,保持大数据库在磁盘的连续区域内。MongoDB也预分配数据文件已确保性能一致。(该行为能通过--noprealloc选项关闭。)预分配在后台发生,且每次数据文件填满时被初始化。这意味着MongoDB服务器总是试图为每个数据库保持一个额外的、空数据文件已避免文件分配的阻塞。
4.命名空间和扩展(Namespaces和Extents)
数据文件内,每个数据库被组织成命名空间,每个命名空间存储特定类型的数据。每个集合的文档有其自己的命名空间,每个索引也一样。命名空间的元数据存储于数据库的.ns文件中。每个命名空间的数据在磁盘上分组成数据文件的部分,称为扩展(extents)。
图4-1中,数据库foo有三个数据文件,第三个文件为预分配且为空。前两个数据文件已被分为属于几个不同命名空间的扩展。
图4-1 命名空间和扩展
图4-1显示几个关于命名空间和扩展的有趣的事情。每个命名空间能有几个不同的扩展,其在磁盘上并不一定连续。就像数据库的数据文件,命名空间的扩展大小也会在每次分配时增大。这用于平衡命名空间的空间浪费和磁盘上数据大部分连续。该图也显示一个特殊命名空间,$freelist,其用于保持不再使用的扩展的轨迹(例如:来自删除的集合或索引的扩展)。当命名空间分配一个新扩展时,其将首先搜索freelist以查看是否有合适大小的扩展可用。
5.内存映射的存储引擎
MongoDB的默认存储引擎(此时仅被支持的存储引擎)为一个内存映射的引擎。当服务器启动时,其内存映射所有的数据文件。接着,操作系统负责管理将数据刷出到磁盘,并负责将数据读入写出。该存储引擎有几个重要特性:
1)MongoDB管理内存的代码小而干净,因为大部分工作推给了操作系统。
2)MongoDB服务器进程的虚拟内存通常很大,超过整个数据集的大小。这是没问题的,因为操作系统将处理内存包含的数据量。
3)MongoDB不能控制数据被写入磁盘的顺序,因此,其用预写日志来提供单服务器持久性是不可能的。目前,正在研MongoDB其他存储引擎来支持单服务器持久性。
4)32位MongoDB服务器每个mongod数据被限定到最大2GB。因为所有数据都必须用32位寻址。