在 CentOS 上排查 MongoDB 性能瓶颈的实用流程
一、快速定位瓶颈类型
- 使用 mongostat 观察整体负载与队列:关注 inserts/s、queries/s、updates/s、deletes/s、getmore/s、command/s,以及 qr/qw(读/写队列)、conn(连接数)、faults/s(缺页,>100 可能内存不足或工作集过大)、idx miss %(索引未命中)、WiredTiger 的 %dirty、%used。这些指标能快速判断是 CPU/IO/锁/内存/索引 哪一类问题。
- 使用 mongotop 定位热点集合:按库/集合维度查看读写耗时,识别异常 热点表 或 突发热点操作。
- 查看 MongoDB 日志:默认路径 /var/log/mongodb/mongod.log,结合 logrotate 做日志轮转,避免磁盘被日志占满影响性能。
- 初步判断后,进入下一节按资源与查询两个维度深入排查。
二、按资源维度排查
- CPU:若 mongostat 的 command/s 高 且 CPU 使用率接近满载,多为 大量聚合/排序/计算 或 索引缺失 导致全表扫描。
- 内存与存储:
- 关注 %dirty(WiredTiger 脏页比例)持续高于 10% 常提示 磁盘 IO 跟不上;%used 接近缓存上限说明 工作集可能大于内存。
- faults/s 高 表示频繁缺页,需检查 工作集大小 与 内存容量,并评估 SSD 替换 HDD。
- 使用 iostat -x 1 观察 await、r/s、w/s、util%,确认是否存在 磁盘瓶颈。
- 网络:通过 mongostat 的 netIn/netOut 观察是否触达带宽上限,或存在 大文档/大批量返回 导致网络拥塞。
- 连接与队列:若 qr/qw 长时间大于 0 或 conn 接近上限,需检查 连接泄漏、连接池配置 与 慢操作阻塞。
- 系统层检查:用 top/htop/vmstat 交叉验证 CPU steal、上下文切换、swap 等系统指标。
三、按查询维度排查
- 发现慢操作:
- 使用 $currentOp 定位当前 长时间运行或阻塞 的操作,必要时 db.killOp(opid) 止损。
- 开启 Database Profiler 抓取慢查询(建议仅在问题库、短时开启):如 db.setProfilingLevel(1, {slowms: 100, sampleRate: 0.5});查看 system.profile 中的 millis、planSummary、keysExamined、docsExamined、nreturned、numYield、responseLength 等字段,判断是否 COLLSCAN、是否 扫描过多、是否 返回过大。
- 分析执行计划:对问题查询使用 explain(“executionStats”),确认是否 IXSCAN、是否 低效排序/聚合、是否可通过 复合索引 覆盖。
- 识别常见低效模式:无索引过滤、前导列缺失、在 $where/$regex 上无索引、聚合缺少 $match/$project 前置裁剪、返回 大字段/大批量 结果。
- 索引有效性:用 $indexStats 找出 未使用或低使用 的索引,删除冗余索引以降低写放大;结合 $collStats 与 $queryStats 观察 集合与查询形态 的整体画像。
四、常见瓶颈与对应处理建议
| 现象 |
可能原因 |
处理建议 |
| qr/qw 高、command/s 高 |
锁竞争、慢查询、资源不足 |
优化慢查询与索引;限流/批处理;扩容或读写分离 |
| %dirty > 10% 或 iostat util% 高 |
磁盘 IO 跟不上 |
升级为 SSD;降低写入峰值;优化索引/批量大小;检查 WiredTiger 配置 |
| faults/s 高 |
工作集大于内存 |
增加内存;优化索引覆盖;归档冷数据;减少大文档/大返回 |
| idx miss % 高 |
索引缺失或顺序不当 |
建立 复合索引(注意前导列);用 explain 验证索引命中 |
| netIn/netOut 高 |
大文档/大批量传输 |
使用 投影 projection、limit、batchSize;压缩与分页 |
| 热点集合/操作 |
业务热点或缺失分片键 |
调整 分片键 均衡数据;对热点表做二级索引与缓存 |
| 连接数接近上限 |
连接泄漏/池配置不当 |
修复连接泄漏;调整应用连接池;增加实例或连接上限 |
| Profiler/日志开销大 |
全量采集或日志级别过低 |
仅对问题库短时开启;提高 slowms;使用 sampleRate;启用 logrotate |
五、建议的排查顺序与命令清单
- 步骤顺序
- mongostat -n 300 2 观察整体负载、队列、缺页、dirty、连接数。
- mongotop -n 100 2 找出热点集合。
- tail -f /var/log/mongodb/mongod.log 检查错误与慢日志线索。
- db.serverStatus() 获取全局指标(连接、内存、锁、缓存等)。
- $currentOp 查正在阻塞/长时间运行的操作,必要时 db.killOp(opid)。
- 在问题库短时开启 Profiler:db.setProfilingLevel(1, {slowms:100, sampleRate:0.5}),分析 system.profile 与 explain(“executionStats”)。
- 用 $indexStats/$collStats/$queryStats 评估索引使用与集合/查询形态。
- 系统层用 iostat -x 1、top/htop、vmstat 交叉验证 IO/CPU/内存。
- 优化后回归验证,并保留对比指标(QPS、P95/P99、队列、IO、命中率)。
- 常用命令清单
- mongostat -h 127.0.0.1:27017 -n 300 2
- mongotop -h 127.0.0.1:27017 -n 100 2
- tail -f /var/log/mongodb/mongod.log
- mongo --eval ‘db.serverStatus()’
- db.adminCommand({$currentOp: 1, “idleConnections”: false})
- db.setProfilingLevel(1, {slowms:100, sampleRate:0.5})
- db.system.profile.find().sort({ts:-1}).limit(10).pretty()
- db.myColl.find({…}).explain(“executionStats”)
- db.myColl.aggregate([{$indexStats:{}}])
- db.myColl.aggregate([{$collStats:{}}])
- db.myColl.aggregate([{$queryStats:{}}])
注:生产环境开启 Profiler 需谨慎,避免性能回退。