第46章:MongoDB-监控应用状态

时间:2023-03-09 02:27:00
第46章:MongoDB-监控应用状态
MongoDB监控 
1 db.serverStatus()

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

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

"connections" # 当前连接到本机处于活动状态的连接数 "activeClients" # 连接到当前实例处于活动状态的客户端数量 "locks" # 锁相关参数 "opcounters" # 启动之后的参数 "opcountersRepl" # 复制想关 "storageEngine" # 查看数据库的存储引擎 "mem" # 内存相关
2 db.stats()

显示信息说明:

"db" : "test" ,表示当前是针对"test"这个数据库的描述。想要查看其他数据库,可以先运行$ use databasename(e.g $use admiin).
"collections" : 3,表示当前数据库有多少个collections.可以通过运行show collections查看当前数据库具体有哪些collection.
"objects" : 13,表示当前数据库所有collection总共有多少行数据。显示的数据是一个估计值,并不是非常精确。
"avgObjSize" : 36,表示每行数据是大小,也是估计值,单位是bytes
"dataSize" : 468,表示当前数据库所有数据的总大小,不是指占有磁盘大小。单位是bytes
"storageSize" : 13312,表示当前数据库占有磁盘大小,单位是bytes,因为mongodb有预分配空间机制,为了防止当有大量数据插入时对磁盘的压力,因此会事先多分配磁盘空间。
"numExtents" : 3,似乎没有什么真实意义。我弄明白之后再详细补充说明。
"indexes" : 1 ,表示system.indexes表数据行数。
"indexSize" : 8192,表示索引占有磁盘大小。单位是bytes
"fileSize" : 201326592,表示当前数据库预分配的文件大小,例如test.0,test.1,不包括test.ns。
3 mongostat

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

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

[mongod@MongoDB oplog]$ mongostat -h 10.0.0.152 --port 28017
insert query update delete getmore command flushes mapped vsize res faults qr|qw ar|aw netIn netOut conn set repl time
*0 *0 *0 *0 0 1|0 0 303.0M 13.0M 0 0|0 0|0 143b 8k 1 RTR 2018-01-08T17:28:42+08:00

参数说明:

参数

参数说明

insert

每秒插入量

query

每秒查询量

update

每秒更新量

delete

每秒删除量

conn

当前连接数

qr|qw

客户端查询排队长度(读|写)最好为0,如果有堆积,数据库处理慢。

ar|aw

活跃客户端数量(读|写)

time

当前时间

 

4 mongotop

命令说明:

[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

mongotop重要指标

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

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

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

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

  如果发现一个操作太长,把数据库卡死的话,可以用这个命令杀死他:> db.killOp(608605)

通常用这个命令来查找耗时的操作,但是,所有跟复制、分片等相关的操作,都应该忽略掉,即使慢也不要去动,更不要去终止他们。

1:opid:操作的唯一标识符

2:active:该操作是否正在运行

3:secs_running:该操作已经执行的时间

4:op:操作的类型

5:desc:日志中与此连接相关的每一条记录都会以[conn3]为前缀,因此可以此来筛选日志

6:locs:描述该操作使用的锁的类型,其中“^”表示全局锁

7:waitingForLock:表示该操作是否因正在等待锁而处于阻塞状态

8:numYields:表示该操作交出锁,而使其他操作得以运行的次数

9:lockstats.timeAcquiringMicros:表示该操作需要多长时间才能取得所需的锁

另外,在执行db.currentOp的时候,还可以加入过滤条件,从而只显示符合条件的结果,

比如:db.currentOp({“ns”:”mydb.users”});只查询该命名空间的操作

6 db.setProfilingLevel() --关闭

  设置server级别慢日志

  打开profiling:

0:不保存

1:保存慢查询日志

2:保存所有查询日志

  注意:级别是对应当前的数据库,而阈值是全局的。

查看profiling状态

查看慢查询:system.profile

关闭profiling

②计算空间消耗

1:使用Object.bsonsize()来计算文档的大小,比如:

Object.bsonsize(db.users.findOne(可以加条件));

2:使用stats函数来显示一个集合的信息,比如:

db.users.stats(比例因子); 可以传入比例因子,如1024表示k,1024*1024表示M

3:使用stats函数显示数据库的信息,跟上面一个类似

③终止操作的执行
可以用db.killOp(opid);,其中的opid可以通过上面的命令来查看。
MongoDB中的oplog

1 什么是oplog

  MongoDB 的Replication是通过一个日志来存储写操作的,这个日志就叫做oplog。

  在默认情况下,oplog分配的是5%的空闲磁盘空间。通常而言,这是一种合理的设置。可以通过mongod --oplogSize来改变oplog的日志大小。

  oplog是capped collection,因为oplog的特点(不能太多把磁盘填满了,固定大小)需要,MongoDB才发明了capped collection(the oplog is actually the reason capped collections were invented). 定值大小的集合,oplogSizeMB: 2048,oplog是具有幂等性,执行过后的不会反复执行。

  值得注意的是,oplog为replica set或者master/slave模式专用(standalone模式运行mongodb并不推荐)。

oplog的位置:

oplog在local库: local。oplog

master/slave 架构下:local.oplog.$main;

replica sets 架构下:local.oplog.rs

参数说明

$ mongodump --help
--oplog use oplog for taking a point-in-time snapshot

  该参数的主要作用是在导出的同时生成一个oplog.bson文件,存放在你开始进行dump到dump结束之间所有的oplog。

  oplog 官方说明https://docs.mongodb.com/manual/core/replica-set-oplog/

第46章:MongoDB-监控应用状态

  在replica set中oplog是一个定容集合(capped collection),它的默认大小是磁盘空间的5%(可以通过--oplogSizeMB参数修改),位于local库的db.oplog.rs。

  其中记录的是整个mongod实例一段时间内数据库的所有变更(插入/更新/删除)操作。当空间用完时新记录自动覆盖最老的记录。

  所以从时间轴上看,oplog的覆盖范围大概是这样的:

第46章:MongoDB-监控应用状态

  其覆盖范围被称作oplog时间窗口。需要注意的是,因为oplog是一个定容集合,所以时间窗口能覆盖的范围会因为你单位时间内的更新次数不同而变化。想要查看当前的oplog时间窗口预计值.

sh1:PRIMARY> rs.printReplicationInfo()
configured oplog size: 2048MB <--集合大小
log length start to end: 305451secs (84.85hrs) <--预计窗口覆盖时间
oplog first event time: Thu Jan 04 2018 19:39:05 GMT+0800 (CST)
oplog last event time: Mon Jan 08 2018 08:29:56 GMT+0800 (CST)
now: Mon Jan 08 2018 16:33:25 GMT+0800 (CST)

  oplog有一个非常重要的特性——幂等性(idempotent。即对一个数据集合,使用oplog中记录的操作重放时,无论被重放多少次,其结果会是一样的。

  举例来说,如果oplog中记录的是一个插入操作,并不会因为你重放了两次,数据库中就得到两条相同的记录。这是一个很重要的特性.

1.3.2 oplog.bson作用

与oplog相关的参数

参数

参数说明

--oplogReplay

重放oplog.bson中的操作内容

--oplogLimit

与--oplogReplay一起使用时,可以限制重放到的时间点

  首先要明白的一个问题是数据之间互相有依赖性,比如集合A中存放了订单,集合B中存放了订单的所有明细,那么只有一个订单有完整的明细时才是正确的状态。

  假设在任意一个时间点,A和B集合的数据都是完整对应并且有意义的(对非关系型数据库要做到这点并不容易,且对于MongoDB来说这样的数据结构并非合理。但此处我们假设这个条件成立),那么如果A处于时间点x,而B处于x之后的一个时间点y时,可以想象A和B中的数据极有可能不对应而失去意义。

  mongodump的进行过程中并不会把数据库锁死以保证整个库冻结在一个固定的时间点,这在业务上常常是不允许的。所以就有了dump的最终结果中A集合是10点整的状态,而B集合则是10点零1分的状态这种情况。

  这样的备份即使恢复回去,可以想象得到的结果恐怕意义有限。

  那么上面这个oplog.bson的意义就在这里体现出来了。如果在dump数据的基础上,再重做一遍oplog中记录的所有操作,这时的数据就可以代表dump结束时那个时间点(point-in-time)的数据库状态。

1.3.3 【模拟】mongodump使用

首先我们模拟一个不断有插入操作的集合foo,

use clsn
for(var i = 0; i < 10000; i++) {
db.clsn.insert({a: i});
}

  然后在插入过程中模拟一次mongodump并指定--oplog。

mongodump -h 10.0.0.152 --port 28021 --oplog -o /home/mongod/backup/oplog

  注意:--oplog选项只对全库导出有效,所以不能指定-d选项。

       因为整个实例的变更操作都会集中在local库中的oplog.rs集合中。

根据上面所说,从dump开始的时间系统将记录所有的oplog到oplog.bson中,所以我们得到这些文件:

[mongod@MongoDB ~]$ ll /home/mongod/backup/oplog
total 8
drwxrwxr-x 2 mongod mongod 4096 Jan 8 16:49 admin
drwxrwxr-x 2 mongod mongod 4096 Jan 8 16:49 clsn
-rw-rw-r-- 1 mongod mongod 77256 Jan 8 16:49 oplog.bson

查看oplog.bson中第一条和最后一条内容

[mongod@MongoDB oplog]$ bsondump oplog.bson >/tmp/oplog.bson.tmp
[mongod@MongoDB oplog]$ head -1 /tmp/oplog.bson.tmp
{"ts":{"$timestamp":{"t":1515401553,"i":666}},"t":{"$numberLong":"5"},"h":{"$numberLong":"5737315465472464503"},"v":2,"op":"i","ns":"clsn.clsn1","o":{"_id":{"$oid":"5a533151cc075bd0aa461327"},"a":3153.0}}
[mongod@MongoDB oplog]$ tail -1 /tmp/oplog.bson.tmp
{"ts":{"$timestamp":{"t":1515401556,"i":34}},"t":{"$numberLong":"5"},"h":{"$numberLong":"-7438621314956315593"},"v":2,"op":"i","ns":"clsn.clsn1","o":{"_id":{"$oid":"5a533154cc075bd0aa4615de"},"a":3848.0}}

  最终dump出的数据既不是最开始的状态,也不是最后的状态,而是中间某个随机状态。这正是因为集合不断变化造成的。

  使用mongorestore来恢复

[mongod@MongoDB oplog]$ mongorestore -h 10.0.0.152 --port 28021 --oplogReplay --drop /home/mongod/backup/oplog
2018-01-08T16:59:18.053+0800 building a list of dbs and collections to restore from /home/mongod/backup/oplog dir
2018-01-08T16:59:18.066+0800 reading metadata for clsn.clsn from /home/mongod/backup/oplog/clsn/clsn.metadata.json
2018-01-08T16:59:18.157+0800 restoring clsn.clsn from /home/mongod/backup/oplog/clsn/clsn.bson
2018-01-08T16:59:18.178+0800 reading metadata for clsn.clsn1 from /home/mongod/backup/oplog/clsn/clsn1.metadata.json
2018-01-08T16:59:18.216+0800 restoring clsn.clsn1 from /home/mongod/backup/oplog/clsn/clsn1.bson
2018-01-08T16:59:18.669+0800 restoring indexes for collection clsn.clsn1 from metadata
2018-01-08T16:59:18.679+0800 finished restoring clsn.clsn1 (3165 documents)
2018-01-08T16:59:19.850+0800 restoring indexes for collection clsn.clsn from metadata
2018-01-08T16:59:19.851+0800 finished restoring clsn.clsn (10000 documents)
2018-01-08T16:59:19.851+0800 replaying oplog
2018-01-08T16:59:19.919+0800 done

  注意黄字体,第一句表示clsn.clsn1集合中恢复了3165个文档;第二句表示重放了oplog中的所有操作。所以理论上clsn1应该有16857个文档(3165个来自clsn.bson,剩下的来自oplog.bson)。验证一下:

sh1:PRIMARY> db.clsn1.count()
3849

  这就是带oplog的mongodump的真正作用。

1.3.4 从别处而来的oplog

oplog有两种来源:

1、mongodump时加上--oplog选项,自动生成的oplog,这种方式的oplog直接 --oplogReplay 就可以恢复

2、从别处而来,除了--oplog之外,人为获取的oplog

例如:

mongodump --port 28021 -d local -c oplog.rs

  既然dump出的数据配合oplog就可以把数据库恢复到某个状态,那是不是拥有一份从某个时间点开始备份的dump数据,再加上从dump开始之后的oplog,如果oplog足够长,是不是就可以把数据库恢复到其后的任意状态了?是的!

  事实上replica set正是依赖oplog的重放机制在工作。当secondary第一次加入replica set时做的initial sync就相当于是在做mongodump,此后只需要不断地同步和重放oplog.rs中的数据,就达到了secondary与primary同步的目的。

  既然oplog一直都在oplog.rs中存在,我们为什么还需要在mongodump时指定--oplog呢?需要的时候从oplog.rs中拿不就完了吗?答案是肯定的,你确实可以只dump数据,不需要oplog。

在需要的时候可以再从oplog.rs中取。但前提是oplog时间窗口必须能够覆盖dump的开始时间。

及时点恢复场景模拟

模拟生产环境

for(i=0;i<300000;i++){ db.oplog.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }

插入数据的同时备份

mongodump -h 10.0.0.152 --port 28021 --oplog -o /home/mongod/backup/config

备份完成后进行次错误的操作

db.oplog.remove({});

备份oplog.rs文件

mongodump -h 10.0.0.152 --port 28021 -d local -c oplog.rs -o /home/mongod/backup/config/oplog

恢复之前备份的数据

mongorestore -h 10.0.0.152 --port 28021--oplogReplay /home/mongod/backup/config

截取oplog,找到发生误删除的时间点

bsondump oplog.rs.bson |egrep "\"op\":\"d\"\,\"ns\":\"test\.oplog\"" |head -1
"t":1515379110,"i":1

复制oplog到备份目录

cp /home/mongod/backup/config/oplog/oplog.rs.bson /home/mongod/backup/config/oplog.bson

进行恢复,添加之前找到的误删除的点(limt)

mongorestore -h 10.0.0.152 --port 28021 --oplogReplay --oplogLimit "1515379110:1" /home/mongod/backup/config

     至此一次恢复就完成了