设为首页 收藏本站
查看: 2036|回复: 0

[经验分享] mongo 固定集合,大文件存储,简单优化 + 三招解决MongoDB的磁盘IO问题

[复制链接]
YunVN网友  发表于 2015-7-9 10:15:14 |阅读模式
  1.固定集合



> db.createCollection('c1',{capped:true, size:100000, max:3});//固定集合  必须  显式创建。 设置capped为true, 集合总大小xxx字节, [集合中json个数max]
{ "ok" : 1 }
> db.c1.stats()
{
"ns" : "test.c1",
"count" : 0,
"size" : 0,
"storageSize" : 102400,
"numExtents" : 1,
"nindexes" : 0,
"lastExtentSize" : 102400,
"paddingFactor" : 1,
"flags" : 0,
"totalIndexSize" : 0,
"indexSizes" : {
},
"capped" : 1,
"max" : 3,
"ok" : 1
}
> db.c1.insert({name:'1'});
> db.c1.insert({name:'2'});
> db.c1.insert({name:'3'});
> db.c1.find()
{ "_id" : ObjectId("51e28837cf05e15d315aa74a"), "name" : "1" }
{ "_id" : ObjectId("51e28839cf05e15d315aa74b"), "name" : "2" }
{ "_id" : ObjectId("51e2883dcf05e15d315aa74c"), "name" : "3" }
> db.c1.insert({name:'4'});
> db.c1.find()
{ "_id" : ObjectId("51e28839cf05e15d315aa74b"), "name" : "2" }
{ "_id" : ObjectId("51e2883dcf05e15d315aa74c"), "name" : "3" }
{ "_id" : ObjectId("51e28845cf05e15d315aa74d"), "name" : "4" }
  普通集合转化为 固定集合



> db.runCommand({convertToCapped:'c1', size:1000000});
{ "ok" : 1 }
  
  2.GridFS 存储大文件。 视频,大图片...
GrdiFS使用两个表来存储数据:
files 包含元数据对象
chunks 包含其他一些相关信息的二进制块.

3.性能优化



> db.c1.find().explain()//查看执行效率
{
"cursor" : "ForwardCappedCursor",
"nscanned" : 3,    //扫描集合中文档次数
"nscannedObjects" : 3,
"n" : 3,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
  3.1建立索引



> db.c1.ensureIndex({name:1}, {background:true});//后台建立索引
> db.c1.getIndexKeys();//简单的查看索引 元素
[ { "name" : 1 } ]
> db.c1.getIndexes();//查看索引 详细信息
[
{
"v" : 1,
"key" : {
"name" : 1
},
"ns" : "test.c1",
"name" : "name_1",
"background" : true
}
]
> db.c1.find({name:'3'}).explain()
{
"cursor" : "BtreeCursor name_1",
"nscanned" : 1,//只查询一次
"nscannedObjects" : 1,
"n" : 1,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
"name" : [
[
"3",
"3"
]
]
}
}
  建立唯一索引:



> db.c2.ensureIndex({age:1}, {unique:1}, {background:1});//唯一索引, 索引值不得重复。
  删除索引:



> db.c2.dropIndex({age:1});
{ "nIndexesWas" : 2, "ok" : 1 }
db.c2.dropIndexes(); //删除所有索引,除_id索引外
    3.2限定返回行数, 设定返回字段数, 将集合转为固定集合
  
  性能监控:
  mongosniff --source
  
  
  随着时间增长存取速度慢下来,明显感觉到。遂进行一下优化:
三招解决MongoDB的磁盘IO问题    转载



有点标题党的意思,不过下面三招确实比较实用,内容来自Conversocial公司的VP Colin Howe在London MongoDB用户组的一个分享。
申请:下面几点并非放四海皆准的法则,具体是否能够使用,还需要根据自己的应用场景和数据特点来决定。
1.使用组合式的大文档
我们知道MongoDB是一个文档数据库,其每一条记录都是一个JSON格式的文档。比如像下面的例子,每一天会生成一条这样的统计数据:
{ metric: "content_count", client: 5, value: 51, date: ISODate("2012-04-01 13:00") }
{ metric: "content_count", client: 5, value: 49, date: ISODate("2012-04-02 13:00") }
而如果采用组合式大文档的话,就可以这样将一个月的数据全部存到一条记录里:
{ metric: "content_count", client: 5, month: "2012-04", 1: 51, 2: 49, ... }
通过上面两种方式存储,预先一共存储大约7GB的数据(机器只有1.7GB的内存),测试读取一年信息,这二者的读性能差别很明显:
第一种: 1.6秒
第二种: 0.3秒
那么问题在哪里呢?
实际上原因是组合式的存储在读取数据的时候,可以读取更少的文档数量。而读取文档如果不能完全在内存中的话,其代价主要是被花在磁盘seek上,第一种存储方式在获取一年数据时,需要读取的文档数更多,所以磁盘seek的数量也越多。所以更慢。
实际上MongoDB的知名使用者foursquare就大量采用这种方式来提升读性能。见此
2.采用特殊的索引结构
我们知道,MongoDB和传统数据库一样,都是采用B树作为索引的数据结构。对于树形的索引来说,保存热数据使用到的索引在存储上越集中,索引浪费掉的内存也越小。所以我们对比下面两种索引结构:
db.metrics.ensureIndex({ metric: 1, client: 1, date: 1})

db.metrics.ensureIndex({ date: 1, metric: 1, client: 1 })
采用这两种不同的结构,在插入性能上的差别也很明显。
当采用第一种结构时,数据量在2千万以下时,能够基本保持10k/s 的插入速度,而当数据量再增大,其插入速度就会慢慢降低到2.5k/s,当数据量再增大时,其性能可能会更低。
而采用第二种结构时,插入速度能够基本稳定在10k/s。
其原因是第二种结构将date字段放在了索引的第一位,这样在构建索引时,新数据更新索引时,不是在中间去更新的,只是在索引的尾巴处进行修改。那些插入时间过早的索引在后续的插入操作中几乎不需要进行修改。而第一种情况下,由于date字段不在最前面,所以其索引更新经常是发生在树结构的中间,导致索引结构会经常进行大规模的变化。
3.预留空间
与第1点相同,这一点同样是考虑到传统机械硬盘的主要操作时间是花在磁盘seek操作上。
比如还是拿第1点中的例子来说,我们在插入数据的时候,预先将这一年的数据需要的空间都一次性插入。这能保证我们这一年12个月的数据是在一条记录中,是顺序存储在磁盘上的,那么在读取的时候,我们可能只需要一次对磁盘的顺序读操作就能够读到一年的数据,相比前面的12次读取来说,磁盘seek也只有一次。
db.metrics.insert([
{ metric: 'content_count', client: 3, date: '2012-01', 0: 0, 1: 0, 2: 0, ... }
{ .................................., date: '2012-02', ... })
{ .................................., date: '2012-03', ... })
{ .................................., date: '2012-04', ... })
{ .................................., date: '2012-05', ... })
{ .................................., date: '2012-06', ... })
{ .................................., date: '2012-07', ... })
{ .................................., date: '2012-08', ... })
{ .................................., date: '2012-09', ... })
{ .................................., date: '2012-10', ... })
{ .................................., date: '2012-11', ... })
{ .................................., date: '2012-12', ... })
])
结果:
如果不采用预留空间的方式,读取一年的记录需要62ms
如果采用预留空间的方式,读取一年的记录只需要6.6ms
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-84693-1-1.html 上篇帖子: MongoDB日志过大怎么办? 下篇帖子: MongoDB学习笔记(一) 简单的安装配置
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表