MongoDB 如何使用内存?为什么内存满了?

最近接到多个MongoDB内存方面的线上case及社区问题咨询,主要集中在:

  • 为什么我的 MongoDB 使用了 XX GB 内存?
  • 一个机器上部署多个 Mongod 实例/进程,WiredTiger cache 应该如何配置?
  • MongoDB 是否应该使用 SWAP 空间来降低内存压力?

MongoDB 内存用在哪?

Mongod 进程启动后,除了跟普通进程一样,加载 binary、依赖的各种library 到内存,其作为一个DBMS,还需要负责客户端连接管理,请求处理,数据库元数据、存储引擎等很多工作,这些工作都涉及内存的分配与释放,默认情况下,MongoDB 使用 Google tcmalloc 作为内存分配器,内存占用的大头主要是「存储引擎」与 「客户端连接及请求的处理」。

存储引擎 Cache

MongoDB 3.2 及以后,默认使用 WiredTiger 存储引擎,可通过 cacheSizeGB 选项配置 WiredTiger 引擎使用内存的上限,一般建议配置在系统可用内存的60%左右(默认配置)。

举个例子,如果 cacheSizeGB 配置为 10GB,可以认为 WiredTiger 引擎通过tcmalloc分配的内存总量不会超过10GB。为了控制内存的使用,WiredTiger 在内存使用接近一定阈值就会开始做淘汰,避免内存使用满了阻塞用户请求。

目前有4个可配置的参数来支持 wiredtiger 存储引擎的 eviction 策略(一般不需要修改),其含义是:

参数默认值含义
eviction_target80当 cache used 超过 eviction_target,后台evict线程开始淘汰 CLEAN PAGE
eviction_trigger95当 cache used 超过 eviction_trigger,用户线程也开始淘汰 CLEAN PAGE
eviction_dirty_target5当 cache dirty 超过 eviction_dirty_target,后台evict线程开始淘汰 DIRTY PAGE
eviction_dirty_trigger20当 cache dirty 超过 eviction_dirty_trigger, 用户线程也开始淘汰 DIRTY PAGE

在这个规则下,一个正常运行的 MongoDB 实例,cache used 一般会在 0.8 * cacheSizeGB 及以下,偶尔超出问题不大;如果出现 used>=95% 或者 dirty>=20%,并一直持续,说明内存淘汰压力很大,用户的请求线程会阻塞参与page淘汰,请求延时就会增加,这时可以考虑「扩大内存」或者 「换更快的磁盘提升IO能力」。

TCP 连接及请求处理

MongoDB Driver 会跟 mongod 进程建立 tcp 连接,并在连接上发送数据库请求,接受应答,tcp 协议栈除了为连接维护socket元数据为,每个连接会有一个read buffer及write buffer,用户收发网络包,buffer的大小通过如下sysctl系统参数配置,分别是buffer的最小值、默认值以及最大值,详细解读可以google。

net.ipv4.tcp_wmem = 8192  65536  16777216
net.ipv4.tcp_rmem = 8192  87380  16777216

redhat7(redhat6上并没有导出这么详细的信息) 上通过 ss -m 可以查看每个连接的buffer的信息,如下是一个示例,读写 buffer 分别占了 2357478bytes、2626560bytes,即均在2MB左右;500个类似的连接就会占用掉 1GB 的内存;buffer 占到多大,取决于连接上发送/应答的数据包的大小、网络质量等,如果请求应答包都很小,这个buffer也不会涨到很大;如果包比较大,这个buffer就更容易涨的很大。

tcp    ESTAB      0      0                       127.0.0.1:51601                                 127.0.0.1:personal-agentskmem:(r0,rb2357478,t0,tb2626560,f0,w0,o0,bl0)

除了协议栈上的内存开销,针对每个连接,Mongod 会起一个单独的线程,专门负责处理这条连接上的请求,mongod 为处理连接请求的线程配置了最大1MB的线程栈,通常实际使用在几十KB左右,通过 proc 文件系统看到这些线程栈的实际开销。 除了处理请求的线程,mongod 还有一系列的后台线程,比如主备同步、定期刷新 Journal、TTL、evict 等线程,默认每个线程最大ulimit -s(一般10MB)的线程栈,由于这批线程数量比较固定,占的内存也比较可控。

# cat /proc/$pid/smaps7f563a6b2000-7f563b0b2000 rw-p 00000000 00:00 0
Size:              10240 kB
Rss:                  12 kB
Pss:                  12 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:        12 kB
Referenced:           12 kB
Anonymous:            12 kB
AnonHugePages:         0 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB

线程在处理请求时,需要分配临时buffer存储接受到的数据包,为请求建立上下文(OperationContext),存储中间的处理结果(如排序、aggration等)以及最终的应答结果等。

当有大量请求并发时,可能会观察到 mongod 使用内存上涨,等请求降下来后又慢慢释放的行为,这个主要是 tcmalloc 内存管理策略导致的,tcmalloc 为性能考虑,每个线程会有自己的 local free page cache,还有 central free page cache;内存申请时,按 local thread free page cache ==> central free page cache 查找可用内存,找不到可用内存时才会从堆上申请;当释放内存时,也会归还到 cache 里,tcmalloc 后台慢慢再归还给 OS, 默认情况下,tcmalloc 最多会 cache min(1GB,1/8 * system_memory) 的内存, 通过 setParameter.tcmallocMaxTotalThreadCacheBytesParameter 参数可以配置这个值,不过一般不建议修改,尽量在访问层面做调优)

tcmalloc cache的管理策略,MongoDB 层暴露了几个参数来调整,一般不需要调整,如果能清楚的理解tcmalloc原理及参数含义,可做针对性的调优;MongoDB tcmalloc 的内存状态可以通过 db.serverStatus().tcmalloc 查看,具体含义可以看 tcmalloc 的文档。重点可以关注下 total_free_bytes,这个值告诉你有多少内存是 tcmalloc 自己缓存着,没有归还给 OS 的。

mymongo:PRIMARY> db.serverStatus().tcmalloc
{"generic" : {"current_allocated_bytes" : NumberLong("2545084352"),"heap_size" : NumberLong("2687029248")},"tcmalloc" : {"pageheap_free_bytes" : 34529280,"pageheap_unmapped_bytes" : 21135360,"max_total_thread_cache_bytes" : NumberLong(1073741824),"current_total_thread_cache_bytes" : 1057800,"total_free_bytes" : 86280256,"central_cache_free_bytes" : 84363448,"transfer_cache_free_bytes" : 859008,"thread_cache_free_bytes" : 1057800,"aggressive_memory_decommit" : 0,...}
}

如何控制内存使用?

合理配置 WiredTiger cacheSizeGB

  • 如果一个机器上只部署 Mongod,mongod 可以使用所有可用内存,则是用默认配置即可。
  • 如果机器上多个mongod混部,或者mongod跟其他的一些进程一起部署,则需要根据分给mongod的内存配额来配置 cacheSizeGB,按配额的60%左右配置即可。

控制并发连接数

TCP连接对 mongod 的内存开销上面已经详细分析了,很多同学对并发有一定误解,认为「并发连接数越高,数据库的QPS就越高」,实际上在大部分数据库的网络模型里,连接数过高都会使得后端内存压力变大、上下文切换开销变大,从而导致性能下降。

MongoDB driver 在连接 mongod 时,会维护一个连接池(通常默认100),当有大量的客户端同时访问同一个mongod时,就需要考虑减小每个客户端连接池的大小。mongod 可以通过配置 net.maxIncomingConnections 配置项来限制最大的并发连接数量,防止数据库压力过载。

是否应该配置 SWAP

官方文档上的建议如下,意思是配置一下swap,避免mongod因为内存使用太多而OOM。

For the WiredTiger storage engine, given sufficient memory pressure, WiredTiger may store data in swap space.Assign swap space for your systems. Allocating swap space can avoid issues with memory contention and can prevent the OOM Killer on Linux systems from killing mongod. 

开启 SWAP 与否各有优劣,SWAP开启,在内存压力大的时候,会利用SWAP磁盘空间来缓解内存压力,此时整个数据库服务会变慢,但具体变慢到什么程度是不可控的。不开启SWAP,当整体内存超过机器内存上线时就会触发OOM killer把进程干掉,实际上是在告诉你,可能需要扩展一下内存资源或是优化对数据库的访问了。

是否开启SWAP,实际上是在「好死」与「赖活着」的选择,个人觉得,对于一些重要的业务场景来说,首先应该为数据库规划足够的内存,当内存不足时,「及时调整扩容」比「不可控的慢」更好。

其他

  • 尽量减少内存排序的场景,内存排序一般需要更多的临时内存
  • 主备节点配置差距不要过大,备节点会维护一个buffer(默认最大256MB)用于存储拉取到oplog,后台从buffer里取oplog不断重放,当备同步慢的时候,这个buffer会持续使用最大内存。
  • 控制集合及索引的数量,减少databse管理元数据的内存开销;集合、索引太多,元数据内存开销是一方面的影响,更多的会影响启动加载的效率、以及运行时的性能。

 

原文链接
本文为云栖社区原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/520020.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为什么要学Python 编程?(附Python学习路线)

为何程序员多数会选择 Python 作为入门级语言?在此,估计不少开发者都会予以反驳,自己明明就没有选择 Python,不能一概而论。下面,我们就用数据一窥如今最流行的编程语言。今年的 3 月份,国外招聘网站 Hacke…

“资源添加到Web应用程序[]的缓存中,因为在清除过期缓存条目后可用空间仍不足 - 请考虑增加缓存的最大空间”

解决办法&#xff1a; 在 /conf/context.xml 的 前添加以下内容&#xff1a; <Resources cachingAllowed"true" cacheMaxSize"100000" />

报告!这群阿里工程师在偷偷养猪

今天下午&#xff0c;期盼已久的阿里巴巴技术脱贫大会就要开始了。 很多人都知道&#xff0c;我们在1年前就投入100亿元人民币成立阿里巴巴脱贫基金。从教育到健康&#xff0c;再到女性、生态和电商扶贫&#xff0c;这五个方向分别由五位阿里合伙人直接牵头。 很多人不知道的…

七大新品集中亮相,腾讯云AI大数据全线升级!

近日腾讯云在北京举行大数据AI新品发布会。会上&#xff0c;腾讯云带来了在大数据与AI领域的最新研究成果&#xff0c;包括AI换脸甄别技术AntiFakes、腾讯星图以及企业画像平台等七大重磅新品&#xff0c;并对AI、大数据产品进行全线升级&#xff0c;致力于为用户带来更精细化的…

解决CentOS7本机时间与实际时间相差8小时的问题

查看当前日期时间&#xff1a; timedatectl删除原来的时间日期配置 rm -rf /etc/localtime链接指向新的时间日期配置 ln -sv /usr/share/zoneinfo/Universal /etc/localtime设置完成后查看当前时间日期&#xff1a; 如果不生效请重启 reboot

linux两个卷组可以合并,Linux系统中所有的逻辑卷必须属于同一个卷组()。

_债券收益率曲线的情况分别是( )商业银行进行流动性管理的方法有( )。眼见即脑见。MOST总线可以有睡眠模式直接切换到通电工作模式。在使用递归算法解决问题时&#xff0c;应满足以下两点&#xff1a;一是该问题能够被递归形式描述&#xff1b;二是【 】。()提问需要在理解篇章…

阿里开发者们的第15个感悟:做一款优秀大数据引擎,要找准重点解决的业务场景

2015年12月20日&#xff0c;云栖社区上线。2018年12月20日&#xff0c;云栖社区3岁。 阿里巴巴常说“晴天修屋顶”。 在我们看来&#xff0c;寒冬中&#xff0c;最值得投资的是学习&#xff0c;是增厚的知识储备。 所以社区特别制作了这个专辑——分享给开发者们20个弥足珍贵的…

解决vsftpd 读取目录列表失败的问题

文章目录1. 问题现象2. 解决方案(重启时效)3. 重启失效解决1. 问题现象 使用第三方FTP软件filezilla进行登陆&#xff0c;出现如下错误&#xff1a; 状态: 正在连接 192.168.1.6:21... 状态: 连接建立&#xff0c;等待欢迎消息... 响应: 220 (vsFTPd 2.2.2) 命令: …

阿里开发者们的第16个感悟:让阅读源码成为习惯

2015年12月20日&#xff0c;云栖社区上线。2018年12月20日&#xff0c;云栖社区3岁。 阿里巴巴常说“晴天修屋顶”。 在我们看来&#xff0c;寒冬中&#xff0c;最值得投资的是学习&#xff0c;是增厚的知识储备。 所以社区特别制作了这个专辑——分享给开发者们20个弥足珍贵的…

腾讯云全面更新数据智能服务全景图!

近日在腾讯云AI大数据新品发布会上&#xff0c;腾讯云副总裁王龙向听众全面介绍了当前腾讯云数据智能服务的全景布局。针对目前整体AI行业的发展趋势&#xff0c;他表示过去一招鲜的发展模式已经难以为继&#xff0c;取而代之的是真正能够产生价值的、端到端的、全面的AI解决方…

linux简介ubuntu,Linux文件系统简介(基于Ubuntu)

1. 查看Linux文件系统(1)使用ls命令可以查看Ubuntu系统的的典型布局。命令&#xff1a;$ ls / 显示&#xff1a;(2)要想看到更详细的目录层次结构&#xff0c;则应安装和使用tree命令来显示根目录或基本目录的布局&#xff0c;以及与之相关联的子目录。命令&#xff1a;$ tree…

揭秘人工智能(系列):人工智能带来的网络安全威胁

历史表明&#xff0c;网络安全威胁随着新的技术进步而增加。关系数据库带来了SQL注入攻击&#xff0c;Web脚本编程语言助长了跨站点脚本攻击&#xff0c;物联网设备开辟了创建僵尸网络的新方法。而互联网打开了潘多拉盒子的数字安全弊病&#xff0c;社交媒体创造了通过微目标内…

查看脚本执行时间

#!/bin/bash starttimedate %Y-%m-%d %H:%M:%S #执行程序 #/usr/bin/unoconv -f pdf CHANGELOG.md #/usr/bin/soffice --headless --invisible --convert-to pdf /app/9.67m.doc endtimedate %Y-%m-%d %H:%M:%S start_seconds$(date --date"$starttime" %s); end_sec…

支付宝工程师创造出了一个可以“拷贝”支付宝的神器

mPaaS是源于支付宝的移动开发平台&#xff0c;从最初的金融级移动开发平台&#xff0c;逐渐演进成集开发、测试、发布、分析、运营于一体的 App 全生命周期管理平台&#xff0c;服务了广发银行、12306、上海地铁等标杆级客户&#xff0c;帮助客户完成技术升级与业务增长。 “拷…

java.net.BindException: Address already in use: connect

https://blog.csdn.net/qq_39240270/article/details/93633821

c语言行列坐标是先行后j,C语言学习之行列操作

C语言学习之队列操作本文件为队列操作的接口&#xff1a;/*queue.h*/#ifndef _SEQQUEUE_H_#define _SEQQUEUE_H_#define QUEUE_MAX 15typedef struct{int number; //顾客编号long time;//进入时间}DATATYPE_T;typedef struct{DATATYPE_T data[QUEUE_MAX]; //队列数组int head; …

Kubernetes API 与 Operator,不为人知的开发者战争

如果我问你&#xff0c;如何把一个 etcd 集群部署在 Google Cloud 或者阿里云上&#xff0c;你一定会不假思索的给出答案&#xff1a;当然是用 etcd Operator&#xff01; 实际上&#xff0c;几乎在一夜之间&#xff0c;Kubernetes Operator 这个新生事物&#xff0c;就成了开…

面试编程岗,期望40K,为什么老板给我翻倍?

临近年底&#xff0c;互联网正在经历优化升级&#xff0c;不少公司出现了裁员新闻&#xff0c;也有很多人纷纷转型、跳槽。那么 IT领域内&#xff0c;什么样的工作比较好&#xff1f;最近笔者看笔者在网上看到一个被裁员的帖子&#xff0c;但仍被震撼到了&#xff0c;也许答案不…

最小化 Java 镜像的常用技巧

背景 随着容器技术的普及&#xff0c;越来越多的应用被容器化。人们使用容器的频率越来越高&#xff0c;但常常忽略一个基本但又非常重要的问题 - 容器镜像的体积。本文将介绍精简容器镜像的必要性并以基于 spring boot 的 java 应用为例描述最小化容器镜像的常用技巧。 精简…

linux上传下载文件命令rz、sz

要使用rz、sz命令传输文件需要给服务器安装lrzsz: yum -y install lrzsz命令sz、rz的使用方法 rz中的r意为received(接收)&#xff0c;输入rz时&#xff0c;意为服务器接收文件&#xff0c;即将文件从本地上传到服务器。 sz中的s意为send(发送)&#xff0c;输入sz时&#xff…