基本思想 将MongoDB用作内存数据库(in-memory database),也即,根本就不让MongoDB把数据保存到磁盘中的这种用法,引起了越来越多的人的兴趣。这种用法对于以下应用场合来讲,超实用:
MongoDB有一个非常酷的设计决策,就是她可以使用内存影射文件(memory-mapped file)来处理对磁盘文件中数据的读写请求。这也就是说,MongoDB并不对RAM和磁盘这两者进行区别对待,只是将文件看作一个巨大的数组,然后按 照字节为单位访问其中的数据,剩下的都交由操作系统(OS)去处理!就是这个设计决策,才使得MongoDB可以无需任何修改就能够运行于RAM之中。 |
实现方法 这一切都是通过使用一种叫做tmpfs的特殊类型文件系统实现的。在Linux中它看上去同常规的文件系统(FS)一样,只是它完全位于RAM中(除非其大小超过了RAM的大小,此时它还可以进行swap,这个非常有用!)。我的服务器中有32GB的RAM,下面让我们创建一个16GB的 tmpfs:# mkdir /ramdata # mount -t tmpfs -o size=16000M tmpfs /ramdata/ # df Filesystem1K-blocksUsed Available Use% Mounted on /dev/xvde15905712497392487179286% / none153449360153449360% /dev/shm tmpfs163840000163840000% /ramdata 接下来要用适当的设置启动MongoDB。为了减小浪费的RAM数量,应该把smallfiles和noprealloc设置为true。既然现在是基于RAM的,这么做完全不会降低性能。此时再使用journal就毫无意义了,所以应该把nojournal设置为true。 dbpath=/ramdata nojournal = true smallFiles = true noprealloc = true MongoDB启动之后,你会发现她运行得非常好,文件系统中的文件也正如期待的那样出现了: # mongo MongoDB shell version: 2.3.2 connecting to: test > db.test.insert({a:1}) > db.test.find() { "_id" : ObjectId("51802115eafa5d80b5d2c145"), "a" : 1 }# ls -l /ramdata/ total 65684 -rw-------. 1 root root 16777216 Apr 30 15:52 local.0 -rw-------. 1 root root 16777216 Apr 30 15:52 local.ns -rwxr-xr-x. 1 root root5 Apr 30 15:52 mongod.lock -rw-------. 1 root root 16777216 Apr 30 15:52 test.0 -rw-------. 1 root root 16777216 Apr 30 15:52 test.ns drwxr-xr-x. 2 root root40 Apr 30 15:52 _tmp 现在让我们添加一些数据,证实一下其运行完全正常。我们先创建一个1KB的document,然后将它添加到MongoDB中4百万次: > str = ""> aaa = "aaaaaaaaaa" aaaaaaaaaa > for (var i = 0; i < 100; ++i) { str += aaa; }> for (var i = 0; i < 4000000; ++i) { db.foo.insert({a: Math.random(), s: str}); } > db.foo.stats() { "ns" : "test.foo", "count" : 4000000, "size" : 4544000160, "avgObjSize" : 1136.00004, "storageSize" : 5030768544, "numExtents" : 26, "nindexes" : 1, "lastExtentSize" : 536600560, "paddingFactor" : 1, "systemFlags" : 1, "userFlags" : 0, "totalIndexSize" : 129794000, "indexSizes" : { "_id_" : 129794000 }, "ok" : 1 } |
文章图片 fbm 翻译于 3个月前 2人顶 顶 翻译的不错哦! |
可以看出,其中的document平均大小为1136字节,数据总共占用了5GB的空间。_id之上的索引大小为130MB。现在我们需要验证一件
非常重要的事情:RAM中的数据有没有重复,是不是在MongoDB和文件系统中各保存了一份?还记得MongoDB并不会在她自己的进程内缓存任何数据,她的数据只会缓存到文件系统的缓存之中。那我们来清除一下文件系统的缓存,然后看看RAM中还有有什么数据:
# echo 3 > /proc/sys/vm/drop_caches # free totalusedfreesharedbufferscached Mem:30689876629278024397096010445817368 -/+ buffers/cache:47436830215508 Swap:000 可以看到,在已使用的6.3GB的RAM中,有5.8GB用于了文件系统的缓存(缓冲区,buffer)。为什么即使在清除所有缓存之后,系统中仍然还有5.8GB的文件系统缓存??其原因是,Linux非常聪明,她不会在tmpfs和缓存中保存重复的数据。太棒了!这就意味着,你在RAM只有一份数据。下面我们访问一下所有的document,并验证一下,RAM的使用情况不会发生变化: > db.foo.find().itcount() 4000000# free totalusedfreesharedbufferscached Mem:30689876632798824361888013245818012 -/+ buffers/cache:50865230181224 Swap:000 # ls -l /ramdata/ total 5808780 -rw-------. 1 root root16777216 Apr 30 15:52 local.0 -rw-------. 1 root root16777216 Apr 30 15:52 local.ns -rwxr-xr-x. 1 root root5 Apr 30 15:52 mongod.lock -rw-------. 1 root root16777216 Apr 30 16:00 test.0 -rw-------. 1 root root33554432 Apr 30 16:00 test.1 -rw-------. 1 root root 536608768 Apr 30 16:02 test.10 -rw-------. 1 root root 536608768 Apr 30 16:03 test.11 -rw-------. 1 root root 536608768 Apr 30 16:03 test.12 -rw-------. 1 root root 536608768 Apr 30 16:04 test.13 -rw-------. 1 root root 536608768 Apr 30 16:04 test.14 -rw-------. 1 root root67108864 Apr 30 16:00 test.2 -rw-------. 1 root root 134217728 Apr 30 16:00 test.3 -rw-------. 1 root root 268435456 Apr 30 16:00 test.4 -rw-------. 1 root root 536608768 Apr 30 16:01 test.5 -rw-------. 1 root root 536608768 Apr 30 16:01 test.6 -rw-------. 1 root root 536608768 Apr 30 16:04 test.7 -rw-------. 1 root root 536608768 Apr 30 16:03 test.8 -rw-------. 1 root root 536608768 Apr 30 16:02 test.9 -rw-------. 1 root root16777216 Apr 30 15:52 test.ns drwxr-xr-x. 2 root root40 Apr 30 16:04 _tmp # df Filesystem1K-blocksUsed Available Use% Mounted on /dev/xvde15905712497396087175686% / none153449360153449360% /dev/shm tmpfs1638400058087801057522036% /ramdata 果不其然! :) |
文章图片 fbm 翻译于 3个月前 2人顶 顶 翻译的不错哦! |
有一点很重要,就是写操作会写入一个特殊的叫做oplog的collection,它位于local数据库之中。缺省情况下,它的大小是总数据量的5%。在我这种情况下,oplog会占有16GB的5%,也就是800MB的空间。在拿不准的情况下,比较安全的做法是,可以使用oplogSize这个选项为oplog选择一个固定的大小。如果备选服务器宕机时间超过了oplog的容量,它就必须要进行重新同步了。要把它的大小设置为1GB,可以这样:
oplogSize = 1000
分片(sharding)呢? 既然拥有了MongoDB所有的查询功能,那么用它来实现一个大型的服务要怎么弄?你可以随心所欲地使用分片来实现一个大型可扩展的内存数据库。配置服务器(保存着数据块分配情况)还还是用过采用基于磁盘的方案,因为这些服务器的活动数量不大,老从头重建集群可不好玩。
注意事项 【基于tmpfs使用mongoDB】RAM属稀缺资源,而且在这种情况下你一定想让整个数据集都能放到RAM中。尽管tmpfs具有借助于磁盘交换(swapping)的能力,但其性能下降将非常显著。为了充分利用RAM,你应该考虑:
- 使用usePowerOf2Sizes选项对存储bucket进行规范化
- 定期运行compact命令或者对节点进行重新同步(resync)
- schema的设计要相当规范化(以避免出现大量比较大的document)
推荐阅读
- 故障分析 | MongoDB 5.0 报错 Illegal instruction 解决
- MongoDB find getmore操作慢问题排查
- mongodb 6、mongodb内存使用优化
- MongoDB内存使用原理
- mongodb 内存
- 【MongoDB】如何将MongoDB改造成内存数据库
- mongodb|mongodb分页排序获取数据 导致超出32M限制
- Mongodb中FAQ整理
- Mongodb 内存问题
- mongodb 内存泄露的bug, v2.0.3中还依然存在