一. 关键指标
- 慢查询:当MongoDB处理能力不足时,找出系统中的慢查询,分析原因,看能否通过建立索引或重新设计schema改进
- 内存使用:MongoDB吃内存(特别是MMAPv1),至少要给MongoDB足够的内存存放索引,最理想的情况是能够存放所有数据。当内存占用过高,或者page faults过高时,考虑能不能给MongoDB预留更多的内存。
- 磁盘占用:特别是对于MMAPv1,涉及到磁盘占用的因素有很多,不合理的schema(文档频繁移动)或集合/文档的删除都可能会导致磁盘空间利用不足。前期需要设计好schema,后期维护也需要定期整理磁盘数据。
- 连接数:MongoDB为每个连接分配一个线程,因此连接是占资源的,并且也不是越多连接越好。合理地控制连接数。
- 索引不命中:查看所有查询的索引不命中情况,尽量让所有查询都通过索引
- 锁等待:锁等待的原因有很多,连接数过多,操作频繁,慢操作,schema设计过于反范式化等,可从上面的原因针对性解决。
二. 监控工具
1. mongostat
mongodb自带的状态检测工具,按照固定时间间隔(默认1s)获取mongodb的当前运行状态,适用于对临时异常状态的监控:
// from MongoDB 3.0 MMAPv1
▶ mongostat
insert query update delete getmore command flushes mapped vsize res faults qr|qw ar|aw netIn netOut conn time
*0 40 1 *0 0 1|0 0 4.3G 11.1G 150.0M 0 0|0 0|0 2k 12k 201 19:07:04
*0 20 *0 *0 0 1|0 0 4.3G 11.1G 150.0M 0 0|0 0|0 1k 11k 201 19:07:05
*0 *0 1 *0 0 1|0 0 4.3G 11.1G 150.0M 0 0|0 0|0 244b 10k 201 19:07:06
*0 20 *0 *0 0 1|0 0 4.3G 11.1G 150.0M 0 0|0 0|0 1k 11k 201 19:07:07
*0 20 *0 *0 0 2|0 0 4.3G 11.1G 150.0M 0 0|0 0|0 1k 11k 201 19:07:08
具体各列的意义都很简单,见官方文档即可。比较重要的字段有:
- res: 常驻内存大小
- mapped: 通过mmap映射数据所占用虚拟内存大小(只对MMAPv1有效)
- vsize: mongodb进程占用的虚拟内存大小
- faults: page fault次数,如果持续过高,则可以考虑加内存
- qr/qw: 读取/写入等待队列的大小,如果队列很大,表示MongoDB处理能力跟不上,可以看看是否存在慢操作,或者减缓请求
- conn: 当前连接数,conn也会占用MongoDB资源,合理控制连接数
- idx miss: 索引不命中所占百分比 如果太高则要考虑索引是否设计得不合理
- flushes: 通常为0或1,对于MMAPv1,表示后台刷盘次数(默认60s),对于WiredTiger,表示执行checkpoint次数(默认60s或2GB journal日志)
- lr/lw: 读取/写入操作等待锁的比例 (New In MongoDB 3.2, Only for MMapv1)
- lrt/lwt: 读取/写入锁的平均获取时间(微妙)
更多参考。
2. db.serverStatus()
返回数据库服务器信息,该命令返回的数据量很大,但执行很快,不会对数据库性能造成影响,其中比较重要的字段有:
- db.serverStatus().mem: 当前数据库内存使用情况
- db.serverStatus().connections: 当前数据库服务器的连接情况
- db.serverStatus().extra_info: 在Linux下,包含page fault次数
- db.serverStatus().locks: 数据库各种类型锁竞态情况
- db.serverStatus().backgroundFlushing: 数据库后台刷盘情况(默认60s)一次,仅针对MMAPv1存储引擎
更多参考。
3. Profiler
主要用于分析查询性能,默认是关闭的,Profiler获取关于查询/写入/命令等操作的详细执行数据,并将这些分析数据写入system.profile集合。Profiler有三个Level:
- Level 0: 意味着关闭Profiler,并不收集任何数据,也是mongod的默认配置。注意mongod总是会将”慢操作”(执行时间超过slowOpThresholdMs,默认100ms)的操作写入mongod日志(不是system.profile集合)
- Level 1: 只收集所有慢操作的信息,慢操作执行时间可通过修改slowOpThresholdMs参数指定
- Level 2: 收集所有的数据库操作执行信息
需要注意,一个操作执行慢,可能是索引不合理,也可能是page fault从磁盘读数据等原因导致。需要进一步分析。
使用示例:
> db.setProfilingLevel(2)
{ "was" : 0, "slowms" : 100, "ok" : 1 }
>
> db.getProfilingStatus()
{ "was" : 2, "slowms" : 100 }
> db.user.insert({"name":"wdj"})
WriteResult({ "nInserted" : 1 })
> db.system.profile.find()
{ "op" : "insert", "ns" : "test.user", "query" : { "insert" : "user", "documents" : [ { "_id" : ObjectId("577e62991fa7b960bb8bf0af"), "name" : "wdj" } ], "ordered" : true }, "ninserted" : 1, "keyUpdates" : 0, "writeConflicts" : 0, "numYield" : 0, "locks" : { "Global" : { "acquireCount" : { "r" : NumberLong(2), "w" : NumberLong(2) } }, "Database" : { "acquireCount" : { "w" : NumberLong(1), "W" : NumberLong(1) } }, "Collection" : { "acquireCount" : { "w" : NumberLong(1), "W" : NumberLong(1) } } }, "responseLength" : 25, "protocol" : "op_command", "millis" : 32, "execStats" : { }, "ts" : ISODate("2016-07-07T14:09:29.690Z"), "client" : "127.0.0.1", "allUsers" : [ ], "user" : "" }
>
system.profile集合中,关键字段:op(操作类型), ns(操作集合), ts(操作时间),millis(执行时间ms),query(操作详情)。
更多参考。
4. db.currentOp()
当MongoDB比较繁忙或者在执行比较慢的命令时,可能会阻塞之后的操作(视数据库和操作的并发级别而定)。可通过db.currentOp()来获取当前正在进行的操作,并可通过db.killOp()来干掉它。
更多参考。
5. db.stats()
返回对应数据库的信息,包括集合数量,文档总大小,文档平均大小,索引数量,索引大小等静态信息:
> db.stats()
{
"db" : "test",
"collections" : 2,
"objects" : 3,
"avgObjSize" : 430,
"dataSize" : 1290,
"storageSize" : 49152,
"numExtents" : 0,
"indexes" : 1,
"indexSize" : 16384,
"ok" : 1
}
>
更多参考。
6. db.collStats()
返回集合详细信息.
更多参考。
7. db.enableFreeMonitoring
Mongo官方提供的免费监视服务,可以脱离altas云服务独立使用,db.enableFreeMonitoring()
会返回一个URL地址,上面有包含MongoDB内存,CPU,读写,网络,磁盘等全方位的可视化监控。