mongodb内存占用过高怎么办
告警
公司有个3.2.7版本的mongo复制集,最近几天频繁告警内存过高。
服务器配置16C+64G内存。mongo备节点内存使用到55G,触发告警。
以下内容基于3.2.7版本,3.2.7版本已经太老,很多后来的命令和配置,3.2.7都没有。
排查
排查mongo配置
主要是检查cacheSizeGB
MongoDB 3.2 及以后,默认使用 WiredTiger 存储引擎,可通过 cacheSizeGB
选项配置 WiredTiger 引擎使用内存的上限,一般建议配置在系统可用内存的一班左右。
默认值是(RAM – 1GB) / 2。出发点是防止系统OOM kill。因为这里的配置只是wiredTiger的内存cache限额,并不是mongo的全部使用内存限额,整个mongo进程的内存占用要比这个值大,所以cacheSizeGB万万不可设置超过RAM的60%。
我们这里配置到了20G。但是实际运行中发现,在并发查询很高的情况下,wt的cacheSize还是会超过这个配置一点点。
查看mongo实例的内存使用情况
返回结果中 bytes currently in the cache 后的值为缓存数据的大小
已经用满了,这种情况可以加一下内存了。但是内存太贵,业务也没有那么高的性能要求,保障不宕机是更有性价比的方案。
既然cache只用了20G,
看看tcmalloc的情况
可以看到page heap freelist占了大头。
解释一下,57338605728 (54682.4 MiB) Virtual address space used 是mongo总的使用的虚拟内存。
48675164320 (46420.3 MiB) Actual memory used (physical + swap)是mongo总的使用的实际内存。(我没有开swap)
实际内存又分成两部分,freelist中的和非freelist的。freelist的就是已经分配后来又用完释放的内存,存在这个freelist数据结构中,已备后面重用这些内存,我的理解就是我用完了,但是我先拿着。这样后面的业务来了,mongo就不需要再向os申请分配内存这一步了,从性能和效率的维度来看更好。
但是缺点是内存一直没有还给os,导致os角度来看,内存的使用率很高。
tcmalloc 为性能考虑,每个线程会有自己的 local free page cache,还有 central free page cache;内存申请时,按 local thread free page cache ==> central free page cache 查找可用内存,找不到可用内存时才会从堆上申请;当释放内存时,也会归还到 cache 里,tcmalloc 后台慢慢再归还给 OS操作系统, 多数情况下,内存使用率高的原因是 tcmalloc 未能及时将内存归还给操作系统,导致内存最大可能达到几十GB。mongo为了提高性能,倾向于利用os上尽可能多的内存。
解决
所以可以将freelist的内存及时释放给os,可以解决内存水位过高的问题。
tcmallocAggressiveMemoryDecommit
是一个服务器参数,用于控制 TCMalloc 内存分配器在什么程度上积极地将不再使用的内存释放回操作系统。当设置为 1
(开启状态)时,tcmallocAggressiveMemoryDecommit
会使 TCMalloc 更积极地释放不再使用的内存。这意味着当应用程序释放内存后,TCMalloc 会尝试将这部分内存标记为空闲并返回给操作系统,而不是保留在进程的地址空间中以便快速重用。