先确认 mongod 进程是否真在吃 cpu:用 top -c 按 p 倒序查看,若 %cpu 长期 >80% 且 command 为 mongod,则问题在 mongodb 内部;再用 mongostat 查高频操作类型,结合 db.currentop({ "secs_running": { "$gt": 5 } }) 定位具体长耗时操作,重点关注 ns、op、command、secs_running 和 locks 字段,确认后可用 db.killop() 快速终止。

先确认是不是 mongod 进程真在吃 CPU
别信监控图的“CPU 使用率 95%”就直接开查索引——top 才是第一道筛子。登到节点上跑:top -c,按 P(大写)按 CPU 倒序,看排第一的是否为 mongod 进程。如果 %CPU 长期 >80%,且 COMMAND 明确是 mongod,问题就在 MongoDB 内部;如果只是 java 或 node 进程高,那得回应用层查。
TIME+ 字段也得扫一眼:某个 mongod 进程运行几小时但 CPU 持续飙高,大概率卡在长事务、后台索引构建或未终止的聚合里。再补一句:top -c | grep mongod 能看到完整启动命令,留意有没有 --wiredTigerCacheSizeGB 设得太小(比如只给 2G),这会逼它频繁刷盘、换页,把 CPU 拖进内核态。
用 mongostat 看清“它在忙什么”
mongostat 不是查慢查询的,它是每秒给你一张快照,告诉你此刻 MongoDB 正在高频干啥。在主节点执行:mongostat -n 30 --host rs0/mongo1:27017,mongo2:27017(直连副本集,不依赖当前 primary)。
- 如果
update列从 300/s 突增到 3000/s,基本是业务在跑没加bulkWrite的 for 循环 -
faults非零要警觉:WiredTiger 缓存页缺失,说明内存不够或访问模式太散,CPU 得花大量时间做页换入换出 -
locked %持续 >10%,常见于短 update 更新同一计数器字段,或后台createIndex正在跑 -
netIn/netOut高但 CPU 更高?别只盯网络,同步跑iostat -x 1 3看%util和await,磁盘 I/O 瓶颈也会反向拉高 CPU
用 db.currentOp() 锁定具体作妖的操作
mongostat 告诉你“哪类操作多”,db.currentOp() 才告诉你“哪个 opid 在拖垮整台机器”。进 mongo shell 后立刻执行:
db.currentOp({ "secs_running": { "$gt": 5 } })
重点盯这几个字段:
-
ns:比如app.orders,确认是不是核心集合被反复扫描 -
op+command:看到"op": "command", "command": { "aggregate": ... }且secs_running>60,八成是漏了$limit或没走索引 -
locks:如果{"Global":"w"}持续存在,说明有全局写锁操作(如repairDatabase)正在堵住所有请求 -
client:IP 是不是来自某台应用服务器?赶紧查它最近发了啥批量任务
定位清楚后,db.killOp(<opid>)</opid> 可立即释放资源,但注意:别 kill 正在写配置库 config 或执行 moveChunk 的操作,可能引发分片元数据错乱。
读请求打到主节点导致主 CPU 过高怎么办
副本集状态正常 ≠ 流量分发合理。主节点 CPU 比从节点高 20%+,第一反应不是 MongoDB 有问题,而是读请求没分流。
- 检查客户端驱动是否显式设置了
readPreference:Java 驱动漏了ReadPreference.secondary(),Node.js 漏了readPreference: 'secondary',都会让读全压主库 - 查从节点配置:
rs.conf()里看slaveDelay是否非零,或hidden: true—— 这两种节点即使stateStr: "SECONDARY",也不会被选为读节点 - 网络分区恢复后,旧连接池可能还缓存着“主节点是 A”的路由信息,而实际主已切到 B,造成逻辑和物理主备错位;此时重启应用或强制刷新连接池更稳妥
真正麻烦的是那些藏在 ORM 底层的隐式读请求,比如 Hibernate 的二级缓存失效后批量 reload,或 Spring Data MongoDB 的 @Query 方法默认走 primary —— 这类得翻驱动源码或抓 wirelog 才能揪出来。











