MongoDB一次性能问题处理
问题:发现线上环境web界面获取MongoDB中的数据变得很慢(界面主要是查询),接着查看Rabbitmq消息队列中对应功能队列中堆积了不少的消息(worker主要是插入数据)。
从上面的问题现象来看基本是MongoDB出现了性能的问题,大致的排查了一下MongoDB。
1. 首先查看一下系统资源:
root@mongo-2-6-0-5:~# free -m
total used free shared buffers cached
Mem: 7986 7826 159 0 21 6681
-/+ buffers/cache: 1123 6862
Swap: 0 0 0
free的内存貌似不太多了,但是cached的挺多,说明内存虽然不太够但是利用率还算可以。接着top看了一下,下面只列出了cpu部分:
Cpu(s): 24.1%us, 1.2%sy, 0.0%ni, 42.4%id, 32.1%wa, 0.0%hi, 0.2%si, 0.1%st
从这看cpu貌似也还行,就是wa有点高,可能跟上面的free内存不太够有关。
从系统资源来看还勉强可以,不至于导致性能下降这么慢,主要是以前运行OK的时候系统资源跟现在状态也差不多了。
2. 接着看一下MongoDB的运行状态
MongoDB提供了一些工具来查看其运行状态,下面每一个命令不具体介绍功能了,更详细的可以查看其文档。
mongostat间隔固定时间获取mongodb的当前运行状态,并输出,这个跟top命令有点像。从这个命令输出来看status这个db的faults值比较高(faults/s 每秒访问失败数(只有Linux有),数据被交换出物理内存,放到swap),这个跟前面我们看到free内存不足也是有一定关系的,从这来看确实有必要增加内存了。
接着用db.stat()、db.serverStatus()看了一下,没有看出太多的问题。
想着看一下当前正在运行的mongo操作吧,看到底是在做什么操作。MongoDB有一个db.currentOp()语句可以查看当前正在运行的mongo语句,一查发现有不少的query操作正在进行,而且貌似一直都在运行,没有结束。
从db.currentOp()的输出来看看不到查询语句到底运行了多久,所以又换了另外一个查询语句db.$cmd.sys.inprog.find({“ns” : “status.statusdetail”, “op” : “query”}),这个的输出中包含有一个secs_running表示语句运行的时间,从这个语句的输出来看这些query语句都运行超过了10min。
综合上面的过程来看很有可能就是有一批"慢查询"导致了MongoDB的性能下降。
3. 如何解决
要解决性能问题就要把这些"慢查询"给kill掉,MongoDB提供了db.killOp()语句来干这件事。
首先我们找出所有“慢查询”语句对应的opid,然后调用db.killOp(176127902/opid/)来kill掉。
鉴于这样的"慢查询"语句太多了,写了一个批处理的shell:
cat opid.txt | xargs -I {} mongo status --eval "db.killOp({}/*opid*/)"
把这些"慢查询"kill掉以后,MongoDB的性能骤然就恢复正常了。