mongodb分片集群中慢查询日志只存在于各shard的mongod实例,mongos因无状态路由不记录profile;需直连shard节点启用profiling、建ts索引、调低slowms,并结合docsexamined/nreturned比值与plansummary分析真实瓶颈。

在 MongoDB 分片集群里,mongos 上查不到真正的慢查询日志——因为 mongos 只路由请求,不执行查询,system.profile 根本不会在那里写入任何记录。真正耗时的执行片段,都分散在后端各个 shard 的 mongod 实例里。
为什么 mongos 上 db.setProfilingLevel() 没用?
mongos 是无状态路由层,它不解析、不执行、不记录查询细节。你调用 db.setProfilingLevel(1) 或设置 slowms,返回成功但实际无效:system.profile 集合为空,或始终提示 "no profiling information available"。
- 所有
profile数据只存在于每个shard(即独立mongod进程)的本地system.profile中 -
config server节点也要检查——虽然不存业务数据,但元数据操作慢会拖垮整个分片协调 - 别被
mongos日志里的320ms耗时误导:那是端到端时间(含网络、合并、协调),单个shard可能只花了8ms
怎么定位具体哪个 shard 在扛慢查询?
先通过 mongos 查清分片拓扑,再直连可疑节点:
- 运行
sh.status(),看哪些shard承载了目标集合,以及 chunk 分布是否倾斜 - 查 config 信息:
db.getSiblingDB("config").shards.find(),拿到每个shard的 host 列表(如shard01/10.0.1.10:27018,10.0.1.11:27018) - 优先连
secondaryOk节点(比如加--readPreference=secondaryPreferred),避免给 primary 增加额外负载 - 确认连接的是
mongod,不是mongos:用db.runCommand({ismaster:1})看输出中ismaster是否为true或secondary
查 system.profile 之前必须做的三件事
system.profile 是 capped collection,但默认不建索引,直接 find 会全表扫描,查起来极慢甚至超时:
- 手动创建时间索引:
db.system.profile.createIndex({ ts: -1 }),否则.sort({ts: -1})就是灾难 - 调低
slowms:分片环境下建议设为50,而不是默认100;小延迟在多个 shard 上叠加后总耗时超标,但单个 shard 不记录 - 立即启用 Profiler:
db.setProfilingLevel(1, { slowms: 50 }),注意这是 per-database 操作,得use your_db_name后再执行
怎么快速筛出真正有问题的慢操作?
别只盯着 millis 数值。关键看执行效率和计划特征:
- 查
docsExamined / nreturned比值:比值 > 100 很可能没走对索引,或索引区分度差 - 关注
planSummary字段:SHARD_MERGE表示跨分片聚合,COLLSCAN是全表扫,IXSCAN是索引扫描但可能 keysExamined 过大 - 常用命令:
db.system.profile.find({ millis: { $gt: 100 } }).sort({ ts: -1 }).limit(5) - 配合
currentOp抓活体:db.currentOp({ "secs_running": { "$gt": 2 } }),实时看卡住的长事务
最容易被跳过的其实是索引和 slowms 的协同:没索引时调低 slowms 只会让 system.profile 更快写满;有索引却没覆盖查询字段时,docsExamined 依然会爆增——这两者得一起看,不能只盯日志数字。











