Mongodb 维护
1.查看服务器线程运行状态
db.currentOp():查看mongodb当前各个线程的状态,相当于mysql中的show full processlist,当服务器运行很慢的时候,可以首先执行下这个命令,可以看下服务器当前的状态,如果发现有异常的线程,可以直接使用db.killOp()将线程干掉,虽然这种比较暴力但不失为临时解决问题的一种绝好方法。
以下是db.currentOp()字段名的解释;
{
"opid" : 789193, # 此操作id
"active" : true, # 状态(running/sleep)
"secs_running" : 3, #操作运行的时间,在active=false时不显示
"op" : "getmore", #操作行为(insert/update/remove)
"ns" : "local.oplog.rs", # 集合名称
"query" : { # 具体的操作语句
},
"client" : "10.0.26.90:55312", #连接db的客户端ip
"desc" : "conn34681", #数据库连接描述
"threadId" : "0x7f24b8793700", # 线程id
"connectionId" : 34681, # 数据库连接id
"waitingForLock" : false, # 是否正在等待锁
"numYields" : 0, # 查询暂停的次数
"lockStats" : { # 锁的状态
"timeLockedMicros" : { # 持有锁的时间(ms)
"r" : NumberLong(81),
"w" : NumberLong(0)
},
"timeAcquiringMicros" : { #等待锁的时间(ms)
"r" : NumberLong(8),
"w" : NumberLong(0)
}
}
}
当发现secs_running这个字段的值较大并且严重阻塞了系统其它线程运行的时候可以先把使用db.killOp(opid)将其kill掉,然后针对这个链接执行的query进行优化。
在一个正在运行的mongodb服务器内部是有很多链接,直接执行db.currentOp()会将所有链接的信息都打印出来,这不便于找出有问题的链接,所以必须都db.currentOp()输出的信息做处理.
以下是一些信息处理脚本
找出运行时间超过200ms的链接信息
db.currentOp(true).inprog.forEach(function(doc){if(doc.active==true &&doc.secs_running>200 ){printjson(doc)}})
如果只需要打出这些链接的某个字段可以直接用print
db.currentOp(true).inprog.forEach(function(doc){if(doc.active==true &&doc.secs_running>200 ){printjson(doc.opid)}})
2.查看对象大小
查看文档大小: Object.bsonsize(db.users.findOne())
注意这里只能查看单个文档文档大小,无法查看多个文档大小累计和
rs0:PRIMARY> Object.bsonsize(db.traderecords.find().limit(1))
493
rs0:PRIMARY> Object.bsonsize({id:"邓旺dwchaoyue"})
29
查看集合的信息db.collection.stats()
rs0:PRIMARY> db.users.stats()
{
"ns" : "gow.users",
"count" : 3561,
"size" : 854640,
"avgObjSize" : 240,
"storageSize" : 2793472,
"numExtents" : 5,
"nindexes" : 2,
"lastExtentSize" : 2097152,
"paddingFactor" : 1,
"systemFlags" : 1,
"userFlags" : 1,
"totalIndexSize" : 310688,
"indexSizes" : {
"_id_" : 122640,
"name_1" : 188048
},
"ok" : 1
}
"ns" #集合名称
"count" # 文档总数
"size" # 集合中数据占用空间大小,不包括索引,单位为字节
该发小和db.collection.dataSize()得到的大小一样。
"avgObjSize" # 平均对像占用的空间大小
"storageSize"#给整个集合分配的存储空间,当删除集合中的文档时,这个值不会降代。
"numExtents" # 连续分配的数据块
"nindexes" #索引个数,每个集合至少有一个 _id 索引。
"lastExtentSize" # 最近分配的块的大小
"paddingFactor"
"systemFlags"
"userFlags"
"totalIndexSize" # 所有索引大小总和
"indexSizes":#列出集合的所有字段
查看数据库的信息:db.stats()
rs0:PRIMARY> db.stats()
{
"db" : "gow", # db名称
"collections" : 23, # 集合个数
"objects" : 569152, # 文档总数
"avgObjSize" : 935.8604801529293, #文档的平均大小
"dataSize" : 532646864, # 所有数据的总大小
"storageSize" : 652820480, # db占用的磁盘空间大小
"numExtents" : 92, # 连续分配的数据块
"indexes" : 34, # 索引个数
"indexSize" : 62832560, # 索引大小
"fileSize" : 1006632960, #预分配给数据库的文件大小
"nsSizeMB" : 16,
"dataFileVersion" : {
"major" : 4,
"minor" : 5
},
"extentFreeList" : {
"num" : 8,
"totalSize" : 22142976
},
"ok" : 1
}
3.数据预热
Mongodb访问磁盘中的数据要比访问内存中的数据慢得多,而且mongodb的内存是依靠
操作自身管理的,不想mysql中中的innodb,存储引擎,还需要管理自己的内存调配.
因此事先将磁盘中的数据加载到内存中可以大大提高mongodb的性能。
1.将数据库/数据目录移至内存:
for file in /data/db/brains.*
do
dd if=$file of=/dev/null
done
当要加载的数据大于内存大小的,之前加载的数据可能会挤兑出内存,所以有的时候将整个数据目录加载到数据库中意义并不是很大,
如果出现这个情况可以只将访问比较频繁的集合加载到内存中
db.runCommand({touch:"traderecords",data:true,index:true})
rs0:PRIMARY> db.runCommand({touch:"traderecords",data:true,index:true})
{
"data" : {
"numRanges" : 3,
"millis" : 91
},
"indexes" : {
"num" : 1,
"numRanges" : 1,
"millis" : 182
},
"ok" : 1
}
集合加载成功。
4.压缩数据:db.runCommand(compact:"collectionName",paddingFactor:1.5)
不会减少mongomongodb占用的空间大小,但可以使mongo不再需要分配新的空间
如果要收回压缩后的空间可以运行修复语句
db.repairDatabase()
5日志切换:db.adminCommand({"logRotate":1})
当mongodb运行一段时间后,log文件会变得很大,操作一个日志文件是相当痛苦的,为了避免大日子文件的产生,可以在低峰时段运行每天运行一次db.adminCommand({"logRotate":1}),
使其自动切换日志文件。每天生成一个日志文件。