1)慢查询
2)阻塞等待
3)硬件资源不足
1,2通常是因为模型/索引设计不佳导致的。
排查思路:按1-2-3依次排查。
从版本 4.0 开始,MongoDB 为独立实例和复制集提供免费的云监控。免费监控提供有关部署的信息,包括:
# 启用监控
db.enableFreeMonitoring()
# 禁止监控
db.disableFreeMonitoring()
# 获取监控信息
db.getFreeMonitoringStatus()
mongostat 是 MongoDB 自带的监控工具,其可以提供数据库节点或者整个集群当前的状态视图。该功能的设计非常类似于 Linux 系统中的 vmstat 命令,可以呈现出实时的状态变化。不同的是,mongostat 所监视的对象是数据库进程。mongostat 常用于查看当前的 QPS/内存使用/连接数,以及多个分片的压力分布。mongostat 采用 Go 语言实现,其内部使用了db.serverStatus()
命令,要求执行用户需具备 clusterMonitor 角色权限。
mongostat -h 192.168.65.174 --port 28017 -ufirechou -pfirechou --authenticationDatabase=admin --discover -n 300 2
参数说明:
-h:指定监听的主机,分片集群模式下指定到一个 mongos 实例,也可以指定单个 mongod,或者复制集的多个节点。
–port:接入的端口,如果不提供则默认为 27017。
-u:接入用户名,等同于-user。
-p:接入密码,等同于-password。
–authenticationDatabase:鉴权数据库。
–discover:启用自动发现,可展示集群中所有分片节点的状态。
-n 300 2:表示输出300次,每次间隔2s。也可以不指定“-n 300”,此时会一直保持输出。
指标说明:
指标名 | 说明 |
---|---|
inserts | 每秒插入数 |
query | 每秒查询数 |
update | 每秒更新数 |
delete | 每秒删除数 |
getmore | 每秒 getmore 数 |
command | 每秒命令数,涵盖了内部的一些操作 |
%dirty | WiredTiger 缓存中脏数据百分比 |
%used | WiredTiger 正在使用的缓存百分比 |
flushes | WiredTiger 执行 CheckPoint 的次数 |
vsize | 虚拟内存使用量 |
res | 物理内存使用量 |
qrw | 客户端读写等待队列数量,高并发时,一般队列值会升高 |
arw | 客户端读写活跃个数 |
netIn | 网络接收数据量 |
netOut | 网络发送数据量 |
conn | 当前连接数 |
set | 所属复制集名称 |
repl | 复制节点状态(主节点/二级节点……) |
time | 时间戳 |
mongostat 需要关注的指标主要有如下几个:
使用交互模式:
mongostat 一般采用滚动式输出,即每一个间隔后的状态数据会被追加到控制台中。从 MongoDB 3.4 开始增加了--interactive
选项,用来实现非滚动式的监视,非常方便。
mongostat -h 192.168.65.174 --port 28017 -ufirechou -pfirechou --authenticationDatabase=admin --discover --interactive -n 2
mongotop 命令可用于查看数据库的热点表,通过观察 mongotop 的输出,可以判定是哪些集合占用了大部分读写时间。mongotop 与 mongostat 的实现原理类似,同样需要 clusterMonitor 角色权限。
mongotop -h 192.168.65.174 --port=28017 -ufirechou -pfirechou --authenticationDatabase=admin
默认情况下,mongotop 会持续地每秒输出当前的热点表。
指标说明:
指标名 | 说明 |
---|---|
ns | 集合名称空间 |
total | 花费在该集合上的时长 |
read | 花费在该集合上的读操作时长 |
write | 花费在该集合上的写操作时长 |
mongotop 通常需要关注的因素主要包括:
mongotop 的统计周期、输出总量都是可以设定的。
# 最多输出100次,每次间隔时间为2s
mongotop -h 192.168.65.174 --port=28017 -ufirechou -pfirechou --authenticationDatabase=admin -n 100 2
Profiler 模块可以用来记录、分析 MongoDB 的详细操作日志。默认情况下该功能是关闭的,对某个业务库开启 Profiler 模块之后,符合条件的慢操作日志会被写入该库的system.profile
集合中。Profiler 的设计很像代码的日志功能,其提供了几种调试级别:
级别 | 说明 |
---|---|
0 | 日志关闭,无任何输出 |
1 | 部分开启,仅符合条件(时长大于slowms)的操作日志会被记录 |
2 | 日志全开,所有的操作日志都被记录 |
对当前的数据库开启 Profiler 模块:
# 将level设置为2,此时所有的操作会被记录下来。
db.setProfilingLevel(2)
# 检查是否生效
db.getProfilingStatus()
如果希望只记录时长超过 500ms 的操作,则可以将 level 设置为 1:
db.setProfilingLevel(1,500)
还可以进一步设置随机采样的比例:
db.setProfilingLevel(1,{slowms:500,sampleRate:0.5})
查看操作日志
开启 Profiler 模块之后,可以通过system.profile
集合查看最近发生的操作日志
db.system.profile.find().limit(5).sort({ts:-1}).pretty()
这里需要关注的一些字段主要如下所示:
{db}.{collection}
。根据这些字段,可以执行一些不同维度的查询。比如查看执行时长最大的 10 条操作记录查看某个集合中的 update 操作日志
db.system.profile.find().limit(10).sort({millis:-1}).pretty()
查看某个集合中的 update 操作日志
db.system.profile.find({op:"update",ns:"shop.user"})
注意事项
system.profile
是一个 1MB 的固定大小的集合,随着记录日志的增多,一些旧的记录会被滚动删除。Profiler 模块所记录的日志都是已经发生的事情,db.currentOp()
命令则与此相反,它可以用来查看数据库当前正在执行的一些操作。想象一下,当数据库系统的 CPU 发生骤增时,我们最想做的无非是快速找到问题的根源,这时db.currentOp
就派上用场了。db.currentOp()
读取的是当前数据库的命令快照,该命令可以返回许多有用的信息,比如:
对示例操作的解读如下:
(1)从 ns、op 字段获知,当前进行的操作正在对test.items
集合执行 update 命令。
(2)command 字段显示了其原始信息。其中,command.q
和command.u
分别展示了 update 的查询条件和更新操作。
(3)"planSummary":"COLLSCAN"
说明情况并不乐观,update 没有利用索引而是正在全表扫描。
(4)microsecs_running:NumberLong(186070)
表示操作运行了 186ms,注意这里的单位是微秒。
优化方向:
opid 表示当前操作在数据库进程中的唯一编号。如果已经发现该操作正在导致数据库系统响应缓慢,则可以考虑将其“杀”死。
db.killOp(4001)
db.currentOp
默认输出当前系统中全部活跃的操作,由于返回的结果较多,我们可以指定一些过滤条件:
db.currentOp({
waitingForLock:true,
$or:[
{op:{$in:["insert","update","remove"]}},
{"query.findandmodify":{$exists:true}}
]
})
db.currentOp({
secs_running:{$gt:1}
})
db.currentOp({
ns:/test/
})
currentOp命令输出说明:
currentOp.type:操作类型,可以是 op、idleSession、idleCursor 的一种,一般的操作信息以 op 表示。其为 MongoDB 4.2 版本新增功能。
currentOp.host:主机的名称。currentOp.desc:连接描述,包含 connectionId。
urrentOp.connectionId:客户端连接的标识符。
currentOp.client:客户端主机和端口。
currentOp.appName:应用名称,一般是描述客户端类型。
currentOp.clientMetadata:关于客户端的附加信息,可以包含驱动的版本。
currentOp.currentOpTime:操作的开始时间。MongoDB 3.6 版本新增功能。
currentOp.lsid:会话标识符。MongoDB 3.6 版本新增功能。
currentOp.opid:操作的标志编号。
currentOp.active:操作是否活跃。如果是空闲状态则为 false。
currentOp.secs_running:操作持续时间(以秒为单位)。
currentOp.microsecs_running:操作持续时间(以微秒为单位)。
currentOp.op:标识操作类型的字符串。可能的值是:“none” “update” “insert”“query”“command” “getmore” “remove” “killcursors”。其中,command操作包括大多数命令,如createIndexes和findAndModify。
currentOp.ns:操作目标的集合命名空间。
currentOp.command:操作的完整命令对象的文档。如果文档大小超过 1KB,则会使用一种 $truncate 形式表示。
currentOp.planSummary:查询计划的概要信息。
currentOp.locks:当前操作持有锁的类型和模式。
currentOp.waitingForLock:是否正在等待锁。
currentOp.numYields:当前操作执行 yield(让步)的次数。一些锁互斥或者磁盘 I/O 读取都会导致该值大于 0。
currentOp.lockStats:当前操作持有锁的统计。
currentOp.lockStats.acquireCount:操作以指定模式获取锁的次数。
currentOp.lockStats.acquireWaitCount:操作获取锁等待的次数,等待是因为锁处于冲突模式。acquireWaitCount 小于或等于 acquireCount。
currentOp.lockStats.timeAcquiringMicros:操作为了获取锁所花费的累积时间(以微秒为单位)。timeAcquiringMicros 除以 acquireWaitCount 可估算出平均锁等待时间。
currentOp.lockStats.deadlockCount:在等待锁获取时,操作遇到死锁的次数。
注意事项:
local.oplog.rs
),需要做一些筛选。