"xprev"
:
"null"
,
"nsdiag"
:
"test.sample"
,
"size"
: 8192,
"firstRecord"
:
"0:50b0"
,
"lastRecord"
:
"0:6cb0"
},
...
]
...
}
可以看到extents在逻辑上是链表形式,以及每个extent的数据量、以及所在data
file
的offset位置.
从上面介绍中已经得知,删除document会导致磁盘碎片,有些update也会导致磁盘碎片,比如update导致文档尺寸变大,进而超过原来分配的空间;当有新的insert操作时,
mongodb会检测现有的extents中是否合适的碎片空间可以被重用,如果有,则重用这些fragment,否则分配新的存储空间。磁盘碎片,对write操作有一定的性能影响,而且
会导致磁盘空间浪费;如果你需要删除某个collection中大部分数据,则可以考虑将有效数据先转存到新的collection,然后直接drop()原有的collection。或者使用
db.runCommand({compact:
'<collection>'
})。
如果你的database已经运行一段时间,数据已经有很大的磁盘碎片(storageSize与dataSize比较),可以通过mongodump将指定database的所有数据导出,然后将原有的db删除,
再通过mongorestore指令将数据重新导入。(同compact,这种操作需要停机维护)
mongod中还有2个默认的database,系统级的,
"admin"
和
"local"
;它们的存储原理同上,其中
"admin"
用于存储
"用户授权信息"
,比如每个database中用户的role、权限等;
"local"
即为本地数据库,我们常说的oplog(replication架构中使用,类似与binlog)即保存在此数据库中。
2)Namespace文件
对于namespace文件,比如
"test.ns"
文件,默认大小为16M,此文件中主要用于保存
"collection"
、index的命名信息,比如collection的
"属性"
信息、每个索引的属性类型等,
如果你的database中需要存储大量的collection(比如每一小时生成一个collection,在数据分析应用中),那么我们可以通过配置文件
"nsSize"
选项来指定。
3)journal文件
journal日志为mongodb提供了数据保障能力,它本质上与mysql binlog没有太大区别,用于当mongodb异常crash后,重启时进行数据恢复;这归结于mongodb的数据持久写入
磁盘是滞后的。默认情况下,
"journal"
特性是开启的,特别在production环境中,我们没有理由来关闭它。(除非,数据丢失对应用而言,是无关紧要的)
一个mongodb实例中所有的databases共享journal文件。
对于write操作而言,首先写入journal日志,然后将数据在内存中修改(mmap),此后后台线程间歇性的将内存中变更的数据flush到底层的data files中,时间间隔为60秒;
write操作在journal文件中是有序的,为了提升性能,write将会首先写入journal日志的内存buffer中,当buffer数据达到100M或者每隔100毫秒,buffer中的数据将会flush
到磁盘中的journal文件中;如果mongodb异常退出,将可能导致最多100M数据或者最近100ms内的数据丢失,flush磁盘的时间间隔有配置项
"commitIntervalMs"
决定,默认为
100毫秒。mongodb之所以不能对每个write都将journal同步磁盘,这也是对性能的考虑,mysql的binlog也采用了类似的权衡方式。开启journal日志功能,将会导致write性能
有所降低,可能降低5~30%,因为它直接加剧了磁盘的写入负载,我们可以将journal日志单独放置在其他磁盘驱动器中来提高写入并发能力(与data files分别使用不同的
磁盘驱动器)。
如果希望数据尽可能的不丢失,可以考虑:
1)减小commitIntervalMs的值
2)每个write指定
"write concern"
中指定
"j"
参数为
true
3)最佳手段就是采用
"replica set"
架构模式,通过数据备份方式解决,同时还需要在
"write concern"
中指定
"w"
选项,且保障级别不低于
"majority"
。
最终需要在
"写入性能"
和
"数据一致性"
两个方面权衡,即CAP理论。
根据write并发量,journal日志文件为1G,如果指定了smallFiles配置项,则最大为128M,和data files一样journal文件也采用了
"preallocated"
方式,journal日志保存在
dbpath下
"journal"
子目录中,一般会有三个journal文件,每个journal文件格式类似于
"j._<序列数字>"
。并不是每次buffer flush都生成一个新的journal日志,而是当前
journal文件即将满时会预创建一个新的文件,journal文件中保存了write操作的记录,每条记录中包含write操作内容之外,还包含一个
"lsn"
(last sequence number),
表示此记录的ID;此外我们会发现在journal目录下,还有一个
"lsn"
文件,这个文件非常小,只保存了一个数字,当write变更的数据被flush到磁盘中的data files后,也
意味着这些数据已经持久化了,那么它们在
"异常恢复"
时也不需要了,那么其对应的journal日志将可以删除,
"lsn"
文件中记录的就是write持久化的最后一个journal记录的ID,
此ID之前的write操作已经被持久写入data files,此ID之前的journal在
"异常恢复"
时则不需要关注;如果某个journal文件中最大 ID小于
"lsn"
,则此journal可以被删除或者重用。
|
***************当你发现自己的才华撑不起野心时,就请安静下来学习吧***************
本文转自散尽浮华博客园博客,原文链接:http://www.cnblogs.com/kevingrace/p/7909947.html,如需转载请自行联系原作者