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})

使其自动切换日志文件。每天生成一个日志文件。