第7回 GridFS——在MongoDB中保存大容量文件的方法

翻译自 : http://gihyo.jp/dev/serial/01/mongodb/0007

 

本文永久链接地址:https://www.askmac.cn/archives/mongodb-gridfs.html

 

GridFS的概要

 

能在MongoDB中保存的Document尺寸一般有最大16Mbyte的限制。这对于保存一般的文本文件是非常足够的尺寸,但要保存一些巨大的文本文件以及视频等Binary data时,就会出现超出16Mbyte的情况。想在MongoDB中保存16Mbyte以上的文件时,通过使用GridFS这种接口,可以将数据进行多个分割来进行保存。这次,我将解说处理MongoDB中处理大尺寸文件的功能——GridFS。

 

GridFS的概要图

 

 

 

图:左青:大文件 左蓝:girdFS interface(mongofile或者是driver) 黄:1.将文件分割到chunk中,写入文件。 2.文件的元数据(文件名、尺寸等等)的写入

上图例:文件 collection

右Mongod以下:chunk用collection、Binary data、Binary data、Binary data、元数据用collection、元数据。

 

被分割的数据我们称之为chunk,作为Binary data保存在Document中。

 

用数据库来管理文件的优点

 

话说回来,用数据库管理文件有怎样的好处呢。

 

在大部分系统之中,图片/音频/视频等大尺寸Binary data使用OS的文件系统进行保存。使用文件系统的话,就能用用习惯的接口访问文件。但是根据情况不同,文件被保存在数据库中,管理起来就会更有效率。以下我试着整理了用数据库来管理文件的优点。

 元数据管理简便

 

不仅是文件,也能通过数据库对文件相关的元数据进行同时管理。比如,文件的尺寸与制成者,制成时间等。视频文件的话也可以管理播放次数。在数据库中与文件相关的元数据也非常简便,有扩张性。另外,包含元数据的备份也很容易。

不受文件系统的上限限制

 

在OS中,对文件数以及目录数有上限。比如,ext3的情况下,目录内的子目录以及文件数的上限是32000。

试着简单操作下gridFS吧

 

在MongoDB中使用GridFS不需要特别的设定以及使用方法。基于Replica set/ sharding也可以使用。那么让我们来试着使用GridFS在MongoDB中保存文件吧。

 

这次我们使用在MongoDB标准版准备的Command-line tool——mongofiles。命令的选项我们将在下章进行详细说明。

 

首先作成用1MB.file这个文件名保存的文件。在下面的例子中作成文件尺寸1MB。

 

$ dd if=/dev/zero of=1MB.file bs=1M count=1

 

使用mongofiles,在girdtest这个数据库中保存刚刚制成的1MB的file。

 

$ mongofiles -v -d gridtest put 1MB.file
Wed Feb 20 15:23:27 creating new connection to:127.0.0.1:27017
Wed Feb 20 15:23:27 BackgroundJob starting: ConnectBG
Wed Feb 20 15:23:27 connected connection!
connected to: 127.0.0.1
added file: { _id: ObjectId('51246bdfa3264162c8e99716'), 
filename: "1MB.file", chunkSize: 262144, 
uploadDate: new Date(1361341409698), 
md5: "b6d81b360a5672d80c27430f39153e2c", 
length: 1048576 }
done!

 

运行结果如上所示的话就代表保存成功了。

 

 

关于collection结构

让我们从mongo shell开始确认GridFS的collection吧。连接mongoDB选择girdtest数据库。

$ mongo> use gridtest

 

 

确认collection。

> show collectionsfs.chunksfs.filessystem.indexes

 

Index之外,也有fs.chunks以及fs.files这样的collection。各自的功能分别如下所示。

 

fs.chunks

 

GridFS中,将文件作为chunk在一定尺寸中分割,保存在fs.chunks collection中。分割文件的默认尺寸是256KB。

 

fs.files

 

在fs.files collection中保存着文件名、上传时间,MD5 hash信息、文件尺寸等元数据。可以追加任意元数据。

关于被保存的元数据在官方document中有详细信息。

在下一章中,我将说明GridFS的两种操作方法:mongofiles以及ruby driver。

 

使用mongofiles的GridFS的操作

 

Mongofile是MongoDB标准版中准备的命令行工具。在安装了MongoDB的目录的bin之中。使用这个mongofiles,来试着操作GridFS吧。

 

各命令共通的命令行工具

 

V选项输出了详细内容

用d选项指定数据库名

 

追加文件

 

要追加文件就应该使用put。在此,我们在gridtest数据库中追加1MB.file这个文件。

$ mongofiles -v -d gridtest put 1MB.file

即使用同样文件名追加的,只要不被覆盖,就能作为别的object来追加。覆盖的情况时,请指定-r 选项。

$ mongofiles -v -d gridtest -r put 1MB.file

取得文件

 

文件的取得请使用get

$ mongofiles -v -d gridtest get 1MB.file

 

有同样文件名的情况,可以取得之后追加的项目。

 

 

文件的list表示

 

要将文件表示成表,请使用list。可以显示文件名以及文件尺寸。有同样文件名的情况下,被表示成复数。在下例中,1MB.file这个名字的文件记录了2个。

 

$ mongofiles -v -d gridtest list
Wed Feb 20 16:08:01 creating new connection to:127.0.0.1:27017
Wed Feb 20 16:08:01 BackgroundJob starting: ConnectBG
Wed Feb 20 16:08:01 connected connection!connected to: 127.0.0.1
1MB.file        1048576
1MB.file        1048576
image01.png     524288
image02.png     262144

 

删除文件

 

文件的删除使用delete。。

 

[注意]

 

同样文件名的数据会被全部删除,请大家注意。

$ mongofiles -v -d gridtest delete 1MB.file

文件搜索

 

文件的搜索使用search。指定的文字列包含文件名的情况下,会被显示。

$ mongofiles -v -d gridtest search 1MB

使用ruby的GridFS的操作

 

通过使用 ruby用MongoDB官方driver,可以从Ruby操作GridFS。Driver可以从gem开始安装。

$ gem install mongo

 

虽然不是必要的,同样地在gem中安装bson_ext的话,可以实现BSON处理的高速化。

$ gem install bson_ext

 

首先进行准备。要从Ruby中处理GridFS的话,需要在fs.chunks中制成index。通过在mongofiles中登陆文件,可以自动制成index。

$ dd if=/dev/zero of=1MB.file bs=1M count=1$ mongofiles -d gridtest put 1MB.file

 

以下是对于gridtest数据库进行取得与保存,最后删除的脚本。追加文件时,可以登陆任意元文件。

require  'mongo'

db_name = "gridtest"
@con = Mongo::Connection.new
@db = @con[db_name]
@grid = Mongo::Grid.new(@db)
@collection = @db["fs.files"]


file_id = @grid.put(File.binread("1MB.file"),
                    :filename => "1MB.file",
                    :tags => ["mongo","database","book"],
                    :memo => "sample file",
                    :owner => "mongonouchi")

puts "get file_id=#{file_id}"
puts "filename = #{@grid.get(file_id).filename}"
puts ""

@collection.find({:_id => BSON::ObjectId(file_id.to_s)}).each{ |doc|
  puts doc.inspect
}

puts ""
puts "delete file_id=#{file_id}"
@grid.delete(file_id)

 

 

上述作为grid_sample.rb保存,以下是输出例。为了大家方便看,我分行写的。被输出的file_id根据环境发生改变。

 

$ ruby grid_sample.rb
get file_id=512ac8a2af1fe66a0e000001
filename = 1MB.file

{"_id"=>BSON::ObjectId('512ac8a2af1fe66a0e000001'), 
 "filename"=>"1MB.file", 
 "contentType"=>"binary/octet-stream", 
 "length"=>1048576, 
 "chunkSize"=>262144, 
 "uploadDate"=>2013-02-25 02:12:50 UTC, 
 "md5"=>"b6d81b360a5672d80c27430f39153e2c", 
 "tags"=>["mongo", "database", "book"], 
 "memo"=>"sample file", 
 "owner"=>"mongonouchi"
}

delete file_id=512ac8a2af1fe66a0e000001

 

 

 其他工具

 

Mongofiles,在官方driver中也开发了其他能操作GridFS的工具。在此我们省略详细接受,有从Nginx开始直接GridFS操作的nginx-gridfs

下次的主题

 

这次介绍了在MongoDB中处理大尺寸文件的GridFS。通过使用GridFS,图片以及动画等大文件也可以通过MongoDB来进行管理。

下次我想介绍就快发售的MongoDBv2.4的新功能。在MongoDB中追加了全文搜索,GeoJSON对应,hash document等先进功能。请大家多多期待。


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *