db.currentop() 默认查不到后台索引构建任务,因其属后台线程而非活跃操作;需用 db.admincommand({currentop: 1, $or: [{secs_running: {$gt: 60}}, {msg: "index"}]}) 过滤捕获,关键字段为 msg: "index"(或 "building index" 等变体),结合 acquiringlock 状态、mongostat 锁队列及 iostat/dmesg 排查资源瓶颈。

db.currentOp() 查不到索引构建任务怎么办
后台建索引({ background: true })不会出现在 db.currentOp() 默认结果里,因为它不被视作“活跃操作”,而是后台线程任务。直接调用 db.currentOp() 返回空列表,不代表没在建索引。
- 必须加过滤条件:用
db.adminCommand({currentOp: 1, $or: [{secs_running: {$gt: 60}}, {msg: "index"}]})才能捕获 - 注意
msg: "index"是关键字段,部分版本日志中会写成"Building index"或"Index build",可尝试模糊匹配 - 如果返回为空,但
db.collection.stats().indexCount长时间没变,且写操作明显变慢,大概率是索引正在构建但被阻塞(比如写入竞争或 I/O 等待)
锁状态怎么看:waitingForLock vs acquiringLock
前台建索引会持全局写锁,后台建索引则持 collection 级读锁——这足以阻塞 update、delete、findOneAndUpdate 等写操作,但允许 find 继续执行。
-
db.currentOp()中出现大量acquiringLock状态,且ns指向同一集合,说明写操作在排队等锁 - 若看到
waitingForLock,更可能是前台模式;acquiringLock更常见于后台模式下高并发写入场景 - 配合
mongostat观察:locked db列持续非零,qw(写队列)上升而netIn未同步增长,就是典型锁争用
磁盘和内存瓶颈怎么确认
索引构建卡住,80% 以上不是代码写错,而是底层资源扛不住。尤其要注意两个独立于 WiredTiger 缓存的硬限制:
- 排序阶段内存直走堆,由
sortBufferSizeMB控制(默认 512),不受wiredTigerCacheSizeGB约束;查dmesg -T | grep -i "killed process"看是否被 OOM killer 干掉 - 磁盘 I/O 瓶颈比 CPU 更常见:HDD 上建索引可能比 SSD 慢 5–10 倍;用
iostat -x 1观察%util是否长期 >90%,await是否突增 - 检查
db.collection.stats()中size和count,预估键值总量(例如 500 万文档 × 平均键长 120B ≈ 600MB 排序数据),再对比sortBufferSizeMB设置是否合理
分片集群里索引创建夯住的特殊原因
分片环境下,createIndex 是广播命令,任一 shard 失联或响应超时,整个命令就会卡住,而不是跳过失败节点。
- 默认超时 30 分钟,期间 shell 无响应、无报错,看起来像“假死”
- 先检查各 shard 连通性:
sh.status()看是否有UNAVAILABLE或NOT_REACHABLE状态 - 查每个 shard 的日志,搜索
"index build failed"或"timeout";主节点日志里可能只显示"waiting for shards"却不报错 - 若确认某 shard 不可用,需先恢复它,或临时降级为单分片验证,别强行重试











