MongoDB的内存使用和预热
以下是有关MongoDB内存使用和预热的简要解释。
前提是在Linux上使用MongoDB ~2.6版本,2.8版本的新存储引擎(Wired Tiger)与此无关。
MongoDB的内存管理
首先,MongoDB是如何管理内存的呢?
总结来说,我们不管理内存。
我完全依赖于操作系统。具体来说,我使用Linux操作系统的mmap()系统调用。
mmap指的是什么?
mmap是一种将文件系统中的文件映射到内存中,使进程能够快速访问映射文件内容的机制。
即使在进程启动后使用mmap映射文件,初始时并不会加载任何内容到内存中。
当进程尝试读取文件时,才会将其加载到内存中。
之后,文件将一直留在内存中,并在后续访问时通过内存进行响应。
如果内存不足,mmap算法会将其从内存中移出,这就是页面错误。
MongoDB和mmap
在MongoDB中,我们将数据目录下的数据库文件使用mmap技术加载到内存中。
当我们查看数据目录下的文件列表(通过ls命令),你会发现一些类似于数据库名.0或数据库名.1的文件,
这些就是数据库文件。
[db]# ls -lh
合計 545M
drwxr-xr-x 2 root root 4.0K 11月 27 22:40 2014 journal
-rw------- 1 root root 64M 11月 27 22:40 2014 local.0
-rw------- 1 root root 16M 11月 27 22:40 2014 local.ns
-rwxr-xr-x 1 root root 6 11月 27 22:40 2014 mongod.lock
-rw------- 1 root root 64M 11月 27 21:15 2014 test.0 ★これ
-rw------- 1 root root 128M 11月 27 21:15 2014 test.1 ★これ
-rw------- 1 root root 256M 11月 27 21:15 2014 test.2 ★これ
-rw------- 1 root root 16M 11月 27 21:15 2014 test.ns
数据文件的内容.
数据文件的内容包括数据本身(BSON)和索引。
数据文件中包含可变长度的数据用extents和索引用extents存储。
关于具体细节,以下幻灯片非常易于理解。
http://blog.mongolab.com/2014/01/how-big-is-your-mongodb/
MongoDB将数据载入内存的时间
启动时不在内存中
我相信根据之前的讨论您已经明白了。
MongoDB在启动时并不把数据和索引加载到内存中。
因为它正在使用mmap。
让我们来看一下以下的hoge收藏品作为例子。 (Tatoeba: 让我们来看一下以下的hoge收藏品作为一个例子。)
> db.hoge.stats()
{
"ns" : "test.hoge",
"count" : 1740681,
"size" : 83552848,
"avgObjSize" : 48,
"storageSize" : 123936768,
"numExtents" : 11,
"nindexes" : 4,
"lastExtentSize" : 37625856,
"paddingFactor" : 1,
"systemFlags" : 0,
"userFlags" : 1,
"totalIndexSize" : 228331152,
"indexSizes" : {
"_id_" : 50846544,
"a_1" : 43807008,
"_id_1_a_1" : 66838800,
"a_1__id_1" : 66838800
},
"ok" : 1
}
根据serverStatus()的结果,数据大小约为83552848(约80M),索引大小约为228331152(约220M)。
> db.serverStatus().mem
{
"bits" : 64,
"resident" : 47, ←実メモリは47M
"virtual" : 1482,
"supported" : true,
"mapped" : 544, ←マップされているのは544M
"mappedWithJournal" : 1088
}
“resident” : 47 となっているため47Mしかメモリを使っていないことになります。
つまりhogeコレクションデータもインデックスも全くメモリには乗っていません。
ただしマップはされています。
一旦能够编写查询语句,数据将逐渐存储到内存中。
起動直後はメモリには一切なく、クエリをかけて必要になったデータ・インデックスからメモリに乗っていきます。
因此,MongoDB在启动之初的响应速度会较慢。
这真的很令人困扰啊。
热身 (Rè
于是,现在是预热的时候。
如果进行预热,您可以将您喜欢的数据加载到内存中。
语法如下:
db.runCommand({ touch: "コレクション名", data: [true|false], index: [true|false] })
让我们在前面的例子中试着只将索引加载到内存中。
> db.serverStatus().mem
{
"bits" : 64,
"resident" : 48, ←起動直後は48M
"virtual" : 1482,
"supported" : true,
"mapped" : 544,
"mappedWithJournal" : 1088
}
> db.runCommand({ touch: "hoge", data: false, index: true }) ←インデックスだけメモリに乗せる
{
"indexes" : {
"num" : 4,
"numRanges" : 30,
"millis" : 48
},
"ok" : 1
}
> db.serverStatus().mem
{
"bits" : 64,
"resident" : 324, ←インデックスだけメモリ乗った
"virtual" : 1482,
"supported" : true,
"mapped" : 544,
"mappedWithJournal" : 1088
}
然后,“居民”这个词的数量增加了324个,加上索引(计算有点不对,但是。。。)