监控Mongo慢查询
监控Mongo慢查询
1. 使用mongostat监控MongoDB全局情况
mongostat是mongdb自带的状态检测工具,在命令行下使用。它会间隔固定时间获取MongoDB的当前运行状态,并输出。
如果你发现数据库突然变慢或者有其他问题的话,你第一手的操作就考虑采用mongostat来查看mongo的状态。
mongostat --host localhost:27017 -uroot -p123456 --authenticationDatabase admin
参数说明:
host:指定IP地址和端口,也可以只写IP,然后使用--port参数指定端口号
-u: 如果开启了认证,则需要在其后填写用户名
-p: 密码
--authenticationDatabase:若开启了认证,则需要在此参数后填写认证库(注意是认证上述账号的数据库)
mongostat输出详解
insert/s : 官方解释是每秒插入数据库的对象数量,如果是slave,则数值前有*,则表示复制集操作
query/s : 每秒的查询操作次数
update/s : 每秒的更新操作次数
delete/s : 每秒的删除操作次数
getmore/s: 每秒查询cursor(游标)时的getmore操作数
command: 每秒执行的命令数,在主从系统中会显示两个值(例如 3|0),分表代表 本地|复制 命令
注: 一秒内执行的命令数比如批量插入,只认为是一条命令(所以意义应该不大)
dirty: 仅仅针对WiredTiger引擎,官网解释是脏数据字节的缓存百分比
used:仅仅针对WiredTiger引擎,官网解释是正在使用中的缓存百分比
flushes:
For WiredTiger引擎:指checkpoint的触发次数在一个轮询间隔期间
For MMAPv1 引擎:每秒执行fsync将数据写入硬盘的次数
注:一般都是0,间断性会是1, 通过计算两个1之间的间隔时间,可以大致了解多长时间flush一次。flush开销是很大的,
如果频繁的flush,可能就要找找原因了
vsize: 虚拟内存使用量,单位MB (这是 在mongostat 最后一次调用的总数据)
res: 物理内存使用量,单位MB (这是 在mongostat 最后一次调用的总数据)
注:这个和你用top看到的一样, vsize一般不会有大的变动, res会慢慢的上升,如果res经常突然下降,去查查是否有别的程序狂吃内存。
qr: 客户端等待从MongoDB实例读数据的队列长度
qw: 客户端等待从MongoDB实例写入数据的队列长度
ar: 执行读操作的活跃客户端数量
aw: 执行写操作的活客户端数量
注:如果这两个数值很大,那么就是DB被堵住了,DB的处理速度不及请求速度。看看是否有开销很大的慢查询。如果查询一切正常,确实是负载很大,就需要加机器了
netIn:MongoDB实例的网络进流量
netOut:MongoDB实例的网络出流量
注:此两项字段表名网络带宽压力,一般情况下,不会成为瓶颈
conn: 打开连接的总数,是qr,qw,ar,aw的总和
注:MongoDB为每一个连接创建一个线程,线程的创建与释放也会有开销,所以尽量要适当配置连接数的启动参数,
maxIncomingConnections,阿里工程师建议在5000以下,基本满足多数场景
set: 副本集的名称
repl: 节点的复制状态
M ---master
SEC ---secondary
REC ---recovering
UNK ---unknown
SLV ---slave
RTR ---mongs process("router')
ARB ---arbiter
2. 使用Profiling捕捉慢查询
类似于MySQL的slow log, mongodb可以监控所有慢的以及不慢的查询。这个工具就是Profiling,该工具在运行的实例上收集有关MongoDB的 写操作,游标,数据库命令等,可以在数据库级别开启该工具,也可以在实例级别开启。该工具会把收集到的所有都写入到system.profile集合中,该集合是一个capped collection。Profiling功能肯定是会影响效率的,但是不太严重,原因是他使用的是system.profile 来记录,而system.profile 是一个capped collection, 这种collection 在操作上有一些限制和特点,但是效率更高。
2.1 慢查询分析过程
1. 设置一个时间阀值,比如200ms
2. 在profiling中(system.profile)找到超过200ms的语句
3. 查看execStats,分析执行计划
4. 根据分析结果,决定是不是需要添加索引
2.2 Profiling基本操作
mongoshell(或者其他客户端比如mongochef等)
#查看状态:级别和时间
PRIMARY> db.getProfilingStatus()
{ "was" : 1, "slowms" : 200 }
#查看级别
PRIMARY> db.getProfilingLevel()
#级别说明:
0:关闭,不收集任何数据。
1:收集慢查询数据,默认是100毫秒。
2:收集所有数据
#设置级别
PRIMARY> db.setProfilingLevel(2)
{ "was" : 1, "slowms" : 100, "ok" : 1 } #这里返回的是上一次的设置
#设置级别和时间
PRIMARY> db.setProfilingLevel(1,200)
{ "was" : 2, "slowms" : 100, "ok" : 1 } #这里返回的是上一次的设置
#关闭Profiling
PRIMARY> db.setProfilingLevel(0)
{ "was" : 1, "slowms" : 200, "ok" : 1 } #这里返回的是上一次的设置
#清空system.profile或者修改大小
#关闭Profiling
PRIMARY> db.setProfilingLevel(0)
{ "was" : 0, "slowms" : 200, "ok" : 1 }
#删除system.profile集合
PRIMARY> db.system.profile.drop()
true
#创建一个新的system.profile集合 --- 4M
PRIMARY> db.createCollection( "system.profile", { capped: true, size:4000000 } )
{ "ok" : 1 }
#重新开启Profiling
PRIMARY> db.setProfilingLevel(1,200)
{ "was" : 0, "slowms" : 200, "ok" : 1 }
#如果是复制集环境,要修改副本的system.profile的大小,必须把副本先从复制集中剔除,然后执行上述步骤,最后加入复制集。
#也可以MongoDB启动时,开启Profiling
mongod --profile=1 --slowms=200
#或者在配置文件里添加
profile = 1
slowms = 200
3. 日常使用的Profiling查询脚本
#返回最近的10条记录
db.system.profile.find().limit(10).sort({ts:-1}).pretty()
#返回所有的操作,除command类型的
db.system.profile.find({op: {$ne:'command'}}).pretty()
#返回特定集合
db.system.profile.find({ns:'mydb.test'}).pretty()
#返回大于5毫秒慢的操作
db.system.profile.find({millis:{$gt:5}}).pretty()
#从一个特定的时间范围内返回信息
db.system.profile.find(
{
ts : {
$gt : new ISODate("2015-10-18T03:00:00Z"),
$lt : new ISODate("2015-10-19T03:40:00Z")
}
}
).pretty()
#特定时间,限制用户,按照消耗时间排序
db.system.profile.find(
{
ts : {
$gt : newISODate("2015-10-12T03:00:00Z") ,
$lt : newISODate("2015-10-12T03:40:00Z")
}
},
{ user : 0 }
).sort( { millis : -1 } )
#查看最新的 Profile 记录:
db.system.profile.find().sort({$natural:-1}).limit(1)
# 显示5个最近的事件
show profile
4. 案例分析
4.1 获取慢查询
#下面的语句过滤几个大表,因为基本无法优化,需要开发改逻辑,所以做了排除,在输出方面只输出了个人认为重要的,方便分析迅速定位
db.system.profile.find({"ns":{"$not":{"$in":["F10data3.f10_4_4_1_gsgg_content", "F10data3.f10_5_1_1_gsyb_content"]}}}, {"ns":1,"op":1, "query":1,"keysExamined":1,"docsExamined":1,"numYield":1, "planSummary":1,"responseLength":1,"millis":1,"execStats":1}).limit(10).sort({ts:-1}).pretty()
#下面是一个超过200ms的查询语句
{
"op" : "query", #操作类型,有insert、query、update、remove、getmore、command
"ns" : "F10data3.f10_2_8_3_jgcc",
"query" : { #具体的查询语句 包括过滤条件,limit行数 排序字段
filter" : {
"jzrq" : {
"$gte" : ISODate("2017-03-31T16:00:00.000+0000"),
"$lte" : ISODate("2017-06-30T15:59:59.000+0000")
},
"jglxfldm" : 10.0
},
"ntoreturn" : 200.0,
"sort" : { #如果有排序 则显示排序的字段 这里是 RsId
"RsId" : 1.0
}
},
"keysExamined" : 0.0, #索引扫描数量 这里是全表扫描,没有用索引 所以是 0
"docsExamined" : 69608.0, #浏览的文档数 这里是全表扫描 所以是整个collection中的全部文档数
"numYield" : 546.0, #该操作为了使其他操作完成而放弃的次数。通常来说,当他们需要访问
还没有完全读入内存中的数据时,操作将放弃。这使得在MongoDB为了
放弃操作进行数据读取的同时,还有数据在内存中的其他操作可以完成。
"locks" : { #锁信息,R:全局读锁;W:全局写锁;r:特定数据库的读锁;w:特定数据库的写锁
"Global" : {
"acquireCount" : {
"r" : NumberLong(1094) #该操作获取一个全局级锁花费的时间。
}
},
"Database" : {
"acquireCount" : {
"r" : NumberLong(547)
}
},
"Collection" : {
"acquireCount" : {
"r" : NumberLong(547)
}
}
},
"nreturned" : 200.0, #返回的文档数量
"responseLength" : 57695.0, #返回字节长度,如果这个数字很大,考虑值返回所需字段
"millis" : 264.0, #消耗的时间(毫秒)
"planSummary" : "COLLSCAN, COLLSCAN", #执行概览 从这里看来 是全表扫描
"execStats" : { #详细的执行计划 这里先略过 后续可以用 explain来具体分析
},
"ts" : ISODate("2017-08-24T02:32:49.768+0000"), #命令执行的时间
"client" : "10.3.131.96", #访问的ip或者主机
"allUsers" : [
],
"user" : ""
}
4.2 分析慢查询
1. 如果发现 millis 值比较大,那么就需要作优化。
2. 如果docsExamined数很大,或者接近记录总数(文档数),那么可能没有用到索引查询,而是全表扫描。
3. 如果keysExamined数为0,也可能是没用索引。
4. 结合 planSummary 中的显示,上例中是 "COLLSCAN, COLLSCAN" 确认是全表扫描
5. 如果 keysExamined 值高于 nreturned 的值,说明数据库为了找到目标文档扫描了很多文档。这时可以考虑创建索引来提高效率。
6. 索引的键值选择可以根据 query 中的输出参考,上例中 filter:包含了 jzrq和jglxfldm 并且按照RsId排序,所以 我们的索引
索引可以这么建: db.f10_2_8_3_jgcc.ensureindex({jzrq:1,jglxfldm:1,RsId:1})
4.3 执行计划中的TYPE类型
COLLSCAN #全表扫描 避免
IXSCAN #索引扫描 可以改进 选用更高效的索引
FETCH #根据索引去检索指定document
SHARD_MERGE #将各个分片返回数据进行merge 尽可能避免跨分片查询
SORT #表明在内存中进行了排序(与老版本的scanAndOrder:true一致) 排序要有index
LIMIT #使用limit限制返回数 要有限制 Limit+(Fetch+ixscan)最优
SKIP #使用skip进行跳过 避免不合理的skip
IDHACK #针对_id进行查询 推荐,_id 默认主键,查询速度快
SHARDING_FILTER #通过mongos对分片数据进行查询 SHARDING_FILTER+ixscan最优
COUNT #利用db.coll.explain().count()之类进行count运算
COUNTSCAN #count不使用Index进行count时的stage返回 避免 这种情况建议加索引
COUNT_SCAN #count使用了Index进行count时的stage返回 推荐
SUBPLA #未使用到索引的$or查询的stage返回 避免
TEXT #使用全文索引进行查询时候的stage返回
PROJECTION #限定返回字段时候stage的返回 选择需要的数据, 推荐PROJECTION+ixscan
监控Mongo慢查询的更多相关文章
- Mongo简单查询总结
mongo 简单查询db.ansheng.findOne()//返回第一条匹配到的数据db.ansheng.findOne({"aaaaa":4})db.ansheng.find( ...
- (ArcGIS API For Silverlight )QueryTask 跨层查询,和监控完整的查询!
(ArcGIS API For Silverlight )QueryTask 跨层查询,和监控完整的查询! 直接在源代码: 定义全局变量: int index=0; /// & ...
- Mongo 应用查询
官网操作手册,基本就够用 https://docs.mongodb.com/manual/ 下面是个分组查询的例子,项目中用到然后查了个例子,自己理解了下,觉得很好很强大. https://blog. ...
- grafana使用Prometheus数据源监控mongo数据库
数据库改用mongo后,监控需求就需要整合进grafana里,由于一直在坚持docker化部署,那么此次也不例外. 1. 安装Prometheus: What is Prometheus? Prome ...
- Zabbix监控Mongo
安装Zabbix-agent # groupadd zabbix # useradd -g zabbix zabbix # yum -y install gcc mysql-community-dev ...
- Mongo常用查询语法
一.查询 find方法 db.collection_name.find(); 查询所有的结果: select * from users; db.users.find(); 指定返回那些列(键): se ...
- SqlProfilter监控指定数据库数据表——监控linq组合查询生成的sql
1.例子 实际测试环境中往往很多测试都在调用数据库,那么如何使用SqlProfilter监控筛选到自己想要监看的数据库对应的表有关linq生成的sql时候就需要做如下设置了 ........... u ...
- mongo 慢查询配置
我是分片部署,所以慢查询相关的配置是在启动片服务上. 执行查询命令,是在share的primary 上. 1. mongodb慢查询 配置 慢查询数据主要存储在 local库的system.pro ...
- Sentry 监控 - Search 搜索查询实战
系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创建版本 快速使用 Docker 上手 Sentry-CLI - 30 秒上手 Source Maps Sentry For ...
随机推荐
- JAM计数法(模拟)
题目描述 Jam是个喜欢标新立异的科学怪人.他不使用阿拉伯数字计数,而是使用小写英文字母计数,他觉得这样做,会使世界更加丰富多彩.在他的计数法中,每个数字的位数都是相同的(使用相同个数的字母),英文字 ...
- 【MAF】MAF插件框架简介
引言 Managed Add-In Framework是一个插件式框架.它有两大作用,一个是解耦,插件和宿主由7个管道组成,两边都有适配器Adapter管道,能最大程度地降低插件和宿主的耦合度: ...
- Arcgis Add-In开发入门实例
作为一个本科侧重于应用,工作之后却做了开发的程序员来说,做GIS,开发应该是一门必修课,只是,苦于各种原因吧,做GIS应用的人会开发的很少,做GIS开发的大部分都是计算机出身,痛心疾首啊-- 不好意思 ...
- Tinker爬坑之路
目的 热修复去年年底出的时候,变成了今年最火的技术之一.依旧记得去年面试的时候统一的MVP,然而今年却变成了RN,热修复.这不得不导致我们需要随时掌握最新的技术.不然可能随时会被淘汰.记得刚进公司,技 ...
- Matisse,来自知乎的PhotoPicker
简介 Matisse,是一款由知乎开源的媒体选择器. 在Activity和Fragment中使用 支持JPEG,PNG,GIF的图片选择和MPEG,MP4格式的视频选择.不能同时选择图片和视频 两种主 ...
- ubuntu 设置plank开机自启之后关机键失效变为注销键
之前因为猎奇心,给我的ubuntu系统换了一个macUbuntu的桌面,但是之前用的dock是docky,昨日闲来无聊换成了plank,设置成然后就发现我的系统关不了机了,只能通过指令关机. 百度之后 ...
- 【1】基于quartz框架和Zookeeper实现集群化定时任务系统
(1)quartz本身可以支持集群化,是基于数据库做协调,现在构想基于zookeeper做协调实现集群化定时系统 流程图如下:
- 2.2 web工程的目录结构
[转] 一个最简单的Web应用的目录结构如下所示: Web应用的结构定义在Servlet的规范中,目前最新版本为3.1. 下载地址:https://jcp.org/aboutJava/communit ...
- Yii 一些小的问题
是否验证 ======================= $model->save()执行时,如何不要验证? 我用的是表单模型,表单模型已经验证了,保存时不想用表模型验证,如何不让表模型验证.也 ...
- 简述负载均衡和 CDN 技术
曾经见到知乎上有人问“为什么像facebook这类的网站需要上千个工程师维护?”,下面的回答多种多样,但总结起来就是:一个高性能的web系统需要从无数个角度去考虑他,大到服务器的布局,小到软件中某个文 ...