以下是htop和show dbs命令的结果。
我知道mongodb使用内存映射IO,因此基本上OS可以处理缓存从理论上讲,当另一个进程请求可用内存时,mongodb应该释放其缓存的内存,但是从我们看到的事实来看,它不是。
OOM开始杀死其他重要流程,例如postgres,redis等。(可以看到,为解决此问题,我们将RAM增加到183GB,现在可以使用,但价格昂贵。mongo使用了约87GB的ram,几乎是其整个数据集大小的4倍)
那么,
这么多的内存使用量真的是正常的吗? (根据文档,WiredTiger最多将约60%的RAM用于其缓存,但考虑到数据集的大小,它是否甚至有足够的数据以占用86GB的RAM?)预期的是,如果另一个进程开始请求更多的内存,为什么mongo不会释放其分配的内存?在我们增加RAM并使系统完全不稳定之前,Linux oom不断将各种其他正在运行的进程(包括mongodb本身)杀死。
谢谢!
#1 楼
好的,在遵循了loicmathieu和jstell的提示并进行了一些细化之后,这些就是我使用WiredTiger存储引擎发现的有关MongoDB的内容。如果有人遇到相同的问题,我将其放在这里。我提到的内存使用线程全部属于2012-2014,所有线程都在WiredTiger之前,并且描述了原始MMAPV1存储的行为。引擎没有单独的缓存或不支持压缩。
WiredTiger缓存设置仅控制WiredTiger存储引擎直接使用的内存大小(而不是mongod使用的总内存)。在MongoDB / WiredTiger配置中,还有许多其他事情可能会占用内存,例如:默认情况下,不会在每次
提交时对数据进行同步,因此日志文件也位于RAM中,这将对内存造成损害。还提到了为了有效地使用I / O,
WiredTiger将I / O请求(缓存未命中)一起分块,这也似乎占用了一些RAM(实际上,脏页( br />更改/更新)并在
WiredTiger在其缓存中保留了多个版本的记录(Multi
版本并发控制,读取操作
WiredTiger将数据的校验和保存在缓存中。
MongoDB本身会消耗内存来处理打开的连接,聚合,服务器端代码等。
考虑到这些事实,依靠
show dbs;
在技术上是不正确的,因为它仅显示数据集的压缩大小。 。db.getSiblingDB('data_server').stats()
# OR
db.stats()
结果如下:
{
"db" : "data_server",
"collections" : 11,
"objects" : 266565289,
"avgObjSize" : 224.8413545621088,
"dataSize" : 59934900658, # 60GBs
"storageSize" : 22959984640,
"numExtents" : 0,
"indexes" : 41,
"indexSize" : 7757348864, # 7.7GBs
"ok" : 1
}
因此,看来实际的数据集大小及其索引占用了该内存的约68GB。 WiredTiger缓存的大小,因为它相当有效地处理了I / O操作(如上所述)。
仍然存在OOM问题,因为我们没有足够的资源来解决这个问题在mongodb中,我们降低了oom_score_adj以防止OOM暂时终止重要进程(意味着我们告诉OOM不要终止所需的进程)。
评论
我们有一个类似的问题。 MongoDB继续消耗RAM。相似的比例。 oom_score_adj解决方案是您想出的最好的解决方案吗?
– Hartator
18年9月28日在21:23
@Hartator好吧,我们减少了wiretiger的cacheSize,加大了对索引和索引策略的管理力度,最后,减少了我们关心的东西oom_score_adj,我想无论如何都可以完成。
– SpiXel
18/12/8在8:15
#2 楼
文档您可能想阅读MongoDB的基本内存问题,以及有关检查内存使用情况的简短讨论。
内存使用概述
命令
db.serverStatus()
(文档)可以概述内存使用情况,具体来说:> db.serverStatus().mem
{ "bits" : 64, "resident" : 27, "virtual" : 397, "supported" : true }
> db.serverStatus().tcmalloc
... not easy to read! ...
> db.serverStatus().tcmalloc.tcmalloc.formattedString
------------------------------------------------
MALLOC: 3416192 ( 3.3 MiB) Bytes in use by application
MALLOC: + 4788224 ( 4.6 MiB) Bytes in page heap freelist
MALLOC: + 366816 ( 0.3 MiB) Bytes in central cache freelist
...
... a bunch of stats in an easier to read format ...
您的索引有多大?所有索引的大小,但是我们也可以使用
db.stats()
获得单个集合的详细信息例如,此命令将比较每个集合的索引大小:
> db.getCollectionNames().map(name => ({totalIndexSize: db.getCollection(name).stats().totalIndexSize, name: name})).sort((a, b) => a.totalIndexSize - b.totalIndexSize).forEach(printjson)
...
{ "totalIndexSize" : 696320, "name" : "smallCollection" }
{ "totalIndexSize" : 135536640, "name" : "bigCollection" }
{ "totalIndexSize" : 382681088, "name" : "hugeCollection" }
{ "totalIndexSize" : 511901696, "name" : "massiveCollection" }
现在我们可以查看大量馆藏的详细信息,以查看其哪个索引最昂贵:可以让我们更好地了解在哪里可以节省资金。 。)
评论
索引是否会消耗大量内存?
– Mathias Lykkegaard Lorenzen
19 Mar 25 '19在13:33
@MathiasLykkegaardLorenzen取决于您索引的字段的唯一值的数量,相对于服务器的RAM。在我们的例子中,createTime索引是有问题的,因为它对于每个文档都是唯一的,并且该集合很大。索引其他字段是可以的,因为唯一值较少(这些值是聚类的)。
– joeytwiddle
19 Mar 26 '19在2:57
因此,是的,大索引对内存使用非常重要,因为(除了仅最近的集合之外),MongoDB尝试将整个索引保留在RAM(以及工作集)中。
– joeytwiddle
20年8月6日,下午5:31
#3 楼
我认为MongoDB在这里没有问题,因为jstell告诉您,带有WiredTiger的MongoDB将使用50%的可用内存,因此,如果您增加服务器的RAM,它将占用更多的内存。由于它的大小超过了DB +索引的大小,因此请记住,WiredTiger压缩磁盘上的数据库,并使用快照日志记录文档更改。因此,WiredTiger的实际大小是使用show dbs * compression_ration +快照日志的大小的大小。因此,几乎不可能知道确切的预期大小。还要记住,诸如
top
,ps
,htop
之类的工具并未显示应用程序真正使用的内存,有关详细信息,请参阅此SOW问题。 :https://stackoverflow.com/questions/131303/how-to-measure-actual-memory-usage-of-an-application-or-process 现在,回到您的问题。您在同一主机上运行其他工具,OOM会杀死它们。我对Linux OOM不熟悉,但是您确定它会因为MongoDB或..仅仅因为它们而杀死它们(也许是因为Postgres占用了过多内存而杀死了Postgres)。如果您的Mongo数据库很大,最好不要将其安装在与其他数据库共享的主机上,否则,如果遇到像您在此处描述的那样的问题,要弄清楚到底是谁造成的,就会遇到很多困难主机上的问题。
评论
也许关于WiredTiger内部的一些演示,例如mongodb.com/presentations/…,可能会有所启发。我希望物理RAM的默认使用率为50%,但这只是对专用MongoDB主机可能需要的内容的猜测,很多人都需要对其进行更改。 FWIW,我不认为将cacheSizeGB设置为“限制” mongo是可以的,因此您可以控制部署。确定缓存需要多少内存mongo,将需要您在预期的服务器负载下监视服务器缓存统计信息。