监控Mongo慢查询

监控Mongo慢查询

1. 使用mongostat监控MongoDB全局情况

  1.  
    mongostat是mongdb自带的状态检测工具,在命令行下使用。它会间隔固定时间获取MongoDB的当前运行状态,并输出。
  2.  
    如果你发现数据库突然变慢或者有其他问题的话,你第一手的操作就考虑采用mongostat来查看mongo的状态。
  3.  
     
  4.  
    mongostat --host localhost:27017 -uroot -p123456 --authenticationDatabase admin
  5.  
    参数说明:
  6.  
    host:指定IP地址和端口,也可以只写IP,然后使用 --port参数指定端口号
  7.  
    -u: 如果开启了认证,则需要在其后填写用户名
  8.  
    -p: 密码
  9.  
    --authenticationDatabase:若开启了认证,则需要在此参数后填写认证库(注意是认证上述账号的数据库)

mongostat输出详解
  1.  
    insert/s : 官方解释是每秒插入数据库的对象数量,如果是slave,则数值前有*,则表示复制集操作
  2.  
    query/s : 每秒的查询操作次数
  3.  
    update/s : 每秒的更新操作次数
  4.  
    delete/s : 每秒的删除操作次数
  5.  
    getmore/s: 每秒查询 cursor(游标)时的getmore操作数
  6.  
    command: 每秒执行的命令数,在主从系统中会显示两个值(例如 3|0),分表代表 本地|复制 命令
  7.  
    注: 一秒内执行的命令数比如批量插入,只认为是一条命令(所以意义应该不大)
  8.  
    dirty: 仅仅针对WiredTiger引擎,官网解释是脏数据字节的缓存百分比
  9.  
    used:仅仅针对WiredTiger引擎,官网解释是正在使用中的缓存百分比
  10.  
    flushes:
  11.  
    For WiredTiger引擎:指checkpoint的触发次数在一个轮询间隔期间
  12.  
    For MMAPv1 引擎:每秒执行fsync将数据写入硬盘的次数
  13.  
    注:一般都是 0,间断性会是1, 通过计算两个1之间的间隔时间,可以大致了解多长时间flush一次。flush开销是很大的,
  14.  
    如果频繁的 flush,可能就要找找原因了
  15.  
    vsize: 虚拟内存使用量,单位MB (这是 在mongostat 最后一次调用的总数据)
  16.  
    res: 物理内存使用量,单位MB (这是 在mongostat 最后一次调用的总数据)
  17.  
    注:这个和你用top看到的一样, vsize一般不会有大的变动, res会慢慢的上升,如果res经常突然下降,去查查是否有别的程序狂吃内存。
  18.  
     
  19.  
    qr: 客户端等待从MongoDB实例读数据的队列长度
  20.  
    qw: 客户端等待从MongoDB实例写入数据的队列长度
  21.  
    ar: 执行读操作的活跃客户端数量
  22.  
    aw: 执行写操作的活客户端数量
  23.  
    注:如果这两个数值很大,那么就是DB被堵住了,DB的处理速度不及请求速度。看看是否有开销很大的慢查询。如果查询一切正常,确实是负载很大,就需要加机器了
  24.  
    netIn:MongoDB实例的网络进流量
  25.  
    netOut:MongoDB实例的网络出流量
  26.  
    注:此两项字段表名网络带宽压力,一般情况下,不会成为瓶颈
  27.  
    conn: 打开连接的总数,是qr,qw,ar,aw的总和
  28.  
    注:MongoDB为每一个连接创建一个线程,线程的创建与释放也会有开销,所以尽量要适当配置连接数的启动参数,
  29.  
    maxIncomingConnections,阿里工程师建议在 5000以下,基本满足多数场景
  30.  
    set: 副本集的名称
  31.  
    repl: 节点的复制状态
  32.  
    M ---master
  33.  
    SEC ---secondary
  34.  
    REC ---recovering
  35.  
    UNK ---unknown
  36.  
    SLV ---slave
  37.  
    RTR ---mongs process("router')
  38.  
    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.  
    1. 设置一个时间阀值,比如200ms
  2.  
    2. 在profiling中(system.profile)找到超过200ms的语句
  3.  
    3. 查看execStats,分析执行计划
  4.  
    4. 根据分析结果,决定是不是需要添加索引
2.2 Profiling基本操作

mongoshell(或者其他客户端比如mongochef等)
#查看状态:级别和时间
PRIMARY> db.getProfilingStatus()
{ "was" : 1, "slowms" : 200 }

  1.  
    #查看级别
  2.  
    PRIMARY> db.getProfilingLevel()
  3.  
     
  4.  
    #级别说明:
  5.  
    0:关闭,不收集任何数据。
  6.  
    1:收集慢查询数据,默认是100毫秒。
  7.  
    2:收集所有数据
  8.  
     
  9.  
    #设置级别
  10.  
    PRIMARY> db.setProfilingLevel( 2)
  11.  
    { "was" : 1, "slowms" : 100, "ok" : 1 } #这里返回的是上一次的设置
  12.  
     
  13.  
    #设置级别和时间
  14.  
    PRIMARY> db.setProfilingLevel( 1,200)
  15.  
    { "was" : 2, "slowms" : 100, "ok" : 1 } #这里返回的是上一次的设置
  16.  
     
  17.  
    #关闭Profiling
  18.  
    PRIMARY> db.setProfilingLevel( 0)
  19.  
    { "was" : 1, "slowms" : 200, "ok" : 1 } #这里返回的是上一次的设置
  20.  
     
  21.  
     
  22.  
    #清空system.profile或者修改大小
  23.  
    #关闭Profiling
  24.  
    PRIMARY> db.setProfilingLevel( 0)
  25.  
    { "was" : 0, "slowms" : 200, "ok" : 1 }
  26.  
    #删除system.profile集合
  27.  
    PRIMARY> db.system.profile.drop()
  28.  
    true
  29.  
    #创建一个新的system.profile集合 --- 4M
  30.  
    PRIMARY> db.createCollection( "system.profile", { capped: true, size:4000000 } )
  31.  
    { "ok" : 1 }
  32.  
    #重新开启Profiling
  33.  
    PRIMARY> db.setProfilingLevel( 1,200)
  34.  
    { "was" : 0, "slowms" : 200, "ok" : 1 }
  35.  
     
  36.  
    #如果是复制集环境,要修改副本的system.profile的大小,必须把副本先从复制集中剔除,然后执行上述步骤,最后加入复制集。
  37.  
     
  38.  
    #也可以MongoDB启动时,开启Profiling
  39.  
    mongod --profile= 1 --slowms=200
  40.  
    #或者在配置文件里添加
  41.  
    profile = 1
  42.  
    slowms = 200

3. 日常使用的Profiling查询脚本

  1.  
    #返回最近的10条记录
  2.  
    db. system.profile.find().limit(10).sort({ts:-1}).pretty()
  3.  
    #返回所有的操作,除command类型的
  4.  
    db. system.profile.find({op: {$ne:'command'}}).pretty()
  5.  
    #返回特定集合
  6.  
    db. system.profile.find({ns:'mydb.test'}).pretty()
  7.  
    #返回大于5毫秒慢的操作
  8.  
    db. system.profile.find({millis:{$gt:5}}).pretty()
  9.  
    #从一个特定的时间范围内返回信息
  10.  
    db. system.profile.find(
  11.  
    {
  12.  
    ts : {
  13.  
    $gt : new ISODate( "2015-10-18T03:00:00Z"),
  14.  
    $lt : new ISODate( "2015-10-19T03:40:00Z")
  15.  
    }
  16.  
    }
  17.  
    ).pretty()
  18.  
    #特定时间,限制用户,按照消耗时间排序
  19.  
    db. system.profile.find(
  20.  
    {
  21.  
    ts : {
  22.  
    $gt : newISODate( "2015-10-12T03:00:00Z") ,
  23.  
    $lt : newISODate( "2015-10-12T03:40:00Z")
  24.  
    }
  25.  
    },
  26.  
    { user : 0 }
  27.  
    ). sort( { millis : -1 } )
  28.  
    #查看最新的 Profile 记录:
  29.  
    db. system.profile.find().sort({$natural:-1}).limit(1)
  30.  
    # 显示5个最近的事件
  31.  
    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()

  1.  
    #下面是一个超过200ms的查询语句
  2.  
    {
  3.  
    "op" : "query", #操作类型,有insert、query、update、remove、getmore、command
  4.  
    "ns" : "F10data3.f10_2_8_3_jgcc",
  5.  
    "query" : { #具体的查询语句 包括过滤条件,limit行数 排序字段
  6.  
    filter " : {
  7.  
    "jzrq" : {
  8.  
    "$gte" : ISODate("2017-03-31T16:00:00.000+0000"),
  9.  
    "$lte" : ISODate("2017-06-30T15:59:59.000+0000")
  10.  
    },
  11.  
    "jglxfldm" : 10.0
  12.  
    },
  13.  
    "ntoreturn" : 200.0,
  14.  
    "sort" : { #如果有排序 则显示排序的字段 这里是 RsId
  15.  
    "RsId" : 1.0
  16.  
    }
  17.  
    },
  18.  
    "keysExamined" : 0.0, #索引扫描数量 这里是全表扫描,没有用索引 所以是 0
  19.  
    "docsExamined" : 69608.0, #浏览的文档数 这里是全表扫描 所以是整个collection中的全部文档数
  20.  
    "numYield" : 546.0, #该操作为了使其他操作完成而放弃的次数。通常来说,当他们需要访问
  21.  
    还没有完全读入内存中的数据时,操作将放弃。这使得在MongoDB为了
  22.  
    放弃操作进行数据读取的同时,还有数据在内存中的其他操作可以完成。
  23.  
    "locks" : { #锁信息,R:全局读锁;W:全局写锁;r:特定数据库的读锁;w:特定数据库的写锁
  24.  
    "Global" : {
  25.  
    "acquireCount" : {
  26.  
    "r" : NumberLong(1094) #该操作获取一个全局级锁花费的时间。
  27.  
    }
  28.  
    },
  29.  
    "Database" : {
  30.  
    "acquireCount" : {
  31.  
    "r" : NumberLong(547)
  32.  
    }
  33.  
    },
  34.  
    "Collection" : {
  35.  
    "acquireCount" : {
  36.  
    "r" : NumberLong(547)
  37.  
    }
  38.  
    }
  39.  
    },
  40.  
    "nreturned" : 200.0, #返回的文档数量
  41.  
    "responseLength" : 57695.0, #返回字节长度,如果这个数字很大,考虑值返回所需字段
  42.  
    "millis" : 264.0, #消耗的时间(毫秒)
  43.  
    "planSummary" : "COLLSCAN, COLLSCAN", #执行概览 从这里看来 是全表扫描
  44.  
    "execStats" : { #详细的执行计划 这里先略过 后续可以用 explain来具体分析
  45.  
    },
  46.  
    "ts" : ISODate("2017-08-24T02:32:49.768+0000"), #命令执行的时间
  47.  
    "client" : "10.3.131.96", #访问的ip或者主机
  48.  
    "allUsers" : [
  49.  
     
  50.  
    ],
  51.  
    "user" : ""
  52.  
    }
4.2 分析慢查询
  1.  
    1. 如果发现 millis 值比较大,那么就需要作优化。
  2.  
    2. 如果 docsExamined数很大,或者接近记录总数(文档数),那么可能没有用到索引查询,而是全表扫描。
  3.  
    3. 如果 keysExamined数为0,也可能是没用索引。
  4.  
    4. 结合 planSummary 中的显示,上例中是 "COLLSCAN, COLLSCAN" 确认是全表扫描
  5.  
    5. 如果 keysExamined 值高于 nreturned 的值,说明数据库为了找到目标文档扫描了很多文档。这时可以考虑创建索引来提高效率。
  6.  
    6. 索引的键值选择可以根据 query 中的输出参考,上例中 filter:包含了 jzrq和jglxfldm 并且按照RsId排序,所以 我们的索引
  7.  
    索引可以这么建: db.f10_2_8_3_jgcc.ensureindex({jzrq:1,jglxfldm:1,RsId:1})
4.3 执行计划中的TYPE类型
  1.  
    COLLSCAN #全表扫描 避免
  2.  
    IXSCAN #索引扫描 可以改进 选用更高效的索引
  3.  
    FETCH #根据索引去检索指定document
  4.  
    SHARD_MERGE #将各个分片返回数据进行 merge 尽可能避免跨分片查询
  5.  
    SORT #表明在内存中进行了排序(与老版本的scanAndOrder:true一致) 排序要有index
  6.  
    LIMIT #使用limit限制返回数 要有限制 Limit+(Fetch+ixscan)最优
  7.  
    SKIP #使用skip进行跳过 避免不合理的skip
  8.  
    IDHACK #针对_id进行查询 推荐,_id 默认主键,查询速度快
  9.  
    SHARDING_FILTER #通过mongos对分片数据进行查询 SHARDING_FILTER+ixscan最优
  10.  
    COUNT #利用db.coll.explain().count()之类进行count运算
  11.  
    COUNTSCAN # count不使用Index进行count时的stage返回 避免 这种情况建议加索引
  12.  
    COUNT_SCAN # count使用了Index进行count时的stage返回 推荐
  13.  
    SUBPLA #未使用到索引的$ or查询的stage返回 避免
  14.  
    TEXT #使用全文索引进行查询时候的stage返回
  15.  
    PROJECTION #限定返回字段时候stage的返回 选择需要的数据, 推荐PRO

转载于:https://www.cnblogs.com/ExMan/p/10907850.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值