MongDB--存储机制GridFS

MongDB–存储机制GridFS

一:简介

GridFS是Mongo的一个子模块,使用GridFS可以基于MongoDB来持久存储文件。并且支持分布式应用(文件分布存储和读取)。作为MongoDB中二进制数据存储在数据库中的解决方案,通常用来处理大文件,对于MongoDB的BSON格式的数据(文档)存储有尺寸限制,最大为16M。但是在实际系统开发中,上传的图片或者文件可能尺寸会很大,此时我们可以借用GridFS来辅助管理这些文件。 在GridFS中,文件存储的集中度会比较高,MongoDB是以2G为单位来分配文件的。

二:应用场景

  • 不经常改变但是经常需要连续访问的大文件
  • 如果您的文件系统在一个目录中存储的文件的数量有限,你可以使用GridFS存储尽可能多的文件。
  • 当你想访问大型文件的部分信息,却不想加载整个文件到内存时,您可以使用GridFS存储文件,并读取文件部分信息,而不需要加载整个文件到内存。
  • 当你想让你的文件和元数据自动同步并部署在多个系统和设施,你可以使用GridFS实现分布式文件存储。

三:GridFS的存储原理

MongoDB服务器几乎不会对GridFS请求做处理,几乎所有的处理都是客户端的驱动程序和工具负责。GridFS使用两个集合存储文件。一个集合是fs.chunks, 用于存储文件内容的二进制数据;一个集合是fs.files,用于存储文件的元数据。(集合名可以修改)

当把一个文件存储到GridFS时,如果文件大于chunksize (每个chunk块大小为256KB),会先将文件按照chunk的大小分割成多个块,最终将块的信息存储在fs.chunks集合的多个文档中。然后将文件信息存储在fs.files集合的唯一一份文档中。其中fs.chunks集合中多个文档中的file_id字段对应fs.files集中文档”_id”字段。

在chunk集合块结内部,各个文档的结构非常简单
{
	"_id":ObjectId("....."),
	"n":0,//块在文件中的相对位置
	"data":BinData{},//块包含的二进制文件
	"files_id":ObjectId{},//块所属文件的元数据信息
}

在file集合内部的文档必须有如下几个键,用户也可以自定义元数据信息
"_id":元信息文件的唯一id
"length":文件包含的字节数
"chunSize":组成文件的每个块的大小,默认是256kb,可以调整
"uploadDate":文件被上传到GridFS的日期
"md5":文件内容的md5校验值,这个值是服务器端计算得到的

在file集合内部的文档有如下几个键是可选的
"filename":文件名
"contentType":文件的MIME类型
"metadata":文件自定义信息

读文件时,先根据查询条件在files集合中找到对应的文档,同时得到“_id”字段,再根据“_id”在chunks集合中查询所有“files_id”等于“_id”的文档。最后根据“n”字段顺序读取chunk的“data”字段数据,还原文件。

在这里插入图片描述

fs.chunks 集合存储文件文件内容的二进制数据,以类json格式文档形式存储。每在GridFS存储一个文件,GridFS就会将文件内容按照chunksize大小(chunk容量为256k)分成多个文件块,然后将文件块按照类json格式存在.chunks集合中,每个文件块对应fs.chunk集合中一个文档。一个存储文件会对应一到多个chunk文档

fs.files 集合存储文件的元数据,以类json格式文档形式存储。每在GridFS存储一个文件,则会在fs.files集合中对应生成一个文档。

四:shell的使用

list - list all files; ‘filename’ is an optional prefix which listed filenames must begin with
search - search all files; ‘filename’ is a substring which listed filenames must contain
put - add a file with filename ‘filename’
put_id - add a file with filename ‘filename’ and a given ‘_id’
get - get a file with filename ‘filename’
get_id - get a file with the given ‘_id’
delete - delete all files with filename ‘filename’
delete_id - delete a file with the given ‘_id’

[hadoop@hadoop01 bin]$ echo "hello word" > foo.txt  //写一个文件
[hadoop@hadoop01 bin]$ ./mongofiles  put foo.txt  //上传到GridFS
2019-11-28T14:41:13.801+0800    connected to: localhost
2019-11-28T14:41:13.802+0800    added file: foo.txt

[hadoop@hadoop01 bin]$ ./mongofiles list  //查看
2019-11-28T14:41:36.113+0800    connected to: localhost
foo.txt 11
[hadoop@hadoop01 bin]$ rm foo.txt 
[hadoop@hadoop01 bin]$ ./mongofiles get foo.txt  //下载
2019-11-28T14:42:28.392+0800    connected to: localhost
2019-11-28T14:42:28.396+0800    finished writing to foo.txt

[hadoop@hadoop01 bin]$ cat foo.txt
hello word

上传文件之后,去mongoDB查看

test>db.fs.files.find().pretty()
{
        "_id" : ObjectId("5ddf6f75732d2b0edcd29e5b"),
        "chunkSize" : 261120,
        "uploadDate" : ISODate("2019-11-28T06:55:49.726Z"),
        "length" : 11,
        "md5" : "4d2220fcf2abf3a9baac712bb93bd29c",
        "filename" : "foo.txt"
}
test>db.fs.chunks.find().pretty()
{
        "_id" : ObjectId("5ddf6f75732d2b0edcd29e5c"),
        "files_id" : ObjectId("5ddf6f75732d2b0edcd29e5b"),
        "n" : 0,
        "data" : BinData(0,"aGVsbG8gd29yZAo=")
}

再put一遍同一文件,MongoDB中存储了两个同样的文件,它们的元数据一致,除了_id键。MongoDB提供了md5哈希算法,但GridFs不会自动处理md5值相同的文件。也就是说,同一个文件进行两次put命令,将会在GridFS中对应两个不同的存储,对于存储来说,这是一种浪费。对于md5相同的文件,如果想要在GridFS中只有一个存储,需要通过API进行扩展处理。

五:注意几点

  • GridFS不会自动处理md5值相同的文件
  • delete命令基于文件名删除,会删除所有文件名相同的文件
  • 使用delete命令删除了文件,但是并不会释放磁盘空间,会造成空间浪费

六:回收磁盘空间的方式

(1)可以通过修复数据库来回收磁盘空间,即在mongo shell中运行db.repairDatabase()命令或者db.runCommand({ repairDatabase: 1 })命令。(此命令执行比较慢)。

使用通过修复数据库方法回收磁盘时需要注意,待修复磁盘的剩余空间必须大于等于存储数据集占用空间加上2G,否则无法完成修复。因此使用GridFS大量存储文件必须提前考虑设计磁盘回收方案,以解决mongoDB磁盘回收问题。

(2)**使用dump & restore方式,即先删除mongoDB数据库中需要清除的数据,然后使用mongodump备份数据库。**备份完成后,删除MongoDB的数据库,使用Mongorestore工具恢复备份数据到数据库。

当使用db.repairDatabase()命令没有足够的磁盘剩余空间时,可以采用dump & restore方式回收磁盘资源。如果MongoDB是副本集模式,dump & restore方式可以做到对外持续服务,在不影响MongoDB正常使用下回收磁盘资源。

MogonDB使用副本集, 实践使用dump & restore方式,回收磁盘资源。70G的数据在2小时之内完成数据清理及磁盘回收,并且整个过程不影响MongoDB对外服务,同时可以保证处理过程中数据库增量数据的完整。

原文参考:http://rdc.hundsun.com/portal/article/703.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值