作为纯内存数据库使用
基本思想
将MongoDB用作内存数据库(in-memory database),也就是让MongoDB
完全在内存中操作者数据的用法,比较适用于以下场景。
置于慢速RDBMS系统之前的写操作密集型高速缓存。
嵌入式系统。
无需持久化数据的PCI兼容系统。
MongoDB
可以使用内存影射文件(memory-mapped file)
来处理对磁盘文件中数据的读写请求。这也就是说,MongoDB
并不对RAM和磁盘这两者进行区别对待,只是将文件看作一个巨大的数组,然后按照字节为单位访问其中的数据,剩下的都交由操作系统去处理。
实现方法
这是通过使用tmpfs
的特殊类型的文件系统实现的。在Linux中它看上去同常规的文件系统一样,只是它完全位于RAM中。例如,在32GB的RAM种创建一个16GB的tmpfs
。
> mkdir /ramdata
> mount -t tmpfs -o size=16000M tmpfs /ramdata/
> df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/xvde1 5905712 4973924 871792 86% /
none 15344936 0 15344936 0% /dev/shm
tmpfs 16384000 0 16384000 0% /ramdata
接下来要用适当的设置启动MongoDB
。
为了减小浪费,应该把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 root 5 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 root 40 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
}
可以看出,其中的document
平均大小为1136字节,数据总共占用了5GB的空间。_id之上的索引大小为130MB。
现在只需要验证RAM中的数据有没有重复,是不是在MongoDB
和文件系统中各保存了一份就行了。
MongoDB
并不会在自己的进程内缓存任何数据,数据只会缓存到文件系统的缓存之中。所以清除文件系统的缓存,然后看看RAM中还有什么数据。
# echo 3 > /proc/sys/vm/drop_caches
# free
total used free shared buffers cached
Mem: 30689876 6292780 24397096 0 1044 5817368
-/+ buffers/cache: 474368 30215508
Swap: 0 0 0
可以看到,在已使用的6.3GB的RAM中,有5.8GB用于了文件系统的缓存(缓冲区,buffer)。这是因为Linux不会在tmpfs
和缓存中保存重复的数据。这也意味着在RAM只有一份数据。
下面访问一下所有的document,并验证RAM的使用情况不会发生变化。
> db.foo.find().itcount()
4000000
> free
total used free shared buffers cached
Mem: 30689876 6327988 24361888 0 1324 5818012
-/+ buffers/cache: 508652 30181224
Swap: 0 0 0
# ls -l /ramdata/
total 5808780
-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 root 5 Apr 30 15:52 mongod.lock
-rw-------. 1 root root 16777216 Apr 30 16:00 test.0
-rw-------. 1 root root 33554432 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 root 67108864 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 root 16777216 Apr 30 15:52 test.ns
drwxr-xr-x. 2 root root 40 Apr 30 16:04 _tmp
# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/xvde1 5905712 4973960 871756 86% /
none 15344936 0 15344936 0% /dev/shm
tmpfs 16384000 5808780 10575220 36% /ramdata
复制(replication)和分片(sharding)
既然服务器在重启时RAM中的数据都会丢失,所以可能会想使用复制来保存数据。
采用标准的副本集(replica set)就能够获得自动故障转移(failover),还能够提高数据读取能力(read capacity)。
如果有服务器重启了,它就可以从同一个副本集中另外一个服务器读取数据从而重建自己的数据(重新同步,resync)。即使在大量数据和索引的情况下,这个过程也不会慢,因为索引操作都是在RAM中进行的。
对于分片也是一样的。
不过,需要注意的是,RAM
属于稀缺资源,尽管tmpfs
具有借助于磁盘交换(swapping)的能力,但其性能下降将非常显著。
所以,为了充分利用RAM,需要考虑下面几件事。
使用
usePowerOf2Sizes
选项对存储bucket
进行规范化。定期运行compact命令或者对节点进行重新同步(resync)。
schema的设计要规范化,避免出现大量比较大的
document
。
感谢支持
更多内容,请移步《超级个体》。