一、MongoDB内存管理概述
1.1 MongoDB内存模型
MongoDB使用WiredTiger存储引擎(默认),其内存管理主要涉及三个层面:
– WiredTiger缓存:用于缓存数据和索引页,默认占系统内存的50%
– 操作系统文件缓存:操作系统层面的文件缓存
– 进程内存:连接池、排序缓冲区、聚合管道等
1.2 内存使用分析
# 查看MongoDB内存使用
mongosh --eval "db.serverStatus().mem"
# 查看WiredTiger缓存详情
mongosh --eval "db.serverStatus().wiredTiger.cache"
# 查看系统内存
free -h
cat /proc/meminfo | head -10
二、WiredTiger缓存配置
2.1 默认缓存策略
WiredTiger默认缓存大小:
– 64GB以上内存:默认50%物理内存减去1GB
– 64GB以下内存:默认50%物理内存
2.2 手动配置缓存大小
编辑 /etc/mongod.conf:
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 8 # 设置为8GB(建议系统内存的50%-60%)
配置建议:
| 系统内存 | 建议缓存大小 | 留给系统 |
|———|————|———|
| 4GB | 1.5GB | 2.5GB |
| 8GB | 4GB | 4GB |
| 16GB | 8GB | 8GB |
| 32GB | 16GB | 16GB |
| 64GB | 30GB | 34GB |
| 128GB | 60GB | 68GB |
2.3 缓存驱逐策略
WiredTiger采用LRU(最近最少使用)算法管理缓存页面:
// 查看缓存驱逐统计
db.serverStatus().wiredTiger.cache
// 关键指标
{
"cache bytes currently in the cache": 4294967296, // 当前缓存使用量
"cache eviction": {
"evicted pages": 123456, // 已驱逐页面数
"eviction server evicting pages": 789, // 驱逐线程活跃数
"modified pages evicted": 456 // 已驱逐的脏页数
},
"cache pages held in cache": 98765, // 缓存中的页面数
"cache bytes dirty in the cache": 536870912 // 脏数据量
}
2.4 调整驱逐参数
# 在mongod.conf中配置(需谨慎)
storage:
wiredTiger:
engineConfig:
eviction_dirty_trigger: 5 # 脏页占比达5%时触发驱逐(默认5%)
eviction_dirty_target: 2.5 # 驱逐目标脏页占比(默认2.5%)
eviction_trigger: 95 # 缓存使用达95%时触发驱逐
eviction_target: 80 # 驱逐目标缓存使用率
三、操作系统层面优化
3.1 透明大页(THP)禁用
MongoDB建议禁用透明大页,避免内存分配延迟:
# 临时禁用
sudo echo never > /sys/kernel/mm/transparent_hugepage/enabled
sudo echo never > /sys/kernel/mm/transparent_hugepage/defrag
# 永久禁用(创建systemd服务)
sudo nano /etc/systemd/system/disable-thp.service
服务配置:
[Unit]
Description=Disable Transparent Huge Pages
Before=mongod.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled'
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/defrag'
[Install]
WantedBy=multi-user.target
启用服务:
sudo systemctl daemon-reload
sudo systemctl enable disable-thp
sudo systemctl start disable-thp
3.2 虚拟内存参数调优
# 调整swappiness(减少交换分区使用)
sudo sysctl -w vm.swappiness=1
# 调整脏页比例
sudo sysctl -w vm.dirty_ratio=15
sudo sysctl -w vm.dirty_background_ratio=5
# 调整最大文件句柄数
sudo sysctl -w fs.file-max=65536
# 永久生效
sudo nano /etc/sysctl.d/99-mongodb.conf
/etc/sysctl.d/99-mongodb.conf 内容:
vm.swappiness=1
vm.dirty_ratio=15
vm.dirty_background_ratio=5
fs.file-max=65536
vm.max_map_count=262144
net.core.somaxconn=65535
生效:
sudo sysctl -p /etc/sysctl.d/99-mongodb.conf
3.3 NUMA架构优化
在NUMA架构服务器上,需要调整NUMA策略:
# 检查是否为NUMA架构
numactl --hardware
# 使用numactl启动MongoDB
sudo numactl --interleave=all /usr/bin/mongod --config /etc/mongod.conf
# 或在systemd服务中配置
sudo nano /etc/systemd/system/mongod.service
修改服务文件:
[Service]
ExecStart=/usr/bin/numactl --interleave=all /usr/bin/mongod --config /etc/mongod.conf
3.4 资源限制配置
# 查看当前限制
ulimit -a
# 调整限制
sudo nano /etc/security/limits.d/mongodb.conf
/etc/security/limits.d/mongodb.conf 内容:
mongodb soft nofile 65536
mongodb hard nofile 65536
mongodb soft nproc 65536
mongodb hard nproc 65536
mongodb soft memlock unlimited
mongodb hard memlock unlimited
四、连接内存优化
4.1 连接池管理
每个MongoDB连接约消耗1MB内存,大量连接会占用大量内存:
// 查看当前连接数
db.serverStatus().connections
// 查看每个连接的内存使用
db.currentOp().inprog.forEach(function(op) {
if (op.opid) print(op.opid + " - " + op.client);
})
限制最大连接数:
# 在mongod.conf中配置
net:
maxIncomingConnections: 500 # 默认65536,建议根据内存调整
4.2 连接池配置(应用端)
// Node.js mongoose连接池配置
mongoose.connect(uri, {
maxPoolSize: 10, // 最大连接数
minPoolSize: 2, // 最小连接数
maxIdleTimeMS: 30000, // 空闲超时
waitQueueTimeoutMS: 5000 // 等待超时
});
五、查询内存优化
5.1 排序内存优化
MongoDB排序操作在内存中进行,超过32MB会报错:
// 查看排序内存使用
db.orders.find().sort({ created_at: -1 }).explain("executionStats")
// 解决方案1:创建索引避免内存排序
db.orders.createIndex({ created_at: -1 })
// 解决方案2:增大排序内存限制
db.adminCommand({ setParameter: 1, internalQueryExecMaxBlockingSortBytes: 67108864 }) // 64MB
5.2 聚合管道内存优化
// 使用allowDiskUse启用磁盘临时文件
db.orders.aggregate([
{ $match: { status: "active" } },
{ $group: { _id: "$user_id", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } }
], { allowDiskUse: true })
// 优化:$match前置减少数据量
db.orders.aggregate([
{ $match: { status: "active", created_at: { $gt: ISODate("2026-01-01") } } },
{ $group: { _id: "$user_id", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } },
{ $limit: 100 }
], { allowDiskUse: true })
5.3 批量操作内存优化
// 分批处理大数据量
const batchSize = 1000;
let skip = 0;
let hasMore = true;
while (hasMore) {
const docs = db.users.find({}).skip(skip).limit(batchSize).toArray();
if (docs.length === 0) {
hasMore = false;
break;
}
// 处理每批数据
docs.forEach(doc => {
// 业务处理
});
skip += batchSize;
}
六、监控与告警
6.1 内存监控脚本
#!/bin/bash
# /usr/local/bin/mongo-mem-monitor.sh
THRESHOLD=90 # 内存使用率告警阈值
HOSTNAME=$(hostname)
# MongoDB内存使用
MONGO_MEM=$(mongosh --quiet --eval "
var mem = db.serverStatus().mem;
print(Math.round(mem.resident / mem.virtual * 100));
")
# 系统内存使用
SYS_MEM=$(free | grep Mem | awk '{printf "%.0f", $3/$2 * 100}')
echo "MongoDB内存使用: ${MONGO_MEM}%"
echo "系统内存使用: ${SYS_MEM}%"
if [ "$SYS_MEM" -gt "$THRESHOLD" ]; then
echo "告警: ${HOSTNAME} 系统内存使用率 ${SYS_MEM}% 超过阈值 ${THRESHOLD}%"
fi
6.2 WiredTiger缓存监控
// 缓存命中率监控脚本
var cacheStats = db.serverStatus().wiredTiger.cache;
var cacheUsed = cacheStats["cache bytes currently in the cache"];
var cacheMax = cacheStats["maximum bytes configured"];
var dirtyPages = cacheStats["cache bytes dirty in the cache"];
var evictionPages = cacheStats["eviction pages evicted"];
var readPages = cacheStats["pages read into cache"];
var usagePercent = (cacheUsed / cacheMax * 100).toFixed(2);
var dirtyPercent = (dirtyPages / cacheMax * 100).toFixed(2);
print("缓存使用率: " + usagePercent + "%");
print("脏页占比: " + dirtyPercent + "%");
print("缓存命中率: " + ((1 - readPages / (readPages + evictionPages)) * 100).toFixed(2) + "%");
6.3 Prometheus告警规则
groups:
- name: mongodb_memory
rules:
- alert: MongoDBHighMemoryUsage
expr: mongodb_wiredtiger_cache_usage_percent > 90
for: 5m
labels:
severity: warning
annotations:
summary: "MongoDB缓存使用率过高 (>90%)"
- alert: MongoDBHighDirtyPage
expr: mongodb_wiredtiger_cache_dirty_percent > 10
for: 5m
labels:
severity: warning
annotations:
summary: "MongoDB脏页比例过高 (>10%)"
七、OOM问题排查与解决
7.1 OOM排查
# 检查OOM日志
sudo dmesg | grep -i "out of memory"
sudo grep -i "killed process" /var/log/syslog
# 检查MongoDB进程状态
ps aux | grep mongod
# 检查cgroup内存限制
cat /sys/fs/cgroup/memory/mongod/memory.limit_in_bytes
7.2 防止OOM
# 调整OOM Score(降低MongoDB被杀概率)
sudo echo -500 > /proc/$(pgrep mongod)/oom_score_adj
# 或在systemd服务中配置
[Service]
OOMScoreAdjust=-500
7.3 配置Swap
# 创建swap文件
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 永久生效
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
# 设置swappiness为1(尽量不用swap)
sudo sysctl -w vm.swappiness=1
八、总结
Debian系统上MongoDB内存管理的关键要点:
- 合理配置WiredTiger缓存:设置为系统内存的50%-60%
- 禁用透明大页:减少内存分配延迟
- 优化系统参数:swappiness、脏页比例、文件句柄数
- 控制连接数:每个连接约1MB内存,限制最大连接数
- 优化查询:创建索引避免内存排序,使用allowDiskUse处理大数据
- 持续监控:监控缓存使用率、脏页比例、内存命中率
注:本文基于MongoDB 7.0和Debian 12编写,配置参数需根据实际硬件和业务负载调整。