需逐个登录各shard节点查mongod日志:先用sh.status()确认shard列表及ip,再定位/var/log/mongodb/mongod.log(或--logpath指定路径),检查slowopthresholdms是否合理,并筛选含“slow query”且plansummary为collscan或持续耗时>500ms的条目。

如何定位慢查询日志在哪个分片上产生
MongoDB 分片集群的慢查询日志默认分散在每个 mongod 实例(包括 shardsvr 和 configsvr)的日志文件中,mongos 本身不记录执行耗时的详细查询日志,只记录路由层错误或超时。所以不能只看 mongos 日志就断定慢在哪——必须逐个登录每个 shard 节点,检查其 mongod 的日志。
实操建议:
- 先用
sh.status()查清当前有哪些 shard,例如shard01、shard02,对应到实际服务器 IP 或容器名 - 确认各 shard 的日志路径:通常为
/var/log/mongodb/mongod.log,但可能被--logpath指定为其他位置,查启动参数:ps -ef | grep mongod | grep -v grep - 注意日志级别:若
slowOpThresholdMs未显式设置,默认是 100ms;若日志里没看到慢查询,先检查该参数是否被调高(如设成 5000),或logLevel是否太低(1及以上才记录慢操作)
如何从日志里快速识别真正慢的查询(而非误报)
MongoDB 日志中带 Slow query 标签的行不一定代表业务瓶颈——它只反映单次执行时间超过阈值,可能由临时锁争用、瞬时磁盘延迟或冷缓存导致。重点要筛出**稳定复现、高频出现、且执行计划未走索引**的条目。
实操建议:
- 用
grep "Slow query" /var/log/mongodb/mongod.log | tail -50快速抓最近慢日志,再用awk '{print $NF}'提取耗时字段(单位毫秒),看是否持续 >500ms - 关注日志中
planSummary字段:如果出现COLLSCAN或SORT且无IXSCAN,基本可判定缺失有效索引 - 注意
originatingCommand字段(仅 4.2+ 启用verbose日志模式时存在):它会显示原始查询语句,否则只能靠ns(命名空间)和query字段拼凑,后者可能被截断
如何让慢查询日志带上更完整的上下文信息
默认日志对排查帮助有限,尤其缺少用户、数据库、连接来源等上下文。MongoDB 本身不支持像 MySQL 那样直接输出 client_ip 或 username,但可通过配置增强可观测性。
实操建议:
- 在
mongod.conf中启用详细日志:systemLog.verbosity: 1(或更高),并确保operationProfiling.mode: slowOp已开启(该配置影响 profile collection,不影响日志,但可交叉验证) - 配合
auditLog(企业版)或应用层埋点:社区版无法记录 user/host,但可在应用侧统一打标,比如在 query comment 里加{"service":"order","trace_id":"abc123"},MongoDB 会原样记入日志的comment字段 - 避免过度开启
logLevel: 2+:会导致日志暴增,IO 压力大,仅调试期临时使用
为什么在分片集群里直接用 db.currentOp() 看不到跨分片慢查询全貌
db.currentOp() 只作用于当前连接的 mongod 实例,而一个分片查询可能被 mongos 拆成多个子查询发往不同 shard,每个 shard 上的 currentOp 只反映本地执行状态,无法还原完整链路。
实操建议:
- 不要依赖单个
db.currentOp()判断全局慢查询;如需实时抓活查询,应在所有 shard 上并发执行,并用secs_running+microsecs_running排序筛选 - 更可靠的方式是开启 profiler(仅限 debug):
db.setProfilingLevel(2, {slowms: 100}),但注意 profiler collection 本身也受分片影响,system.profile不自动分片,必须建在 admin 库且只存在于单个节点——所以只适用于单 shard 测试环境 - 生产环境推荐用
mongostat --host <mongos-addr></mongos-addr>观察整体 opcounters,结合网络监控(如netstat -s | grep -i "retransmit")判断是否卡在 mongos 到 shard 的网络环节
真正难的不是找到慢日志,而是区分它是查询写法问题、索引缺失、分片键设计不合理,还是底层硬件抖动。日志里那行 Slow query 只是个入口,后面得立刻跟进 explain("executionStats")、sh.status() 查 chunk 分布、以及 iostat -x 1 看磁盘 await——三者缺一不可。











