想要深入了解MongoDB如何存储数据之前,有一个概念必须清楚,那就是Memeory-Mapped Files。

Memeory-Mapped Files

下图展示了数据库是如何跟底层系统打交道的。

  • 内存映射文件是OS通过mmap在内存中创建一个数据文件,这样就把文件映射到一个虚拟内存的区域。
  • 虚拟内存对于进程来说,是一个物理内存的抽象,寻址空间大小为2^64
  • 操作系统通过mmap来把进程所需的所有数据映射到这个地址空间(红线),然后再把当前需要处理的数据映射到物理内存(灰线)
  • 当进程访问某个数据时,如果数据不在虚拟内存里,触发page fault,然后OS从硬盘里把数据加载进虚拟内存和物理内存
  • 如果物理内存满了,触发swap-out操作,这时有些数据就需要写回磁盘,如果是纯粹的内存数据,写回swap分区,如果不是就写回磁盘。

MongoDB的存储模型

  • 有了内存映射文件,要访问的数据就好像都在内存里面,简单化了MongoDB访问和修改数据的逻辑
  • MongoDB读写都只是和虚拟内存打交道,剩下都交给OS打理
  • 虚拟内存大小=所有文件大小+其他一些开销(连接,堆栈)
  • 如果journal开启,虚拟内存大小差不多翻番
  • 使用MMF的好处1:不用自己管理内存和磁盘调度2:LRU策略3:重启过程中,Cache依然在。
  • 使用MMF的坏处1:RAM使用会受磁盘碎片的影响,高预读也会影响2:无法自己优化调度算法,只能使用LRU

  • 磁盘上的文件是有extent构成,分配集合空间的时候也是以extent为单位进行分配的
  • 一个集合有一个或者多个etent
  • ns文件里面命名空间记录指向那个集合的第一个extent

数据文件与空间分配

当创建数据库时(其实MongoDB没有显式创建数据库的方法,在向数据库中的集合写入数据时会自动创建该数据库),MongoDB会在磁盘上分配一组数据文件,所有集合,索引和数据库的其他元数据都保存在这些文件里。数据文件被放在启动时指定的dbpath里,默认放入/data/db下面。典型的一个文件组织结构如下:

$ cat /data/db
$ ls -al
-rw------- root root - : local.ns
-rw------- root root - : local.
-rw------- root root - : local.
-rw------- root root - : local.
-rw------- root root - : local.
-rw------- root root - : local.
-rw------- root root - : local.
-rw------- root root - : local.
-rw------- root root - : local.
-rw------- root root - : local.
-rw------- root root - : local.
-rw------- root root - : local.
-rw------- root root - : test.ns
-rw------- root root - : test.
-rw------- root root - : test.
-rw------- root root - : test.
-rw------- root root - : test.
-rw------- root root - : test.
-rw------- root root - : test.
-rw------- root root - : test.
-rw------- root root - : test.
-rw------- root root - : test.
...
-rwxr-xr-x root root - : mongod.lock
drwxr-xr-x root root - : journal
drwxr-xr-x root root - : _tmp
  • mongod.lock中存储了服务器的进程ID,是一个进程锁定文件。数据文件是依据所属的数据库命名的。
  • test.ns是第一个生成的文件(ns扩展名就是namespace的意思),数据库中的每个集合和索引都有自己的命名空间,每个命名空间的元数据都存放在这个文件里。默认情况下,.ns文件大小固定在16MB,大约可以存储24000个命名空间。也就是说数据库中的索引和集合总数不能超过24000,该值可以通过mongod的--nssize选项进行定制。
  • 像test.0这样以0开始的整数结尾的文件就是集合和索引数据文件。刚开始的时候,即使只有一条数据,MongoDB也会预分配几个文件,这种预分配的做法,能让数据尽可能连续存储,减少磁盘碎片。在像数据库添加数据时,MongoDB会分配更多的数据文件。每个新数据文件的大小都是上一个已分配文件的两倍(64M->128M->256M),直到预分配文件大小的上限2G。此处基于一个假设,如果总数据大小呈恒定速率增长,应该逐渐增加数据文件分配的空间。当然这个预分配策略也是可以通过--noprealloc关掉,但是不建议在production环境下使用。
  • 默认的local数据库,该数据库不参与replication。当mongod是一个副本集的成员时,在local数据库中就有一个叫做oplog.rs的预分配的capped集合,预分配的大小为磁盘空间的5%。这个大小可以通过--oplogSize进行调整。oplog主要用于副本集Primary和Secondary成员见的replication,它的大小限制了两个副本集之间,在重新完全同步之前,允许多长时间不同步。
  • journal目录,journal功能2.4版本默认是开启的。
  • 可以使用db.stats()来确认已使用空间和已分配空间。
  • {
    "db" : "test",
    "collections" : ,
    "objects" : , #文档总个数
    "avgObjSize" : 232.3416429039893, #单位是字节
    "dataSize" : , #集合中所有数据实际大小(包括padding factor为每个文档分配的额外空间以允许文档增长)。该值在文档size变小的时候,这个值不会减少,除非文档被删除,或者执行compact或者repairDatabase操作
    "storageSize" : , #分配给集合的空间大小(包括为集合增长预留的额外空间和未分配的已删除空间,即不会因为文档size变小或者删除而减小),实际上从数据文件中分配给集合的空间是以块为单位,也称之为extents,即分配的extents的大小
    "numExtents" : ,
    "indexes" : ,
    "indexSize" : ,
    "fileSize" : , #所有数据文件大小之和,不包括命名空间文件(ns文件)
    "nsSizeMB" : ,
    "dataFileVersion" : {
    "major" : ,
    "minor" :
    },
    "ok" :
    }
  • 使用db.accesslog.stats()确认某个集合的使用量
  • {
    "ns" : "test.accesslog",
    "count" : ,
    "size" : , #实际数据大小,不包括索引
    "avgObjSize" : 254.967435758365,
    "storageSize" : , #预分配的数据存储空间
    "numExtents" : ,
    "nindexes" : ,
    "lastExtentSize" : ,
    "paddingFactor" : , #当文档因更新size增长时事先padding可以提速,减少碎片的产生
    "systemFlags" : ,
    "userFlags" : ,
    "totalIndexSize" : ,
    "indexSizes" : {
    "_id_" : ,
    "action_1_time_1" : ,
    "gz_id_1_action_1_time_1" : ,
    "time_1" :
    },
    "ok" :
    }

--EOF--

MongoDB如何存储数据的更多相关文章

  1. 数据存储之使用MongoDB数据库存储数据

    安装MongoDB环境: 1.官网下载:https://www.mongodb.com/download-center#community 2.MongoDB可视化工具compass下载https:/ ...

  2. MongoDB存储数据

    想要深入了解MongoDB如何存储数据之前,有一个概念必须清楚,那就是Memeory-Mapped Files.   Memeory-Mapped Files   下图展示了数据库是如何跟底层系统打交 ...

  3. SpringBoot学习笔记(10):使用MongoDB来访问数据

    SpringBoot学习笔记(10):使用MongoDB来访问数据 快速开始 本指南将引导您完成使用Spring Data MongoDB构建应用程序的过程,该应用程序将数据存储在MongoDB(基于 ...

  4. 阿里云MongoDB存储数据

    近期上了个活动,考虑后期的运维及人力成本,还是选择了阿里云的MongoDB,不过阿里云这玩意本地测试官方没有给本地测试链接地址,只能做映射上去了测了... 选了个2核4G的,更多详细信息,可以去阿里上 ...

  5. 为什么MongoDB适合大数据的存储?

    NoSQL数据库都被贴上不同用途的标签,如MongoDB和CouchDB都是面向文档的数据库,但这并不意味着它们可以象JSON(JavaScript Object Notation,JavaScrip ...

  6. mongodb 物理删除数据

    刚开始用mongodb的时候,感觉很好用,速度很快,不过后面就遇到一个问题,数据物理内存一直增加,删除表也不管用. 然后网上找了各种办法,最后发现一个办法管用,就是物理删除存储数据. 操作如下: 1. ...

  7. Mongodb FAQ 存储(storage)篇

    1.什么是内存映射文件(memory mapped files)? 内存映射文件是操作系统通过调用函数mmap()创建的一个放在内存中的一个数据文件.这种文件可以当做一个从零开始的内存或者数组,你可以 ...

  8. MongoDB的存储结构及对空间使用率的影响

    MongoDB的存储结构及对空间使用率的影响 使用MongoDB一段时间的同学肯定会发现,MongoDB往往会占用比实际数据大小多不少空间的问题.如果利用db.stats()命令去查看,会发现Mong ...

  9. mongodb的存储引擎

    mongodb版本为3.4 mongodb存储引起的一些概述 存储引擎是MongoDB的核心组件,负责管理数据如何存储在硬盘和内存上.从MongoDB 3.2 版本开始,MongoDB 支持多数据存储 ...

随机推荐

  1. Linux 的启动流程

    转载:http://www.ruanyifeng.com/blog/2013/08/linux_boot_process.html 更多文档参见:http://pan.baidu.com/s/1hqo ...

  2. 1.5.3 什么是Tokenizer-分词

    什么是Tokenizer-分词 分词器的工作就是分解文本流成词(tokens).在这个文本中,每一个token都是这些字符的一个子序列.一个分析器(analyzer)必须知道它所配置的字段,但是tok ...

  3. Linux 查看物理内存

    free -k free -m free -b man free cat /proc/meminfo

  4. Parallel.ForEach() 并行循环

    现在的电脑几乎都是多核的,但在软件中并还没有跟上这个节奏,大多数软件还是采用传统的方式,并没有很好的发挥多核的优势. 微软的并行运算平台(Microsoft’s Parallel Computing ...

  5. LocalActivityManager的内部机制

    LocalActivityManager内部机制的核心在于,它使用了主线程对象mActivityThread来装载指定的Activity.注意,这里是装载,而不是启动,这点很重要. 所谓的启动,一般是 ...

  6. 机房收费系统之uml图——初版

    说起uml图,在我心中最难的当属类图无疑.虽然敲了三层的小例子,但真正让把三层和uml图结合起来,并且还要考虑设计模式的时候,总是让人有一种无从下手的感觉,不过还好,通过这半个多月的思考与探索(竟然用 ...

  7. 原来腾讯还出过一个开源项目libco

    虽然只能在OpenSUSE上使用,还是应该赞一个的.

  8. Hive编程(影印版)

    <Hive编程(影印版)> 基本信息 原书名:Programming Hive 作者: Edward Capriolo Dean Wampler Jason Rutherglen 出版社: ...

  9. ionic中input框禁止输入问题

    其实这个问题在之后沥青思路之后觉得还是挺好实现的,没有思路的时候真是找不到头绪~ 功能的描述为:当输入框中没有内容时,允许用户编辑:当其中有内容时不允许用户编辑,只有当用户点击编辑按钮后,才可允许编辑 ...

  10. JQuery Validate验证显示错误提示位置

    验证多个Name值相同的元素: $(".send").click(function () { var a = 0; var b = 0; var c = 0; var d = 0; ...