当 MongoDB 出现响应变慢时,很多第一反应是查看慢查询日志,但慢日志只能说明某条语句执行时间长,无法直接反映实例整体的连接压力、内存换页和操作队列变化。mongostat 是 MongoDB 自带的一个轻量级状态监控工具,它以类似 Linux vmstat 的方式每秒输出一行统计,能够快速帮助运维和开发人员判断数据库当前是读多写少、连接打满、还是内存不足。该工具随 mongodb-database-tools 或服务器二进制包一起提供,通常位于 MongoDB 安装目录的 bin 下。

启动 mongostat 最基本的命令是直接执行 mongostat,默认连接本机 27017 端口的 mongod 或 mongos。如果实例在远程主机,可以加上 --host 参数。下面先给出一段默认输出示例,帮助理解后续字段说明。
insert query update delete getmore command dirty used flushes vsize res qr qw ar aw netIn netOut conn time
*0 *0 *0 *0 0 1|0 0.2% 75.2% 0 1.50G 203M 0 0 0 0 1.2k 4.5k 10 10:15:30
*1 *2 *0 *0 0 2|0 0.2% 75.2% 0 1.50G 203M 0 0 0 0 3.8k 7.2k 10 10:15:31
输出中每行对应一个采样周期,默认一秒一次。以 * 开头表明当前值是采样间隔内的变化量,而不是累计值;带 | 的字段表示读写命令的成功与失败次数。这张输出表本身就能回答很多问题:如果 qr 或 ar 持续大于 0,说明读操作在排队;如果 conn 逐步逼近实例配置的 maxIncomingConnections,连接层可能先成为瓶颈。
mongostat 核心指标怎么读
默认输出的字段比较多,但可以分成操作计数、内存与存储、队列与连接、网络吞吐四组。操作计数包括 insert、query、update、delete、getmore 和 command,它们表示每秒执行的各类操作数量。getmore 专门指客户端从游标继续拉取数据,比如批量遍历集合时会出现。command 字段的 1|0 形式表示成功一次、失败零次。持续观察这些数值可以判断业务读写比例,例如 query 远大于 insert 的实例通常偏向检索型场景,而 update 频繁则要考虑写入放大和索引维护成本。
内存相关字段中,dirty 是 WiredTiger 缓存中尚未刷盘的脏数据百分比,used 是缓存使用百分比。默认配置下 WiredTiger 缓存大小为物理内存的一半减去 1GB,如果 used 长期接近 100% 且 dirty 较高,说明缓存压力大,可能出现数据频繁从磁盘读取。这时可以结合 vsize 和 res 来看:vsize 是进程虚拟内存大小,res 是实际驻留内存大小。res 接近物理内存上限时,操作系统可能开始换页,性能会明显下降。flushes 表示每秒钟执行的 fsync 次数,写多时该值会上升。
队列字段 qr 和 qw 表示等待读取或写入的客户端队列长度,ar 和 aw 是活跃执行读或写操作的数量。如果 qr 持续大于 0,而 ar 并不高,通常说明有读操作被锁或磁盘 IO 阻塞;如果 qw 积压且 aw 已经接近并发上限,则要考虑扩容或优化写模式。网络字段 netIn 和 netOut 统计每秒网络输入输出字节数,单位是 KB 或 MB,可以帮助区分是网络带宽打满还是磁盘吞吐不足。
最后 conn 是当前连接数,注意这是实例级别的连接总数,而不是应用连接池中的客户端数量。连接数瞬间飙升可能会触发 MongoDB 的拒绝服务保护,因此监控该值的变化趋势比单点数值更重要。
常用启动参数与输出控制
直接运行 mongostat 会持续不断输出,对于脚本采集或者只看最近几十行的情况并不方便。可以使用 --rowcount 参数限制输出行数,例如只采样 20 次后自动退出,适合定时任务抓取快照。命令如下:
mongostat --rowcount=20 --host=127.0.0.1 --port=27017
如果 mongod 开启了认证,需要加上 --username、--password 和 --authenticationDatabase 参数。实际使用中不建议在命令行明文写密码,可以通过环境变量或提示输入的方式提供。连接副本集时,使用 --host 传入副本集名称和成员地址,格式为 replSetName/host1:port1,host2:port2,mongostat 会从返回的成员中读取数据。连接分片集群时通常连接 mongos 进程,因为 mongos 会聚合各个分片的统计信息。
另一个实用参数是 --discover,它会在副本集模式下自动发现所有节点,并把每个节点的统计并排显示出来。对于需要观察主从延迟和读写分布的场景非常有用。输出会多出 host 列,标识每行来自哪个成员。配合 --noheaders 可以去掉表头,方便把输出重定向到文本文件后用脚本解析。例如:
mongostat --host=rs0/192.168.1.10:27017,192.168.1.11:27017 --discover --rowcount=10 --noheaders
还有一些与 MongoDB 服务器版本相关的细节:从 4.4 开始,mongostat 输出的 dirty 和 used 字段只适用于使用 WiredTiger 存储引擎的实例,如果使用内存存储引擎或老版本 MMAPv1,这些列可能显示为 0 或不出现。对于 5.0 及以上版本,部分字段名称保持不变,但内部统计口径可能微调,因此排查问题时最好先确认客户端工具版本与服务器版本是否匹配。如果 mongostat 版本过老,连接新版本 MongoDB 时可能无法识别部分新指标,建议使用与服务器相同大版本的工具包。
结合系统指标定位性能瓶颈
mongostat 反映的是数据库内部视角,要完整定位问题还需要结合操作系统指标。一个常见误区是看到 query 很高就认为慢查询多,实际上 query 只是计数,不代表查询是否走索引、是否扫描大量文档。真正需要关注的是结合 qr 和 ar 判断有没有排队,以及结合 MongoDB 日志中的 slow query 确定具体语句。例如下面这个组合命令:
mongostat --rowcount=30 --host=127.0.0.1 > mongostat_$(date +%F_%H%M%S).log tail -n 10 mongostat_*.log
该命令把 30 秒的采样结果写入带时间戳的日志文件,然后查看最近 10 行,适合在问题复现时快速抓取现场。看完之后可以检查同一时间段内的系统 CPU、磁盘 IO 和内存。Linux 下可用 iostat -x 1 查看磁盘平均等待时间,如果 await 持续超过 20 毫秒,同时 mongostat 中 qr 或 qw 不为零,基本可以判断磁盘成为瓶颈。此时扩容磁盘、增加缓存或调整写入关注级别都能缓解。
另一个典型问题是连接数增长异常。应用如果使用连接池,理论上连接数应该平稳,但若有连接泄漏,conn 会持续上涨,最终逼近上限后新的请求无法建立连接。可以用 mongostat 的 --json 参数输出 JSON 格式,配合 jq 或脚本定时解析 conn 字段,设置阈值告警。例如:
mongostat --rowcount=1 --host=127.0.0.1 --json
输出为一个 JSON 对象,包含所有字段,脚本可以通过 jq '.conn' 提取当前连接数。虽然 mongostat 本身没有内置告警,但作为数据源接入监控系统非常方便。
mongostat 与 mongotop 的适用边界
有些用户会把 mongostat 和 mongotop 混用,其实两者定位不同。mongostat 展示的是实例级操作计数、内存、网络和队列,适合判断整体健康状态;mongotop 则按集合或命名空间展示读写耗时,适合找出具体哪个集合读写最频繁。如果业务整体变慢,先用 mongostat 看是否存在全局性资源争用;如果只有某个接口慢,再用 mongotop 定位到具体集合,最后用 explain 分析对应查询。
实际排障中可以按顺序执行:先运行 mongostat --rowcount=60 观察一分钟,重点关注 conn、qr、qw、dirty、used 和 netIn、netOut;发现队列长时间堆积后运行 mongotop 查看是哪个集合占用了时间;最后对相关查询执行 explain(executionStats) 检查索引使用情况。这种从整体到局部的方式,比直接猜测某条慢查询更可靠。
最后要提醒的是,mongostat 本身也会产生少量数据库连接和命令开销,虽然非常小,但在极端性能测试中最好把采样间隔调大或使用 --rowcount 控制时长,避免监控工具干扰结果。日常巡检中建议把它和 MongoDB Cloud Manager、Prometheus 等监控体系结合使用,让 mongostat 作为命令行快速排查的补充手段,而不是唯一的监控来源。

