来自  http://www.ttlsa.com/mongodb/mongodb-and-memory/#

但凡初次接触MongoDB的人,无不惊讶于它对内存的贪得无厌,至于个中缘由,我先讲讲Linux是如何管理内存的,再说说MongoDB是如何使用内存的,答案自然就清楚了。
据说带着问题学习更有效,那就先看一个MongoDB服务器的top命令结果:

 
1
2
3
4
5
shell> top -p $(pidof mongod)
Mem: 32872124k total, 30065320k used, 2806804k free, 245020k buffers
Swap: 2097144k total, 100k used, 2097044k free, 26482048k cached
VIRT RES SHR %MEM
1892g 21g 21g 69.6

这台MongoDB服务器有没有性能问题?大家可以一边思考一边继续阅读。

先讲讲Linux是如何管理内存的
在Linux里(别的系统也差不多),内存有物理内存和虚拟内存之说,物理内存是什么自然无需解释,虚拟内存实际是物理内存的抽象,多数情况下,出于方便性的考虑,程序访问的都是虚拟内存地址,然后操作系统会通过Page Table机制把它翻译成物理内存地址,详细说明可以参考Understanding Memory和Understanding Virtual Memory,至于程序是如何使用虚拟内存的,可以参考Playing with Virtual Memory,这里就不多费口舌了。
很多人会把虚拟内存和Swap混为一谈,实际上Swap只是虚拟内存引申出的一种技术而已:操作系统一旦物理内存不足,为了腾出内存空间存放新内容,就会把当前物理内存中的内容放到交换分区里,稍后用到的时候再取回来,需要注意的是,Swap的使用可能会带来性能问题,偶尔为之无需紧张,糟糕的是物理内存和交换分区频繁的发生数据交换,这被称之为Swap颠簸,一旦发生这种情况,先要明确是什么原因造成的,如果是内存不足就好办了,加内存就可以解决,不过有的时候即使内存充足也可能会出现这种问题,比如MySQL就有可能出现这样的情况,一个可选的解决方法是限制使用Swap:

 
1
shell> sysctl vm.swappiness=0

查看内存情况最常用的是free命令:

 
1
2
3
4
5
shell> free -m
total used free shared buffers cached
Mem: 32101 29377 2723 0 239 25880
-/+ buffers/cache: 3258 28842
Swap: 2047 0 2047

新手看到used一栏数值偏大,free一栏数值偏小,往往会认为内存要用光了。其实并非如此,之所以这样是因为每当我们操作文件的时候,Linux都会尽可能的把文件缓存到内存里,这样下次访问的时候,就可以直接从内存中取结果,所以cached一栏的数值非常的大,不过不用担心,这部分内存是可回收的,操作系统的虚拟内存管理器会按照LRU算法淘汰冷数据。还有一个buffers,也是可回收的,不过它是保留给块设备使用的。

知道了原理,我们就可以推算出系统可用的内存是free + buffers + cached:

 
1
2
shell> echo $((2723 + 239 + 25880))
28842

至于系统实际使用的内存是used – buffers – cached:

 
1
2
shell> echo $((29377 - 239 - 25880))
3258

除了free命令,还可以使用sar命令:

 
1
2
3
4
5
6
shell> sar -r
kbmemfree kbmemused %memused kbbuffers kbcached
3224392 29647732 90.19 246116 26070160
shell> sar -W
pswpin/s pswpout/s
0.00 0.00

希望你没有被%memused吓到,如果不幸言中,重读本文。

再说说MongoDB是如何使用内存的
目前,MongoDB使用的是内存映射存储引擎,它会把数据文件映射到内存中,如果是读操作,内存中的数据起到缓存的作用,如果是写操作,内存还可以把随机的写操作转换成顺序的写操作,总之可以大幅度提升性能。MongoDB并不干涉内存管理工作,而是把这些工作留给操作系统的虚拟内存管理器去处理,这样做的好处是简化了MongoDB的工作,但坏处是你没有方法很方便的控制MongoDB占多大内存,幸运的是虚拟内存管理器的存在让我们多数时候并不需要关心这个问题。

MongoDB的内存使用机制让它在缓存重建方面更有优势,简而言之:如果重启进程,那么缓存依然有效,如果重启系统,那么可以通过拷贝数据文件到/dev/null的方式来重建缓存,更详细的描述请参考:Cache Reheating – Not to be Ignored。

有时候,即便MongoDB使用的是64位操作系统,也可能会遭遇OOM问题,出现这种情况,多半是因为限制了内存的大小所致,可以这样查看当前值:

 
1
shell> ulimit -a | grep memory

多数操作系统缺省都是把它设置成unlimited的,如果你的操作系统不是,可以这样修改:

 
1
2
shell> ulimit -m unlimited
shell> ulimit -v unlimited

注:ulimit的使用是有上下文的,最好放在MongoDB的启动脚本里。

有时候,MongoDB连接数过多的话,会拖累性能,可以通过serverStatus查询连接数:

 
1
mongo> db.serverStatus().connections

每个连接都是一个线程,需要一个Stack,Linux下缺省的Stack设置一般比较大:

 
1
2
shell> ulimit -a | grep stack
stack size (kbytes, -s) 10240

至于MongoDB实际使用的Stack大小,可以用如下命令确认(单位:K):

 
1
shell> cat /proc/$(pidof mongod)/limits | grep stack | awk -F 'size' '{print int($NF)/1024}'

如果Stack过大(比如:10240K)的话没有意义,简单对照命令结果中的Size和Rss:

 
1
shell> cat /proc/$(pidof mongod)/smaps | grep 10240 -A 10

所有连接消耗的内存加起来会相当惊人,推荐把Stack设置小一点,比如说1024:

 
1
shell> ulimit -s 1024

注:从MongoDB1.8.3开始,MongoDB会在启动时自动设置Stack。

有时候,出于某些原因,你可能想释放掉MongoDB占用的内存,不过前面说了,内存管理工作是由虚拟内存管理器控制的,幸好可以使用MongoDB内置的closeAllDatabases命令达到目的:

 
1
2
mongo> use admin
mongo> db.runCommand({closeAllDatabases:1})

另外,通过调整内核参数drop_caches也可以释放缓存:

 
1
shell> sysctl vm.drop_caches=1

平时可以通过mongo命令行来监控MongoDB的内存使用情况,如下所示:

 
1
2
3
4
5
6
mongo> db.serverStatus().mem:
{
"resident" : 22346,
"virtual" : 1938524,
"mapped" : 962283
}

还可以通过mongostat命令来监控MongoDB的内存使用情况,如下所示:

 
1
2
3
shell> mongostat
mapped vsize res faults
940g 1893g 21.9g 0

其中内存相关字段的含义是:

mapped:映射到内存的数据大小
visze:占用的虚拟内存大小
res:占用的物理内存大小
注:如果操作不能在内存中完成,结果faults列的数值不会是0,视大小可能有性能问题。

在上面的结果中,vsize是mapped的两倍,而mapped等于数据文件的大小,所以说vsize是数据文件的两倍,之所以会这样,是因为本例中,MongoDB开启了journal,需要在内存里多映射一次数据文件,如果关闭journal,则vsize和mapped大致相当。

如果想验证这一点,可以在开启或关闭journal后,通过pmap命令来观察文件映射情况:

 
1
shell> pmap $(pidof mongod)

到底MongoDB配备多大内存合适?宽泛点来说,多多益善,如果要确切点来说,这实际取决于你的数据及索引的大小,内存如果能够装下全部数据加索引是最佳情况,不过很多时候,数据都会比内存大,比如本文所涉及的MongoDB实例:

 
1
2
3
4
5
mongo> db.stats()
{
"dataSize" : 1004862191980,
"indexSize" : 1335929664
}

本例中索引只有1G多,内存完全能装下,而数据文件则达到了1T,估计很难找到这么大内存,此时保证内存能装下热数据即可,至于热数据是多少,取决于具体的应用,你也可以通过观察faults的大小来判断当前内存是否能够装下热数据,如果faults持续变大,就说明当前内存已经不能满足热数据的大小了。如此一来内存大小就明确了:内存 > 索引 + 热数据,最好有点富余,毕竟操作系统本身正常运转也需要消耗一部分内存。

关于MongoDB与内存的话题,大家还可以参考官方文档中的相关介绍。

MongoDB与内存的更多相关文章

  1. 如何限制mongodb数据库内存占用量方法

    多实例下: 可以通过绑定cpu,来防止多实例相互干扰. mongodb的内存也可以限制主,防止全部内存都被一个实例占据. ulimit -s 4096 && ulimit -m 314 ...

  2. 使用cgroups限制MongoDB的内存使用

    cgroups,其名称源自控制组群(control groups)的简写,是Linux内核的一个功能,用来限制,控制与分离一个进程组群的资源(如CPU.内存.磁盘输入输出等). 这个项目最早是由Goo ...

  3. mongodb 对内存的占用监控 ——mongostat,linux系统可用的内存是free + buffers + cached

    刚开始使用mongodb的时候,不太注意mongodb的内存使用,但通过查资料发现mongodb对内存的占用是巨大的,在本地测试服务器中,8G的内存居然被占用了45%.汗呀. 本文就来剖析一下mong ...

  4. mongodb WiredTiger 内存分配

    转载自勤奋的小青蛙 mongodb占用内存非常高,这是因为官方为了提升存储的效率,设计就这么设计的. 但是大部分的个人开发者所购买的服务器内存并没有那么大,所以,我们需要配置下MongoDB的内存缓存 ...

  5. MongoDB 的内存使用限制

    本文将简述一下MongoDB的内存限制问题 1. 使用Docker限制 当我们使用docker创建mongo 容器时,可通过使用以下参数,对mongo可以使用的资源进行限制 内存限制 参数 简介 -m ...

  6. mongodb聚合内存不足解决方案

    原因:mongodb每一个文档默认只有16M.聚合的结果是一个BSON文档,当超过16M大小时,就会报内存不够错误. exceeded memory limit for $group.but didn ...

  7. mongodb 超出内存限制

    mongodb 查询数据默认占用最大内存为100M,如果查询涉及到大量数据进行$group.$sort时会抛出类似以下的异常: Received error :: { $err: \"Exc ...

  8. Windows下使用WSRM限制MongoDB内存

    有个项目用到了MongoDB,我们是在WINDOWS 2008 64位环境下部署的,为啥不部署到linux下面呢,我们没那么多服务器,只能将就一下了. 大家都知道Mongodb吃内存太厉害了,如果不重 ...

  9. MongoDB内存管理机制

    目前,MongoDB使用的是内存映射存储引擎,它会把磁盘IO操作转换成内存操作,如果是读操作,内存中的数据起到缓存的作用,如果是写操作,内存还可以把随机的写操作转换成顺序的写操作,总之可以大幅度提升性 ...

随机推荐

  1. discuz!安装遇到问题的解决方案

    正常的安装步骤好多地方都有写过了,我安装的时候遇到问题百度翻了个遍也没有找到,现在问题已经解决了,发出了分享一下! 进入第三步创建数据库的时候提示:由于目标计算机积极拒绝,无法连接. 打开phpmya ...

  2. oracle pl/sql split函数

    在软件开发过程中程序员经常会遇到字符串的拼接和拆分工作. 以java开发为例: 前台传入字符串拼接形式的一个JSON数据,如:"1001,1002,1003",这可能代表了一组序号 ...

  3. 蚁群算法求解旅行商问题(附c和matlab源代码)

    前几天写了个模拟退火算法的程序,然后又陆陆续续看了很多群智能算法,发现很多旅行商问题都采用蚁群算法来求解,于是开始写蚁群算法的模板.网上关于蚁群算法的理论很多就不再这里赘述了,下面直接上代码和进行简单 ...

  4. YisouSpider你想搞死我的服务器吗?

    在1分钟666次请求中,你占了445次,你大爷的想干啥呢? 42.156.254.30 - - [03/Feb/2016:11:46:00 +0800] "GET /thread-22063 ...

  5. netty学习

    1.不选择java原生nio的原因   (1)nio的类库和api繁杂   (2)需要具备其他的额外的技能做铺垫,例如熟悉java多线程编程.   (3)可靠性能力补齐的工作量和难度都非常大,例如客户 ...

  6. css中图片等比例缩放

    li img{ display: inline-block; max-height: 60px; max-width: 60px; vertical-align: middle; }

  7. windows下nginx的启动关闭

    Windows下Nginx的启动.停止等命令 在Windows下使用Nginx,我们需要掌握一些基本的操作命令,比如:启动.停止Nginx服务,重新载入Nginx等,下面我就进行一些简单的介绍. .启 ...

  8. 深入理解HTTP协议

  9. <form>属性

    当form表单中action没有值时,默认当前页方法.

  10. ORACLE导入、导出命令使用方法

    oracle导入.导出命令使用方法: 给用户增加导入数据权限的操作 第一,启动sql*puls 第二,以system/manager登陆 第三,create user 用户名 IDENTIFIED B ...