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个,加上索引(计算有点不对,但是。。。)

bannerAds