转自:http://www.mongoing.com/blog/file-storage
参考:http://blog.mlab.com/2014/01/how-big-is-your-mongodb/
数据库文件类型
MongoDB 的数据库文件主要有 3 种:
- journal 日志文件
- namespace 表名文件
- data 数据及索引文件
日志文件
跟一些传统数据库不同,MongoDB 的日志文件只是用来在系统出现宕机时候恢复尚未来得及同步到硬盘的内存数据。日志文件会存放在一个分开的目录下面。启动时候 MongoDB 会自动预先创建 3 个每个为 1G 的日志文件(初始为空)。除非你真的有持续海量数据并发写入,一般来说 3 个 G 已经足够。
命名文件 dbname.ns
这个文件用来存储整个数据库的集合以及索引的名字。这个文件不大,默认 16M,可以存储 24000 个集合或者索引名以及那些集合和索引在数据文件中得具体位置。通过这个文件 MongoDB 可以知道从哪里去开始寻找或插入集合的数据或者索引数据。这个值可以通过参数调整至2G。
数据文件 dbname.0, dbname.1,… dbname.n
MongoDB 的数据以及索引都存放在一个或者多个 MongoDB 数据文件里。第一个数据文件会以“数据库名.0”命名,如 my-db.0。这个文件默认大小是 64M,在接近用完这个 64M 之前,MongoDB 会提前生成下一个数据文件如 my-db.1。数据文件的大小会 2 倍递增。第二个数据文件的大小为 128M,第三个为 256M。一直到了 2G 以后就会停止,一直按这个 2G 这个大小增加新的文件。
当然 MongoDB还 会生成一些临时文件如 _tmp
和 mongod.lock
等, 不过他们跟我们的讨论都没有太大相关性。
数据文件结构
Extent
在每一个数据文件内,MongoDB 把所存储的 BSON 文档的数据和 B 树索引组织到逻辑容器“Extent”里面。如下图所示(my-db.1 和 my-db.2 是数据库的两个数据文件):
- 一个文件可以有多个 Extent
- 每一个 Extent 只会包含一个集合的数据或者索引
- 同一个集合的数据或索引可以分布在多个 Extent 内。这几个 Extent 也可以分步于多个文件内
- 同一个 Extent 不会又有数据又有索引
Record 记录
在每个 Extent 里面存放有多个”Record“, 每一个记录里包含一个记录头以及 MongoDB 的 BSON 文档,以及一些额外的 padding 空间。Padding 是 MongoDB 在插入记录时额外分配一些未用空间,这样将来文档变大的时候不至于需要把文档迁移到别处。 记录头以整个记录的大小开始,包括该记录自己的位置以及前一个记录和后一个记录的位置。可以想象成一个 Double Linked List。
数据库大小参数
在之前的基础上,我们可以来理解一下 db.stats() 里面关于空间大小参数的含义。
dataSize
dataSize 是最接近真实数据大小的一个参数。你可以用来检查你的数据有多少。这个大小包括了数据库(或者集合)的每条记录的总和。注意每条记录除了 BSON 文档外还有 header 及 padding 这些额外开销。所以实际大小会比真正数据所占空间会稍大。
当删除文档的时候,这个参数会相应变小因为它是所有文档数的大小总和。如果你的文档没有删除,只是文档内部的字段被删除或缩小,则不会对 dataSize 有影响。原因就是因为文档所在记录还在,并且整条记录所占空间并无改动,只不过记录内的未用空间变多了而已。
storageSize
这个参数等于数据库或者某个集合所有用到的 Data Extents 的总和。注意这个数字会大于 dataSize 因为 Extent 里面会有一些删除文档之后留下来的碎片(deleted)。及时你的 storageSize 大出 dataSize 很多,这个也不一定就是很糟糕的情况。如果有新插入的文档小于或等于碎片的大小,MongoDB 会重新利用这个碎片来存储新的文档。不过在这之前这些碎片将一直会被保留在那里占用空间。由于这个原因,你删除文档的时候这个参数不会变小。
碎片问题会因为运行的时间变长而变得严重。你可以通过 compact 命令来进行碎片清理或者通过新架一台从机复制所有数据,然后变成主节点的方式来解决这些碎片。
fileSize
这个参数只在数据库上有效,指的是实际文件系统中用到的文件的大小。它包括所有的数据 Extents 的总和,索引 Extent 的总和,以及一些未被分配的空间。之前提到 MongoDB 会对数据库文件创建时候进行预分配,例如最小就是 64M,哪怕你只有几百个 KB 的数据。所以这个参数可能会比实际的数据大小会大不少。这些额外未用空间是用来保证 MongoDB 可以在新的数据写入时候快速的分配新的 Extent,避免引起磁盘空间分配引起的延迟。
值得注意的是,当你删除文档,或甚至集合和索引,这个参数不会变小。换句话说,数据库所使用的硬盘空间只会上升(或者不变),而不会因为删除数据而变小。当然需要知道的是这并不就意味着浪费,只是说有很多预留空间而已。