MongoDB自带了 mongostat 和 mongotop 这两个命令来监控 MongoDB的运行情况。这两个命令对于我们处
理 MongoDB数据库变慢等等问题非常有用,能详细的统计 MongoDB当前的状态信息。 通过 mongostat 工具 可以查看 mongodb实例每秒读写数、执行命令、读写等待队列数、活跃读写命令、网络吞吐、连接数等性能指 标。下面我们来具体看下 mongostat的用法。
一、问题诊断工具 - mongostat¶

1、参数说明
host:指定 IP地址和端口,也可以只写 IP,然后使用 port参数指定端口号 -u: 如果开启了认证,则需要在其后填写用户名
-p: 密码
2、命令:
$ /data/download/mongodb-database-tools/bin/mongostat --host 192.168.1.153 --port=27017 -uroot -p000000 --authenticationDatabase=admin
insert query update delete getmore command dirty used flushes vsize res qrw arw net_in net_out conn time
*0 *0 *0 *0 0 0|0 0.0% 1.2% 0 1.61G 109M 0|0 0|0
110b 55.8k 4 Oct 16 20:13:45.962
*0 *0 *0 *0 0 1|0 0.0% 1.2% 0 1.61G 109M 0|0 0|0
112b 56.5k 4 Oct 16 20:13:46.959
*0 *0 *0 *0 0 1|0 0.0% 1.2% 0 1.61G 109M 0|0 0|0
112b 56.7k 4 Oct 16 20:13:47.953
3、参数说明:
insert/s : 官方解释是每秒插入数据库的对象数量,如果是 slave,则数值前有 *,则表示复制集操作
query/s : 每秒的查询操作次数
update/s : 每秒的更新操作次数
delete/s : 每秒的删除操作次数
getmore/s: 每秒查询 cursor(游标 )时的 getmore操作数
command: 每秒执行的命令数,在主从系统中会显示两个值 (例如 3|0),分表代表 本地 |复制 命令 dirty:内存中的脏⻚数量百分比。默认在 5%以下,每分钟在后台刷盘;超过 5%后台进程频繁刷盘,超过 20% 会阻止新请求。
used:分配给 mongodb的内存使用的百分比。低于 80%,不会触发内存回收 ,超过 80%,触发 LRU回收内存,默
认超过 95%会阻止新请求。
flushes:
For WiredTiger引擎:指 checkpoint的触发次数在一个轮询间隔期间
For MMAPv1 引擎:每秒执行 fsync将数据写入硬盘的次数
注:一般都是 0,间断性会是 1, 通过计算两个 1之间的间隔时间,可以大致了解多⻓时间 flush一次。 flush开销是很大的,如果频繁的 flush,可能就要找找原因了
vsize: 虚拟内存使用量,单位 MB (这是 在 mongostat 最后一次调用的总数据)
res: 物理内存使用量,单位 MB (这是 在 mongostat 最后一次调用的总数据)
注:这个和用 top看到的一样 , vsize一般不会有大的变动, res会慢慢的上升,如果 res经常突然下 降,去查查是否有别的程序狂吃内存。
qrw: 客户端等待从 MongoDB实例读写数据的队列⻓度
arw: 执行读写操作的活跃客户端数量
注:如果这两个数值很大,那么就是 DB被堵住了, DB的处理速度不及请求速度。看看是否有开销很大的慢 查询。如果查询一切正常,确实是负载很大,就需要加机器了
netIn:MongoDB实例的网络进流量
netOut: MongoDB实例的网络出流量
注:此两项字段表名网络带宽压力,一般情况下,不会成为瓶颈
conn: 打开连接的总数,是 qr,qw,ar,aw的总和
注: MongoDB为每一个连接创建一个线程,线程的创建与释放也会有开销,所以尽量要适当配置连接数的启动
参数, maxIncomingConnections,建议在 5000以下,基本满足多数场景
4、主要关注点:
dirty:
内存中的脏⻚数量百分比。默认在 5%以下,每分钟在后台刷盘;超过 5%后台进程频繁刷盘,超过 20 %会阻止 新请求。
used:
分配给 mongodb的内存使用的百分比。低于 80%,不会触发内存回收 ,超过 80%,触发 LRU回收内存,默认超过 95%会阻止新请求。
qrw: 排队的请求数量,超过 10以上,需要关注下积压的操作是什么(慢查询、锁等)。
二、问题诊断工具 - mongotop¶

通过 mongotop 查看 mongodb 实例中热点表读写情况,该监控工具将按照请求时间从大到小进行排序的前 10个表的请求消耗时间打印出来。
mongotop提供每个集合的统计数据。默认情况下, mongotop每一秒刷新一次。
1、命令
$ /data/download/mongodb-database-tools/bin/mongotop --host 192.168.1.153 --port=27017 -uroot -p000000 --authenticationDatabase=admin
ns total read write 2024-08-11T20:20:39+08:00
admin.system.users 0ms 0ms 0ms
admin.system.version 0ms 0ms 0ms
app.a 0ms 0ms 0ms
app.c 0ms 0ms 0ms
app.fruit 0ms 0ms 0ms
app.log 0ms 0ms 0ms
app.log1 0ms 0ms 0ms
app.log2 0ms 0ms 0ms
app.system.users 0ms 0ms 0ms
config.system.sessions 0ms 0ms 0ms
2、输出字段说明
ns:数据库命名空间,后者结合了数据库名称和集合。
total: mongod在这个命令空间上花费的总时间。 read:在这个命令空间上 mongod执行读操作花费的时间。 write:在这个命名空间上 mongod进行写操作花费的时间。
根据 二八定理,我们可以选择对于占用请求时间超过 80%的热表慢查询进行针对性的性能分析和优化。那么如何开启慢日志并查看呢?
三、问题诊断 – mongod 慢日志¶
1、开启 mongoDB慢日志 profile
启用 profile时,对数据库性能是有影响的(profile=2/1). profile还会消耗哈磁盘空间,因为它记录到 2个地方:system.profile集合和 mongo的系统日志
(1) Profiling级别:
0:关闭,不收集任何数据。
1:收集慢查询数据,默认是 100毫秒。
2:收集所有数据
2、慢日志配置方法:
方法一:启动命令行
启动 MongoDB时加上--profile=级别
方法二:配置文件
operationProfiling:
mode: slowOp
slowOpThresholdMs: 10
方法三:在线配置
> db.setProfilingLevel(<level>, <options>);
db.setProfilingLevel(2); //设置 Profiling级别
db.setProfilingLevel( 1 , 10 ); //设置 Profiling级别和慢查询收集阈值
使用方法:
- level :integer类型,配置数据库 profiler级别,支持 0,1,2
- options: document or integer, 可选的,接受 document or integer。如果将整数值作为 options参数而不是文档作为参数传递,则该值将分配给 slowms。
3、查询 Profiling 记录
(1) db.system.profile.find( { info: /test.foo/ } ) //查看 info包含 test.foo 的记录
(2) db.system.profile.find( { millis : { $gt : 100 } } ) //列出执行时间⻓于某一限度 (100ms)的 Profile记录
(3) db.system.profile.find().limit(10).sort( { ts : -1 } ) //查看最新 10条的 Profile 记录
(4) show profile //可列出最近 5条执行时间超过 1ms的 Profile 记录
(5) 返回某个时间范围的慢操作信息:
db.system.profile.find({
ts : {
$gt: new ISODate("2024-08-01T10:00:00Z"),
$lt: new ISODate("2024-08-03T11:00:00Z")
}
}).pretty()
4、mongod日志中的慢日志
说明: mongod的日志也会记录慢日志信息,会更加详细。如下图的例子。
慢查询日志解析备注:
{
"timestamp": "2024–08–01T11:20:30.775+0800" // 日期和时间, ISO8601格式
"severityLevel": "I" // 日志级别 I代表info的意思,其他的还有F,E,W,D等
"components": "COMMAND" //组件类别,不同组件打印出的日志带不同的标签,便于日志分类
"namespace": "test.test" //查询的命名空间,即 <databse.collection>
"operation": "find" //操作类别,可能是 [find,insert,update,remove,getmore,command]
"command": { find: "test", filter: { i:10000.0 },$db:"test"} //具体的操作命令细节
"planSummary": "COLLSCAN", //命令执行计划的简要说明,当前果是全表扫描, 如果是IXSCAN { lv: -1 },则是使用了 lv 这个字段的索引
"keysExamined": 0, // 该项表明为了找出最终结果MongoDB搜索了索引中的多少个key
"docsExamined": 27108, // 该项表明为了找出最终结果MongoDB搜索了多少个文档
"cursorExhausted": 1, // 该项表明本次查询中游标耗尽的次数
"keyUpdates":0, // 该项表名有多少个index key在该操作中被更改,更改索引键也会有少量的性能消耗,因为数据库不单单要删除旧Key,还要插入新的Key到B-Tree索引中
"writeConflicts":0, // 写冲突发生的数量,例如update一个正在被别的update操作的文档
"numYields":211, // 为了让别的操作完成而屈服的次数,一般发生在需要访问的数据尚未被完全读取到内存中,MongoDB会优先完成在内存中的操作
"nreturned":1, // 该操作最终返回文档的数量
"reslen":243, // 结果返回的大小,单位为bytes,该值如果过大,则需考虑limit()等方式减少输出结果
"locks": { // 在操作中产生的锁,锁的种类有多种,如下
Global: { acquireCount: { r: 424 } }, //具体每一种锁请求锁的次数
Database: { acquireCount: { r: 212 } },
Collection: { acquireCount: { r: 212 } }
},
"protocol": "op_command", // 消息的协议
"millis" : 19ms, // 从 MongoDB 操作开始到结束耗费的时间,单位为 ms
}
(如果开启慢查询,默认 100毫秒以上的查询 mongodb会写入慢查询 log)。
