如何降低MongoDB的使用内存

在我们的系统中部署了很多套MongoDB的集群,但是有的时候会发现MongoDB启动不起来,或者启动之后一会儿MongoDB实例就挂了,也不知道是什么原因。我们按照如下方式进行了排查:

  1. 检查所在宿主OS中MongoDB的存储磁盘空间是否足够
  2. 检查所在宿主OS中的空闲内存是否足够
    使用命令free -h或者用命令top也可以
  3. 检查MongoDB的运行日志
  4. 通过top -p pid命令跟踪进程的内存占用 发现进程突然被kill掉。怀疑这时是因为进程的内存增长过快导致[2]

配置MongoDB的内存占用

在MongoDB的配置文件中配置允许缓存占用的最大内存值,这里的单位是GByte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
storage:
dbPath: <string>
journal:
enabled: <boolean>
commitIntervalMs: <num>
directoryPerDB: <boolean>
syncPeriodSecs: <int>
engine: <string>
wiredTiger:
engineConfig:
cacheSizeGB: <number>
journalCompressor: <string>
directoryForIndexes: <boolean>
maxCacheOverflowFileSizeGB: <number> // deprecated in MongoDB 4.4
collectionConfig:
blockCompressor: <string>
indexConfig:
prefixCompression: <boolean>
inMemory:
engineConfig:
inMemorySizeGB: <number>
oplogMinRetentionHours: <double>

对cacheSizeGB这个配置,官方的解释[3]如下:

Starting in MongoDB 3.4, the default WiredTiger internal cache size is the larger of either:

  • 50% of (RAM - 1 GB), or
  • 256 MB.
    For example, on a system with a total of 4GB of RAM the WiredTiger cache will use 1.5GB of RAM (0.5 * (4 GB - 1 GB) = 1.5 GB). Conversely, a system with a total of 1.25 GB of RAM will allocate 256 MB to the WiredTiger cache because that is more than half of the total RAM minus one gigabyte (0.5 * (1.25 GB - 1 GB) = 128 MB < 256 MB).
    The storage.wiredTiger.engineConfig.cacheSizeGB limits the size of the WiredTiger internal cache. The operating system will use the available free memory for filesystem cache, which allows the compressed MongoDB data files to stay in memory. In addition, the operating system will use any free RAM to buffer file system blocks and file system cache.

To accommodate the additional consumers of RAM, you may have to decrease WiredTiger internal cache size.

意思是什么呢? WiredTiger引擎缓存大小几乎没有上限。而在缓存占用内存快速上升的时候触发了OOM Killer,导致MongoDB实例进程直接被杀掉。所以要限制缓存的最大值。

在我们的系统中配置的值是4, 重新启动MongoDB服务之后,使用top命令观察如下:

自此,问题已经解决了。后来观察集群,也没有出现过进程被杀掉的情况。

关于systemd的一些补充

MongoDB的服务启停建议都通过systemd来管理。

一般来讲,systemd的service文件可以放在这些目录下面:

  • /usr/lib/systemd/system/
  • /lib/systemd/system
  • /run/systemd/system
  • /etc/systemd/system

systemd常见命令:

1
2
3
4
5
6
7
8
9
10
# 自启动
systemctl enable nginx.service
# 禁止自启动
systemctl disable nginx.service
# 启动服务
systemctl start nginx.service
# 停止服务
systemctl stop nginx.service
# 重启服务
systemctl restart nginx.service