MongoDB监控之一:运行状态、性能监控,分析

时间:2024-11-12 08:03:37

为什么要监控?

监控及时获得应用的运行状态信息,在问题出现时及时发现。

监控什么?

CPU、内存、磁盘I/O、应用程序(MongoDB)、进程监控(ps -aux)、错误日志监控

1.4.1 MongoDB集群监控方式

db.serverStatus()

  查看实例运行状态(内存使用、锁、用户连接等信息)

  通过比对前后快照进行性能分析

MongoDB监控之一:运行状态、性能监控,分析
"connections"     # 当前连接到本机处于活动状态的连接数
"activeClients" # 连接到当前实例处于活动状态的客户端数量
"locks" # 锁相关参数
"opcounters" # 启动之后的参数
"opcountersRepl" # 复制想关
"storageEngine" # 查看数据库的存储引擎
"mem" # 内存相关
MongoDB监控之一:运行状态、性能监控,分析

状态:

db.stats()

显示信息说明:

MongoDB监控之一:运行状态、性能监控,分析
# 统计数据库信息
db.stats()
{
        "db" : "test",          # 系统自带测试数据库
        "collections" : 0,      # 集合数量
        "views" : 0,            #
        "objects" : 0,          # 文档对象的个数, 所有集合的记录数之和
        "avgObjSize" : 0,         # 平均每个对象的大小, 通过 dataSize / Objects 得到
        "dataSize" : 0,         # 当前库所有集合的数据大小
        "storageSize" : 0,       # 磁盘存储大小
        "numExtents" : 0,        # 所有集合的扩展数据量统计数
        "indexes" : 0,            # 已建立索引数量
        "indexSize" : 0,        # 索引大小
        "fileSize" : 0,            #
        "fsUsedSize" : 0,        #
        "fsTotalSize" : 0,        #总大小
        "ok" : 1
}
MongoDB监控之一:运行状态、性能监控,分析

1.4.2 mongostat

mongostat是mongdb自带的状态检测工具,在命令行下使用。它会间隔固定时间获取mongodb的当前运行状态,并输出。如果你发现数据库突然变慢或者有其他问题的话,你第一手的操作就考虑采用mongostat来查看mongo的状态。

主要功能:

实时数据库状态,读写、加锁、索引命中、缺页中断、读写等待队列等情况。

每秒刷新一次状态值,并能提供良好的可读性,通过这些参数可以观察到MongoDB系统整体性能情况。

常用命令格式:

mongostat --host 192.168.1.100:27017 -uroot -p123456 --authenticationDatabase admin
参数说明:
host:指定IP地址和端口,也可以只写IP,然后使用--port参数指定端口号
-u: 如果开启了认证,则需要在其后填写用户名
-p: 不用多少,肯定是密码
--authenticationDatabase:若开启了认证,则需要在此参数后填写认证库(注意是认证上述账号的数据库)
输出各字段解释说明:
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以下,基本满足多数场景。

1.4.3 mongotop

mongotop命令说明:

MongoDB监控之一:运行状态、性能监控,分析
[mongod@MongoDB oplog]$ mongotop  -h 127.0.0.1:27017
2018-01-08T17:32:56.623+0800 connected to: 127.0.0.1:27017 ns total read write 2018-01-08T17:32:57+08:00
admin.system.roles 0ms 0ms 0ms
admin.system.users 0ms 0ms 0ms
admin.system.version 0ms 0ms 0ms
app.user 0ms 0ms 0ms
automationcore.automation.job.status 0ms 0ms 0ms
automationcore.config.automation 0ms 0ms 0ms
automationcore.config.automationTemplates 0ms 0ms 0ms
automationcore.config.automationTemplates_archive 0ms 0ms 0ms
automationcore.config.automation_archive 0ms 0ms 0ms
automationstatus.lastAgentStatus 0ms 0ms 0ms
MongoDB监控之一:运行状态、性能监控,分析

mongotop重要指标

ns:数据库命名空间,后者结合了数据库名称和集合。
total:mongod在这个命令空间上花费的总时间。
read:在这个命令空间上mongod执行读操作花费的时间。
write:在这个命名空间上mongod进行写操作花费的时间。

1.4.3 mongosniff

此工具可以从底层监控到底有哪些命令发送给了MongoDB 去执行,从中就可以进行分析:以root 身份执行:

$./mongosniff --source NET lo

然后其会监控位到本地以localhost 监听默认27017 端口的MongoDB 的所有包请求。

1.4.3 db级别命令

1、db.currentOp()

db.currentOp是个好东西,顾名思义,就是当前的操作。在mongodb中可以查看当前数据库上此刻的操作语句信息,包括insert/query/update/remove/getmore/command等多种操作。直接执行

db.currentOp()一般返回一个空的数组,我们可以指定一个参数true,这样就返回用户connections与系统cmmand相关的操作。下面看个列子:

db.currentOp(true) 会返回很多信息:

db.currentOp()

查看数据库当前执行什么操作。

用于查看长时间运行进程。

通过(执行时长、操作、锁、等待锁时长)等条件过滤。

重点关注以下几个字段:

字段 说明
client 请求是由哪个客户端发起的。
opid 操作的opid,有需要的话,可以通过db.killOp(opid) 直接终止该操作。
secs_running/microsecs_running 这个值重点关注,代表请求运行的时间,如果这个值特别大,请看看请求是否合理。
query/ns 这个字段能看出是对哪个集合正在执行什么操作。
lock* - 还有一些跟锁相关的参数,需要了解可以看官网文档,本文不做详细介绍。
- db.currentOp文档请参见:db.currentOp

示例:

gechongrepl:PRIMARY> db.currentOp()
{
"inprog" : [
{
"opid" : ,
"active" : true,
"secs_running" : ,
"microsecs_running" : NumberLong(),
"op" : "getmore",
"ns" : "local.oplog.rs",
"query" : { },
"client" : "192.168.91.132:45745",
"desc" : "conn5",
"threadId" : "0x7f1370cb4700",
"connectionId" : ,
"waitingForLock" : false,
"numYields" : ,
"lockStats" : {
"timeLockedMicros" : {
"r" : NumberLong(),
"w" : NumberLong()
},
"timeAcquiringMicros" : {
"r" : NumberLong(),
"w" : NumberLong()
}
}
}
]
}

opid" : 6222,#进程号
"active" : true,#是否活动状态
"secs_running" : 3,#操作运行了多少秒
"microsecs_running" : NumberLong(3662328),
"op" : "getmore",#操作类型,包括(insert/query/update/remove/getmore/command)
"ns" : "local.oplog.rs",#命名空间
"query" : {},#如果op是查询操作,这里将显示查询内容;也有说这里显示具体的操作语句的

"client" : "192.168.91.132:45745",#连接的客户端信息
"desc" : "conn5",#数据库的连接信息
"threadId" : "0x7f1370cb4700",#线程ID
"connectionId" : 5,#数据库的连接ID
"waitingForLock" : false,#是否等待获取锁
"numYields" : 0,
"lockStats" : {
"timeLockedMicros" : {#持有的锁时间微秒
"r" : NumberLong(141),#整个MongoDB实例的全局读锁
"w" : NumberLong(0)},#整个MongoDB实例的全局写锁
"timeAcquiringMicros" : {#为了获得锁,等待的微秒时间
"r" : NumberLong(16),#整个MongoDB实例的全局读锁
"w" : NumberLong(0)}#整个MongoDB实例的全局写锁

2、db.killOp(opid)

kill当前的操作 opid为具体的操作id号,当然了,只能kill正在进行中的。opid是通过db.currentOp()查询返回的。如果发现一个操作太长,把数据库卡死的话,可以用这个命令杀死他:> db.killOp(608605)

示例:

MongoDB监控之一:运行状态、性能监控,分析
 { "inprog" :
[
{
"opid" : 3434473,//操作的id
"active" : <boolean>,//是否处于活动状态
"secs_running" : 0,//操作运行了多少秒
"op" : "<operation>",//具体的操作行为,包括(insert/query/update/remove/getmore/command)
"ns" : "<database>.<collection>",//操作的命名空间,如:数据库名.集合名
"query" : {//具体的操作语句
},
"client" : "<host>:<outgoing>",//连接的客户端信息
"desc" : "conn57683",//数据库连接描述
"threadId" : "0x7f04a637b700",//线程id
"connectionId" : 57683,//数据库连接id
"locks" : {//锁的相关信息
"^" : "w",
"^local" : "W",
"^<database>" : "W"
},
"waitingForLock" : false,//是否在等待并获取锁,
"msg": "<string>"
"numYields" : 0,
"progress" : {
"done" : <number>,
"total" : <number>
}
"lockStats" : {
"timeLockedMicros" : {//此操作获得以下锁后,把持的微秒时间
"R" : NumberLong(),//整个mongodb服务实例的全局读锁
"W" : NumberLong(),//整个mongodb服务实例的全局写锁
"r" : NumberLong(),//某个数据库实例的读锁
"w" : NumberLong() //某个数据库实例的写锁
},
"timeAcquiringMicros" : {//此操作为了获得以下的锁,而耗费等待的微秒时间
"R" : NumberLong(),//整个mongodb服务实例的全局读锁
"W" : NumberLong(),//整个mongodb服务实例的全局写锁
"r" : NumberLong(),//某个数据库实例的读锁
"w" : NumberLong()//某个数据库实例的写锁
}
}
},
..... ]
}
MongoDB监控之一:运行状态、性能监控,分析

1.4.3 MongoDB优化器profile

在MySQL 中,慢查询日志是经常作为我们优化数据库的依据,那在MongoDB 中是否有类似的功能呢?答案是肯定的,那就是MongoDB Database Profiler。

1.开启profiling功能

有两种方式可以控制 Profiling 的开关和级别,第一种是直接在启动参数里直接进行设置。启动MongoDB 时加上–profile=级别 即可。也可以在客户端调用db.setProfilingLevel(级别) 命令来实时配置,Profiler 信息保存在system.profile 中。我们可以通过db.getProfilingLevel()命令来获取当前的Profile 级别,类似如下操作:

db.setProfilingLevel(2);

上面profile 的级别可以取0,1,2 三个值,他们表示的意义如下:

0 – 不开启

1 – 记录慢命令 (默认为>100ms)

2 – 记录所有命令

Profile 记录在级别1 时会记录慢命令,那么这个慢的定义是什么?上面我们说到其默认为100ms,当然有默认就有设置,其设置方法和级别一样有两种,一种是通过添加 –slowms 启动参数配置。第二种是调用db.setProfilingLevel 时加上第二个参数:

db.setProfilingLevel( level , slowms )
db.setProfilingLevel( 1 , 10 );

2.查看 Profile的设置级别

db.getProfilingLevel()

> db.setProfilingLevel(1)
{ "was" : 2, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
> db.getProfilingLevel()
1
>

3.查询 Profiling 记录

与MySQL的慢查询日志不同,Mongo Profile 记录是直接存在系统db里的,记录位置 system.profile ,所以,我们只要查询这个Collection的记录就可以获取到我们的 Profile 记录了。

慢查询(system.profile)说明

详细信息见《MongoDB分析工具之二:MongoDB分析器Profile

二、性能问题排查

2.1、mongodb client端报错,感觉像连接数配置小了

mongoDB server端定位方法:

查看总的连接数,因为mongoDB 默认的最大连接数为820.

netstat -nat | grep -i "27017" | wc -l

netstat -nt|grep 27017|wc -l

或者:

到/data/mongodb/mongos/log

查看mongoDB的日志文件:
mongos.diagnostic.data  mongos.log

2.2、设置mongoDB server的最大连接数

修改mongodb最大连接数

在启动里边加参数  --maxConns=20000或者在 /etc/mongod.cnf (我自己见的配置文件添加 maxConns=20000)

重启mongodb

如果当前mongodb最大连接数没有变成20000,排查你service mongodb启动的脚本,如果脚本有 ulimit -n 12000,修改成30000,

如果修改成20000,貌似最大连接数也不到20000,这里具体原因没查,我的脚本是 /etc/init.d/mongod

还有一个地方可能影响到mongodb最大连接数,Linux系统默认一个进程最大打开文件数目是1024,修改rc.local

vi /etc/rc.local

很好我这里的一个进程最大打开文件数目远远大于20000

2.3、报错:because there was a socket exception raised by this connection.

回答1:

After few tries I've found out that it was a problem with the Azure's Load Balancer.
After 60s of inactivity it will disconnect any pending TCP connection.

After further digging I've found this post of the MongoDB diagnostics FAQ, and I've set the tcp keepalive to 120s:

sudo sysctl -w net.ipv4.tcp_keepalive_time=<value>

and I've also set the socketKeepAlive of the MongoClient to true:

MongoClientOptions.Builder options = MongoClientOptions.builder();
options.socketKeepAlive(true);
mongoClient = new MongoClient(mongoAddress, options.build());

After these fixes the issue seems gone!

回答2:

If you experience socket errors between clients and servers or between members of a sharded cluster or replica set that do not have other reasonable causes, check the TCP keepalive value (for example, the tcp_keepalive_time value on Linux systems). A common keepalive period is 7200 seconds (2 hours); however, different distributions and macOS may have different settings.

For MongoDB, you will have better results with shorter keepalive periods, on the order of 120 seconds (two minutes).

where u have installed mongodb u have to simply run this command on Linux

sudo sysctl -w net.ipv4.tcp_keepalive_time=120

mtop – 针对 MongoDB 的 top 命令

这是一个基于MongoDB Python 客户端 pymongo 的小程序,他使你可以像用操作系统的top命令一样,实时观察你的MongoDB 的状态。

1.安装 pymongo 及 mtop

下载安装pymongo:http://api.mongodb.org/python/1.9%2B/installation.html

如果有easy_install 那安装起来就比较easy了~只需要:

$ easy_install pymongo

下载安装mtop:https://github.com/beaufour/mtop

2.运行mtop

./mtop.py -s localhost:27017 -d 2000

3.参数说明

  • -s:表示MongoDB 所在的机器及端口
  • -d:刷新的间隔,以毫秒计所以上面表示每两秒一次。