一、MongoDB 监控工具全景图MongoDB 的监控工具可以按响应时效和数据深度分为四个层次)层次工具/方法典型场景响应速度实时命令行mongostat、mongotop突发故障第一响应、日常巡检秒级内置诊断serverStatus、stats、currentOp深度分析、脚本化采集按需毫秒级返回慢查询分析system.profile、explain性能调优、容量规划事后分钟/小时级长期监控PrometheusGrafana、PMM趋势预警、容量预测、SLA 报表周期性秒/分钟级采集四个层次不是割裂的而是一个自上而下诊断、自下而上优化的闭环。日常靠第四层保底故障时从第一层切入逐级下钻。这中间贯穿着一条主线先看整体 → 下钻到集合 → 定位到具体操作 → 优化并长期观测。二、mongostat —— 实例级实时性能仪表盘1. 工具定位mongostat是 MongoDB 发行版自带的轻量级命令行工具它每秒可调捕获一次实例的操作计数和资源状态并以表格形式输出。它回答了最核心的问题数据库现在整体忙不忙在忙什么2. 基本用法# 连接本地默认端口mongostatmongodb://root:root192.168.56.101:27027/?authSourceadmin# 连接远程副本集推荐使用 URI自动发现主节点mongostat--urimongodb://admin:passmongodb0.example.com:27017/?authSourceadmin# 每 2 秒输出一次共输出 10 行后退出mongostat--rowcount10--sleep2# 输出字段带单位人性化显示如 1.2Gmongostat--humanReadabletrue权限要求执行用户需拥有serverStatus和replSetGetStatus权限。建议创建专用监控角色db.createRole({role:monitorRole,privileges:[{resource:{cluster:true},actions:[serverStatus,replSetGetStatus]}],roles:[]})3. 核心字段全解析以下对mongostat输出的关键字段进行逐一解读并给出实战告警阈值字段含义原理简析告警参考insert/query/update/delete每秒操作次数带*表示复制操作统计自上次采样以来的增量与业务基线对比突增/骤降超 50% 需关注getmore每秒游标批量获取次数由find()分批返回触发大结果集查询常见若持续高且伴随 query 不高可能未用limit()command每秒执行的命令数如find、aggregate、count主节点输出格式本地|复制副本集—conn当前活跃连接数包括客户端和内部连接接近net.maxIncomingConnections的 80% 即警戒dirty / usedWiredTiger 缓存中脏数据 / 总使用比例百分比核心指标——见 2.4 节深度解析dirty 5% 告警 10% 紧急used 95% 告警flushes每秒执行fsync将缓存写入磁盘的次数WiredTiger 默认每 60s 一次 checkpoint若远超 1次/分钟说明有主动fsync操作vsize / res虚拟内存 / 常驻物理内存单位MB/GBres应接近storage.wiredTiger.engineConfig.cacheSizeGBres持续远超 cacheSizeGB 时说明内存压力大qrw读写操作队列长度格式读队列|写队列超过 0 表示操作在等待锁或 IO任何非零且持续存在即表示有瓶颈arw活跃的读写操作数格式读|写当前正在执行的操作持续高位说明硬件吞吐已达上限netIn / netOut每秒网络入/出流量字节—与带宽容量对比4. 深度原理解析WiredTiger 缓存与 dirty 指标dirty和used是mongostat中最关键也最易误读的指标。要理解它们必须深入 WiredTiger 的缓存机制。WiredTiger 的缓存架构WiredTiger 使用两级缓存内部缓存内存和磁盘数据文件。所有读操作优先从缓存中取数据cache缓存未命中时才触发磁盘读取。写操作先写入内存中的缓存页并将该页标记为“dirty”脏页随后由后台线程异步刷盘。检查点Checkpoint机制WiredTiger 每隔60 秒默认执行一次全局检查点checkpoint将内存中所有脏页的变更以一致性快照的方式写入磁盘。检查点期间dirty比例会短暂下降但检查点的频率是固定的。dirty 比例持续走高意味着什么脏数据产生的速度超过了后台刷盘线程eviction线程的消化速度。常见原因写入量突发暴涨、磁盘 IOPS 不足导致刷盘慢、内存太小导致缓存压力过大。当dirty超过 5%系统开始进入“软压力”状态后台 eviction 线程会被加速唤醒。超过 20% 时写入操作会开始被阻塞直到脏数据被刷出。used 比例与工作集Working Setused表示当前缓存中有效数据占比包括干净页和脏页。如果used持续 95%说明缓存空间已基本占满。此时新的数据页进入缓存必须驱逐evict旧的页这会消耗额外的 CPU。经验法则used稳定在 70%~85% 是健康状态95% 以上时考虑扩大cacheSizeGB或减少工作集大小。5. 实战场景通过 mongostat 快速定位故障场景一实例突然变慢但没有报错$ mongostat insert query update delete conn dirty used vsize res qrw arw netIn netOut120034001251281.272.46.1G3.8G0|03|11.8m3.2mdirty仅 1.2%缓存健康。qrw0|0无排队。used72.4%缓存充裕。结论实例本身负载正常慢问题大概率出在具体的查询语句上应进入慢查询分析见第五章。场景二写入操作卡顿应用大量超时$ mongostat insert query update delete conn dirty used vsize res qrw arw netIn netOut850012004203051212.796.26.1G5.6G3|25|36.8m9.1mdirty12.7%远超 5%used96.2%接近极限。qrw3|2有读写排队arw5|3活跃线程数很高。根因写入量过高磁盘刷盘能力不足缓存堆积大量脏数据。排查方向检查是否有大批量导入或密集更新查看磁盘 IOPS 是否达到瓶颈考虑调整eviction_trigger参数或扩容内存/SSD。三、mongotop —— 集合级热点定位1. 工具定位mongotop提供每个集合collection级别的读写耗时统计是mongostat的下钻工具。如果说mongostat告诉你“身体发烧了”那mongotop就帮你找到“哪个器官发炎了”。2. 基本用法# 默认每秒刷新显示所有集合的读写耗时mongotop# 每 30 秒采样一次更利于观察趋势mongotop30# 连接副本集并指定认证mongotop--urimongodb://admin:passmongodb0.example.com:27017/?authSourceadmin30# 只输出耗时超过 100ms 的集合可通过 --threshold 过滤mongotop--threshold1003. 输出格式与字段含义2025-06-26T10:30:15.1230800 connected to: mongodb0.example.com ns totalreadwritetest.orders 82403ms 12ms 82391ms test.inventory 1520ms 1120ms 400ms admin.system.users 5ms 5ms 0ms local.oplog.rs 340ms 340ms 0ms字段含义ns命名空间格式为数据库名.集合名total该集合在此采样周期内的读写总耗时毫秒read该集合读操作的耗时总和write该集合写操作的耗时总和注意mongotop统计的是耗时等待执行而非操作次数。一个集合 total 很高不一定意味着 QPS 高也可能是单次操作特别慢如全表扫描。4. 实战解读与排查流程场景观察到 test.orders 的 total 高达 82403ms远高于其他集合排查步骤确认是读主导还是写主导本例write82391ms占绝对大头说明是写入热点。查看该集合的索引策略高写入耗时通常意味着每次更新/插入要维护大量索引或索引不适合。检查是否有大量 upsert 或 array 更新这类操作在 WiredTiger 中可能触发页分裂加剧写入延迟。查看db.collection.stats()分析该集合的索引数量和平均文档大小。结合慢查询日志定位具体慢写入语句。阈值参考基于三节点副本集、SSD 存储total持续 1000ms健康。total在 1000~5000ms可接受需关注趋势。total持续 5000ms必须介入该集合已成为瓶颈。5. 副本集环境下的特殊关注在副本集中主节点Primary的mongotop显示的是业务读写耗时从节点Secondary的mongotop则会显示大量local.oplog.rs的读取耗时因为从节点通过拉取 oplog 来复制数据。如果从节点的local.oplog.rs读取耗时异常高同时业务集合的写耗时也很高说明复制延迟正在发生。对比主从节点的mongotop输出可以辅助判断延迟是来源于网络还是从节点自身的写入能力。四、内置诊断命令 —— 系统化的深度透视1. db.serverStatus() —— 全局状态总览db.serverStatus()是 MongoDB 最全面的内置诊断命令返回一个包含数百个指标的 JSON 文档。它不会对性能造成明显影响可放心在线上使用。// 在 mongosh 中执行db.serverStatus()// 针对性查看关键维度避免输出过大db.serverStatus().connections db.serverStatus().mem db.serverStatus().opcounters db.serverStatus().opLatencies db.serverStatus().wiredTiger关键指标分组解读1连接与网络指标含义解读connections.current当前连接数应与net.maxIncomingConnections默认 65536对比connections.available剩余可用连接低于 100 时需排查是否有连接泄漏network.bytesIn / bytesOut累计网络流量用于计算平均带宽占用2操作计数与延迟OpCounters OpLatencies指标含义opcounters.insert/query/update/delete自启动以来的累计操作次数opLatencies.reads.latency读操作的总延迟微秒opLatencies.reads.ops读操作总次数opLatencies.reads.avg平均读延迟可通过latency / ops计算实战技巧opcounters的绝对值意义不大应与其历史基线对比。例如如果query计数在过去 5 分钟内的增量突然翻倍说明业务或流量发生了变化。3内存与缓存WiredTiger 核心在wiredTiger.cache路径下指标含义bytes currently in the cache当前缓存数据字节数bytes dirty in the cache当前脏数据字节数pages read into cache从磁盘读入缓存的总页数pages written from cache从缓存写入磁盘的总页数pages evicted by application threads应用线程主动驱逐的页数若过高说明缓存压力大tracked dirty bytes in the cache追踪中的脏字节数计算缓存命中率命中率 1 - (pages read into cache) / (pages requested from cache)理想值应 99%。若命中率低于 95%说明内存严重不足大量读请求穿透到磁盘。2. db.stats() —— 数据库级存储统计db.stats()返回当前数据库的存储概览常用于容量规划和碎片分析。use myApp db.stats()关键输出示例{db:myApp,collections:12,views:2,objects:8450000,avgObjSize:512,dataSize:4326400000,storageSize:5120000000,indexes:34,indexSize:1536000000,totalSize:6656000000,ok:1}字段含义实战解读dataSize逻辑数据大小压缩后不含索引反映真实数据量storageSize磁盘上实际分配的存储空间大于dataSize是因预分配和碎片indexSize所有索引的总大小索引大小不应超过数据大小的 2 倍avgObjSize平均文档大小过大1MB需考虑子文档拆分如果storageSize远大于dataSize如 2 倍以上说明存在大量存储碎片可考虑执行compact副本集需滚动操作。db.runCommand({compact:集合名})3. db.collection.stats() —— 集合级深度诊断db.collection.stats()提供指定集合的详细统计是排查单个集合性能问题的核心工具。db.orders.stats()db.orders.stats(1024)// 以 KB 为单位显示重点关注字段字段含义告警条件count文档总数与预期不符可能说明同步延迟或业务异常size数据占用压缩后—avgObjSize平均文档大小突增说明文档结构变化storageSize磁盘分配空间明显大于size说明需 compactnindexes索引数量超过 7 个需审慎评估写入性能影响totalIndexSize索引总大小—indexSizes每个索引的大小详情可发现异常大的索引capped是否为固定集合—wiredTiger.creationStringWiredTiger 创建配置可看到 block_compressor 等信息经典场景某个集合查询变慢执行db.orders.stats()后发现totalIndexSize高达size的 3 倍且indexSizes中有一个很少使用的字段索引非常大。结论维护过多无用索引占用了内存并拖慢了写入建议删除冗余索引。4. db.currentOp() —— 当前操作快照db.currentOp()返回正在执行的所有操作是诊断“卡住”问题和死锁的利器。// 查看所有活跃操作db.currentOp({active:true})// 查看运行超过 5 秒的查询db.currentOp({active:true,secs_running:{$gt:5}})// 查看特定数据库的操作db.currentOp({ns:/^myApp/})关键输出字段opid操作 ID可用于db.killOp(opid)终止。ns操作的命名空间。command执行的命令内容。secs_running已运行秒数。waitingForLock是否在等待锁。locks当前持有的锁类型。五、慢查询分析 —— system.profile 与 explain 闭环当mongostat显示实例繁忙且mongotop定位到热点集合后下一步就是找到具体是哪条查询或写入在作祟。这需要依赖数据库分析器和执行计划工具。1. 开启与配置系统分析器ProfilerMongoDB 内建的分析器会将耗时超过阈值的操作写入system.profile集合。// 查看当前分析级别0关闭1记录慢查询2记录所有操作db.getProfilingLevel()// 设置级别为 1慢查询阈值 100ms推荐生产环境db.setProfilingLevel(1,{slowms:100})// 查看当前设置db.getProfilingStatus()级别选择建议0关闭仅用于极致性能压测不推荐生产环境。1慢查询推荐。阈值依据业务核心查询的平均耗时 * 1.5~2 倍设置。2全部操作仅调试临时开启会显著增加系统开销。2. 查询 system.profile 定位慢操作// 按时间倒序查看最近的 10 条慢查询db.system.profile.find().sort({ts:-1}).limit(10)// 查找耗时超过 1 秒的查询按耗时降序db.system.profile.find({millis:{$gt:1000}}).sort({millis:-1})// 按集合过滤查看特定表的慢操作db.system.profile.find({ns:myApp.orders})// 查看全表扫描的慢查询即未使用索引db.system.profile.find({planSummary:{$regex:/COLLSCAN/}})system.profile 常用字段字段含义ts执行时间戳ns命名空间op操作类型query/update/insert/delete/commandmillis执行耗时毫秒command完整的命令或查询语句planSummary执行计划摘要如 IXSCAN、COLLSCANnreturned返回文档数keysExamined扫描的索引键数docsExamined扫描的文档数3. explain() 分析执行计划从system.profile中找到可疑的慢查询语句后使用explain(executionStats)获取详细执行计划db.orders.find({customerId:C10086,status:pending,createdAt:{$gte:ISODate(2025-01-01)}}).explain(executionStats)输出中的核心指标及诊断规则指标含义健康标准executionTimeMillis该查询实际执行耗时—totalKeysExamined扫描的索引条目数应接近nReturnedtotalDocsExamined扫描的文档数应接近nReturnednReturned返回的文档数—stage顶层执行阶段避免COLLSCANinputStage.stage子执行阶段IXSCAN索引扫描为优经验法则若totalDocsExamined远大于nReturned如 1000 倍则索引选择性差或未命中索引。若stage为COLLSCAN必须创建索引。若totalKeysExamined接近totalDocsExamined但远大于nReturned说明索引字段区分度不足需考虑复合索引。示例创建有效的复合索引根据上述查询条件可创建db.orders.createIndex({customerId:1,status:1,createdAt:-1})创建后再次执行explain()确认stage变为FETCH从索引回表或IXSCAN且totalDocsExamined大幅降低。六、监控体系搭建 —— 从命令到平台化1. 分层监控架构设计一个成熟的 MongoDB 生产环境监控体系应包含以下五个层次2. 开源方案推荐Prometheus Grafana这是社区最成熟的组合MongoDB 官方也提供了 Prometheus Exporter# 启动 MongoDB Exportermongodb_exporter\--mongodb.urimongodb://admin:passlocalhost:27017\--collector.database\--collector.collection\--collector.topmetrics\--collector.indexusageGrafana 仪表盘建议使用社区广泛验证的MongoDB 官方仪表盘ID: 1860或 Percona 提供的详细仪表盘。关键面板至少包括QPS 与操作类型分布连接数趋势WiredTiger 缓存命中率与 dirty 比例复制延迟各集合的读写耗时Top 10告警规则示例基于 Prometheus 语法告警规则表达式持续时间级别脏数据比例过高mongodb_mongostat_dirty * 100 82mWarning脏数据紧急mongodb_mongostat_dirty * 100 151mCritical缓存使用率过高mongodb_mongostat_used * 100 955mWarning复制延迟time() - mongodb_replset_member_optimeDate 101mCritical连接数接近上限mongodb_connections_current / mongodb_connections_available 0.22mWarning七、面试题精选Q1用户反馈应用写入超时登录到 MongoDB 主节点执行 mongostat看到 dirty 持续 15%used 98%qrw 显示 4|2。请说出你的完整排查思路和应对措施。参考答案第一步现象确认—— 从mongostat可判断系统处于缓存高压 写入阻塞状态。dirty15%说明脏数据已严重堆积used98%说明缓存几近占满qrw4|2说明有操作在排队等待资源。第二步根因定位—— 导致脏数据堆积的原因通常有三类磁盘 IOPS 瓶颈后台刷盘线程无法及时将脏页落盘。写入流量突增业务批量导入或密集更新突发。内存不足cacheSizeGB设置过小工作集超过物理内存。第三步快速止血—— 如果应用允许先限流或暂停批量写入操作避免情况恶化。同时检查磁盘 IO 使用率如iostat -x 1若%util接近 100%确认磁盘瓶颈。第四步长期措施若磁盘 IOPS 不足升级为本地 NVMe SSD 或提高云盘 IOPS 上限。调整 WiredTiger 刷盘参数eviction_trigger和eviction_target默认无需修改除非专家调优。考虑增加storage.wiredTiger.engineConfig.cacheSizeGB注意留足内存给操作系统文件缓存。检查业务写入模式是否可以改为批量写入或降低写入频率。Q2mongotop 显示 test.orders 的 total 高达 30 秒但该集合的 QPS 只有 200且索引齐全。你认为可能的原因是什么如何进一步排查参考答案原因分析mongotop统计的是总耗时而非单个操作耗时。total30s且 QPS 只有 200说明单次操作平均耗时高达 150ms30,000ms / 200这是不正常的。索引齐全但仍慢指向以下可能索引没有被使用查询条件字段顺序与复合索引不匹配或使用$or、$regex等无法有效利用索引的操作。大量文档被扫描虽然索引命中了但选择性很差如索引字段只有 2 个枚举值导致仍要回表扫描大量文档。文档体积过大每个文档大小超过几 MB即使通过索引找到回表取数据也消耗大量时间。锁等待或页分裂高并发下写入导致 WiredTiger 页分裂读操作被阻塞。进一步排查步骤从system.profile中捞出该集合最近的慢查询用explain(executionStats)确认实际执行计划。检查totalKeysExamined和totalDocsExamined若后者远大于前者则索引选择性差。查看db.collection.stats().avgObjSize若远大于正常值考虑拆分文档。结合db.currentOp()查看是否有长时间持有锁的操作。Q3你的监控系统发现副本集的从节点延迟持续增大从正常的 1s 增长到 10 分钟。你如何定位原因并解决参考答案定位思路确认延迟量在从节点执行rs.status().members[1].optimeDate与主节点对比。查看从节点的 mongostat重点看qrw和dirty。如果从节点dirty过高说明从节点自身写入能力不足可能硬件较差。查看从节点的db.currentOp()是否有长时间运行的查询比如报表分析阻塞了 oplog 重放从节点重放 oplog 是单线程的如果一个分析查询耗时 5 分钟这 5 分钟内的所有新 oplog 都会积压。检查网络带宽主从间netOut是否接近带宽上限。解决方案若是从节点硬件差考虑升级配置或将读流量切到其他从节点。若是长查询阻塞终止该操作db.killOp()或将其移至只读的隐藏节点hidden: true, priority: 0执行。若网络问题检查交换机或跨机房专线质量。Q4某日凌晨MongoDB 实例的used缓存比例从 70% 缓慢上升至 98%但dirty始终低于 3%查询响应时间没有明显变化。请分析这种现象是否正常以及是否需要处理。参考答案现象定性这是典型的工作集增长现象但不一定危险。used上升表示缓存中存储的数据页越来越多说明查询正在访问此前不常用的数据将其读入缓存。dirty保持低位说明没有写入压力刷盘线程工作正常。查询响应时间未变化说明缓存命中率依然足够高因为新加载的数据也服务了请求。是否需要处理如果used上升到 99%~100% 并且开始出现缓存驱逐pages evicted by application threads计数上升同时查询变慢则需要介入。若稳定在 98% 但无驱逐说明工作集恰好略大于缓存大小属于临界状态建议提前扩容内存或调整cacheSizeGB。同时检查是否有不合理的全表扫描操作将大量无关数据加载进缓存挤占了热数据空间。Q5你团队有 20 套 MongoDB 副本集手工执行 mongostat 已经无法满足日常巡检需求。请你设计一套最低成本的自动化监控方案并说明核心指标和告警维度。参考答案方案设计低成本选型采集层在每套集群的主机上部署mongodb_exporter或使用 Telegraf 的 MongoDB 插件采集间隔 30 秒。存储层单机部署 Prometheus使用 2TB 磁盘可保存 30 天。可视化与告警Grafana 搭建统一仪表盘并配置 AlertManager 发送钉钉/邮件告警。补充使用mtail或 Filebeat 采集慢查询日志存入 Elasticsearch 供临时检索。核心指标与告警维度优先级排序S级立即告警节点宕机、复制延迟 60s、连接数耗尽 5% available、dirty 10%。A级预警dirty 5%、缓存命中率 95%、CPU 使用率 80%、磁盘可用空间 20%。B级日常观察QPS 趋势、索引大小增长、各集合存储空间变化。附录快速索引需求推荐命令/工具看一眼整体负载mongostat找热点集合mongotop查全局状态db.serverStatus()看库存储db.stats()看集合详情db.collection.stats()看当前卡住的操作db.currentOp()查慢查询日志db.system.profile.find()分析执行计划.explain(executionStats)长期监控平台Prometheus Grafana / Ops Manager