`
QING____
  • 浏览: 2253380 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Mongodb与GridFS

 
阅读更多

一、概述

    GridFS是基于mongodb存储引擎是实现的“分布式文件系统”,底层基于mongodb存储机制,和其他本地文件系统相比,它具备大数据存储的多个优点。GridFS适合存储超过16MB的大型文件,不过16M数据在当今互联网时代,已经不足为奇。我们可以使用GridFS构建大规模的“图片服务器”、“文档服务器”、“视频、音频”文件服务器,GridFS对于web应用,可以结合nginx插件“ningx-gridfs”能够简单的实现负载均衡等特性,非常便捷;可以简单认为GridFS是为web应用而生。个人认为,目前架构比较简单的NoSQL文件系统中GridFS是最优秀的。

 

    GridFS并不是将单个文件直接存储为一个document,而是将文件分成多个parts或者说chunks,然后将每个chunk作为作为一个单独的document存储,然后将chunks有序保存。默认情况下,GridFS的chunk大小位255k。GridFS使用2个collections来存储这些文件,一个collection存储文件的chunks(实际文件数据),另一个则存储文件的metadata(用户自定义的属性,filename,content-type等)。

 

    当用户查询GridFS中的文件时,客户端或者driver将会重新按序组装这些chunks。用户可以range查询文件,也可以获取文件的任意部分的信息,比如:跳过(skip)视频或者音频(任何文件)的中间部,实现“range access of single file”。

 

    对于mongodb而言,每个document最大尺寸为16M,如果想存储一条数据(比如一个文件)超过16M,那么只能使用GridFS支持;GridFS可以支持单个文件尺寸达到数G,读取文件时可以分段读取。此外,GridFS可以从Mongodb的高性能、高可用特性中获益,比如我们可以在“replica set”或者“sharding”架构模式下使用GridFS。

 

二、使用场景

    document的大小超过16M是使用GridFS的条件之一,因为mongodb普通的collection无法支持16M以上的document,我们不得不选择其他方案;在一些情况下,将这些大文件存储在GridFS中,比直接存储在本地文件系统中更加适合:

    1)如果你的文件系统对每个目录下文件的个数有限制(或者太多,将会影响文件的打开速度等)。

    2)如果你的文件数据,有分数据中心镜像保存(大数据情况,可用性保证)。

    3)如果你希望访问一个超大的文件,而不希望将它全部加入内存,而是有“range access”的情况,即分段读取,那么GridFS天生就具备这种能力,你可以随意访问任意片段。

 

    对于一个大文件,如果你希望原子性的更新它的全部内容,那么GridFS将不适合;比如同时更新一个文件的多个chunk,因为mongodb本身没有事务机制。

 

    对于小于16M的文件,比如一些图片、CSS、js文件等,应该将它们直接存储在普通的collection中而非GridFS(bindata,参见org.bson.types.Binary),因为它们通常较小,GridFS无法发挥其优势。当然,你为了统一application的“文件系统”存储方式,也可以将这些小文件保存在GridFS中,性能也不会差的太多,为了提升性能,对这些小文件,可以在存储时手动设置它的chunkSize,避免文件被切分成多个chunks来提高性能。

 

三、GridFS内部存储结构简析(JAVA代码示例)

    比如我们创建了一个GridFS数据库,可以可以通过mongo shell指令看到:

> ./mongo --host 127.0.0.1 --port 27017
> use common-fs
> show collections;
fs.chunks
fs.files
system.indexes

 

    我们可以看到“common-fs”数据库下有2个collection:“fs.chunks”和“fs.files”;其中前缀“fs”为bucket名称。

    1)fs.chunks:存储二进制数据,如上文所述,保存在GridFS中的每个文件都会根据“chunkSize”拆分成多个chunks并依次保存在“fs.chunks”中,每个chunk都持有“files_id”即为“文件id”,“n”为chunk的序列;比如一个文件被拆分成3个chunks,那么“fs.chunks”中将会有3个document,它们持有相同的files_id,“n”分别为0、1、2。

{
  "_id" : <ObjectId>,	//chunk ID,全局唯一
  "files_id" : <ObjectId>,	//file collection表的"_id"值
  "n" : <num>,	//chunk的序列号,第一个chunk位0。
  "data" : <binary>	//二进制数据
}
> db.fs.chunks.getIndexes();
[
...
	{
		"v" : 1,
		"unique" : true,
		"key" : {
			"files_id" : 1,
			"n" : 1
		},
		"name" : "files_id_1_n_1",
		"ns" : "common-fs.fs.chunks"
	}
]

    chunks默认情况下已经对“files_id”和“n”建立了唯一索引。

 

    2)fs.files:存储文件的metadata,GridFS每保存一个文件,都会在此collection中插入一条document,结构如下所示。其中“metadata”字段用于保存用户自定义的K-V数据(比如保存文件的format),其他字段是GridFS内置的,开发者不能修改(除file_name外),每个文档都有一个md5字段,所以开发者不需要自己再去计算md5值。其中filename为开发者指定的“文件名称”。

{
  "_id" : <ObjectId>,	//
  "length" : <num>,	//文件的长度
  "chunkSize" : <num>,	//chunkSize
  "uploadDate" : <timestamp>,	//文件生成的时间戳
  "md5" : <hash>,	//HASH值

  "filename" : <string>,	//文件名,用户指定
  "contentType" : <string>,	//
  "aliases" : <string array>,	//别名
  "metadata" : <dataObject>,	//用户自定的metadata
}
> db.fs.files.getIndexes();
[
...
	{
		"v" : 1,
		"key" : {
			"filename" : 1,
			"uploadDate" : 1
		},
		"name" : "filename_1_uploadDate_1",
		"ns" : "common-fs.fs.files"
	}
]

    其中“filename”和“updateDate”默认已经建立了组合索引,但不是unique,所以GridFS中filename是可以重复的;建议使用_id来获取文档,比如如果你使用GridFS构建一个图片服务器,可以使用_id的值作为图片的名称。

    其中有一个比较重要的参数“chunkSize”,这个值默认为“261120”(即255k),对于web应用此值基本不需要调整;如果你的应用是文件的“上传”、“下载”等,可以考虑将此值扩大,比如64M等。还有一种特例,比如你的文件通常较小,比如只有1M左右,而且通常不会涉及到“range access”,那么可以将每个file的chunkSize设置为文档的大小,这样可以在存储时只有一个chunk。

    客户端查询文件时首先会查询“fs.files”获取metadata并获得files_id值(即_id),然后再根据files_id查询“fs.chunks”获取chunks列表(根据n排序),当客户端需要读取某个chunk数据时才会触发实际数据传输。

 

四、Sharding架构

    随着GridFS中文件数量的增加,最终有可能存储空间会达到单机磁盘上限,或者由于Read操作较多单机无法承载压力,此时就需要考虑分布式部署;解决此文件的方案为sharding,即将GridFS的数据分布存储在多个mongod节点中。

    sharding基本原理和mongodb一样,此处不再赘言;因为一个GridFS数据库,由“fs.files”和“fs.chunks”两个collections构成,一个文件将不同的信息保存在两个collections中,那么究竟该如何设计sharding呢?首先表明无论两个collection同时sharding还是只有其中一个sharding,都不需要客户端修改代码,也不会影响数据访问,因为无论是“通过filename查询fs.files”还是“通过files_id查询fs.chunks”中间都会经过mongos实例路由。

    因为fs.files文件中只保存metadata,通常都比较小,因此在可以不sharding。如果sharding,则根据应用需要选择合适的“shard key”,比如你通常使用_id来查询文件,那么可以将_id作为“shard key”的一部分(比如shard key为{_id : 1,filename:1}),如果你的应用通常使用filename查询文件,那么可以将filename作为shard key(或者前缀);我们最终的目的,就是确保查询方式与数据sharding保持一致,提供高效的查询,同时还需要尽可能保证数据的均匀分布。

    对于fs.chunks文件,这个是优先被sharding的,因为它的数据量通常为fs.files的数倍;不过这个collection的shard key只能为{"files_id" : 1, n : 1},因为这个collection只有这种查询方式,且只有这样才会保证同一个file_id的多个chunk尽可能的保存在同一个shard-chunk中。

    具体如何sharding请参见相关文档。

 

五、GridFS代码样例(JAVA)

    1、构建GridFS实例

MongoClient mongoClient = new MongoClient("127.0.0.1",30017);//单例
DB db = mongoClient.getDB("common-fs");

//单例即可,创建多个实例并无影响,内部间接使用了mongoClient作为通讯支撑
GridFS gridFS = new GridFS(db);//可以指定bucket名字,默认值为“fs”

 

    2、创建文件

FileInputStream inputStream = new FileInputStream(new File("/data/logs/support-web/web-all.log"));
GridFSInputFile inputFile = gridFS.createFile(inputStream);
inputFile.setFilename("web-all.log");
inputFile.setContentType("text/plain");
inputFile.save();
ObjectId fileId = (ObjectId)inputFile.getId();//此ID,在客户端生成
System.out.println(fileId.toHexString());//此字符串ID,可供application使用

 

    3、读取文件

GridFSDBFile file = gridFS.find(new ObjectId("56457faf6dca030a4b3e46cd"));
file.writeTo(new File("/data/logs/test-1.log"));

//此外还可以使用inputstream方式
BufferedInputStream inputStream = new BufferedInputStream(file.getInputStream(),1024);
OutputStream outputStream = new FileOutputStream(new File("/data/logs/test-2.log"));
byte[] bytes = new byte[1024];
while (true) {
    int count = inputStream.read(bytes);
    if(count < 1024) {
        break;
    }
    outputStream.write(bytes,0,count);
}
inputStream.close();
outputStream.close();

 

参考文档:

1)GridFS:【官方文档】

2)GridFS构建解答:【1】【2】  

3)Nginx插件:https://github.com/mdirolf/nginx-gridfs,不过此插件已经停止维护了,可能随着mongodb版本的升级将有可能不兼容;此后大只能在tomcat中访问gridfs了(或者NodeJS)。

 

分享到:
评论

相关推荐

    MongoDB.GridFS.dll

    MongoDB.GridFS.dll c#类库...............................................

    MongoDB的GridFS:存储大文件的解决方案.rar

    GridFS简介 什么是GridFS GridFS的工作原理 GridFS的应用场景 安装与配置 安装MongoDB 安装MongoDB驱动 GridFS基本操作 文件的上传 文件的下载 文件的删除 GridFS高级操作 文件分片与元数据管理 并发文件操作 文件...

    Mongodb基于GridFS存储文件

    Mongodb基于GridFS存储文件,通过流的方式存储文件图片,以及读取功能。本人亲自测试、编写。值得信赖

    Mongodb + GridFS +Java 操作Mongodb中存储的文件

    GridFS 是 MongoDB 提供的一种用于存储和检索大型文件的标准规范,它将大文件分割成多个小块(chunks)存储,方便高效管理和检索。在这个Java操作MongoDB中存储的文件实例中,我们将探讨如何利用GridFS API进行文件...

    Mongodb的gridfs的C#的例子

    首先,你需要通过NuGet包管理器或在项目文件中添加依赖来安装`MongoDB.Driver`库,这将提供与MongoDB服务器交互所需的API。 2. **连接到MongoDB** 使用`MongoClient`类建立到MongoDB服务器的连接。例如: ```...

    mongodb+GridFS文件的上传下载删除DEMO

    Java 开发者可以使用 MongoDB 官方提供的 Java 驱动程序,这个驱动程序提供了与 MongoDB 交互的 API。 1. **GridFS 概述** - GridFS 分为两个主要部分:`fs.files` 和 `fs.chunks` 集合。`fs.files` 存储文件元...

    MongoDB数据库GRIDFS上传下载删除文件

    MongoDB是一种流行的开源、分布式文档型数据库,常用于处理大量数据和高可...在给定的压缩包文件中,"DataBase.sln"可能是Visual Studio的解决方案文件,而"DataBase"可能包含与MongoDB数据库相关的代码或配置文件。

    MongoDB-GridFS-test:从MongoDB GridFS下载文件的性能测试

    我正在尝试从GridFS读取3种不同的部署(不同的MongoDB驱动程序)。 并将结果与​​经典的Nginx配置进行比较。贡献者( ) ( )构型1,Nginx location /files/ { alias /home/ubuntu/;}测试期间, open_file_cache...

    mongodb gridfs .NET(C#) 文件存储实例

    功能:基于mongodb gridfs实现简单文件上传、下载、搜索、删除。 开发环境:VS2012 mongodb驱动:官方Driver 上传控件:jquery uploadify 疑问:sort()方法可能有点问题 PS:有问题可以留言,欢迎交流~

    gridfs2s3:将 MongoDB GridFS 文件迁移到 AWS S3 的工具

    gridfs2s3 - 将 MongoDB GridFS 文件迁移到 AWS S3 的工具 这是一个简单的工具,它将抓取您指向的 GridFS 中的所有文件,并将它们粘贴到 S3 中 安装 go install github.com/Bowbaq/gridfs2s3 用法 gridfs2s3 -h flag...

    Vue+axios+Spring Boot+mongoDB 基于Mongo图片存储和基于GridFS的文件存储.zip

    在本项目中,Spring Boot通过其MongoDB的数据访问层(Data MongoDB)与MongoDB的GridFS接口进行交互,实现了文件的CRUD操作。当Vue应用通过axios发送文件时,Spring Boot服务会接收到文件,然后将其保存到MongoDB的...

    基于spring-boot和mongodb gridfs文件系统的文件服务器,用于微服务架构的文件上传下载功能支撑.zip

    基于node.js、vue、mongodb等技术构建的web系统,界面美观,功能齐全,适合用作毕业设计、课程设计作业等,项目均经过测试,可快速部署运行! 基于node.js、vue、mongodb等技术构建的web系统,界面美观,功能齐全,...

    Mongodb批量删除gridfs文件实例

    GridFS 是 MongoDB 内置的一个文件系统,用于存储和检索大文件,如图片、视频等。当你的应用不再需要某些文件,例如大量的图片,进行批量删除可以回收宝贵的存储空间。下面将详细介绍如何在 MongoDB 中批量删除 ...

    Mongodb GridFS图片文件存储解决方案

    3. **易于使用**:MongoDB 提供了丰富的驱动程序,支持多种编程语言,如 Java、Python、Node.js 等,使得与 GridFS 的交互变得简单。 **GridFSTest.java 示例** 在给定的 `GridFSTest.java` 文件中,我们可以看到一...

    MongoDB GridFS.pdf

    MongoDB GridFS 是一种在 MongoDB 数据库中存储和检索大型文件(如图片、音频、视频等)的机制。由于 MongoDB 的 BSON 文档格式对单个文档的大小有限制(默认为 16MB),GridFS 提供了一种解决方案,它将大文件分割...

    Nginx与Nginx-GridFS的安装与配置

    现在,Nginx已经配置好与MongoDB的GridFS进行交互。Web应用可以通过`http://yourserver/gridfs/`访问存储在MongoDB中的文件。Nginx会自动处理文件的读取和写入操作,减轻了后端应用的压力。 为了确保一切正常运行,...

    Laravel开发-laravel-gridfs-storage

    在本文中,我们将深入探讨Laravel开发中的一个特殊组件——`laravel-gridfs-storage`,这是一个将MongoDB的GridFS存储系统与Laravel框架的存储API整合的工具。MongoDB GridFS是一种分布式文件存储系统,它允许我们以...

    使用java上传MP4文件至mongodb数据库,并下载 源代码

    MongoDB中的GridFS是用于存储大文件的标准,它将文件拆分为多个小块(chunks),便于高效存储和检索。GridFS分为两个集合:`files`用于存储文件元数据,`chunks`用于存储文件内容。 上传MP4文件到GridFS,首先创建...

    Laravel开发-gridfs

    接下来,你需要安装一个适配器库来让Laravel与MongoDB的GridFS接口进行交互。Mongodb PHP Library(也称为mongodb/mongodb)是一个常用的选项,你可以通过Composer来安装: ```bash composer require mongodb/...

Global site tag (gtag.js) - Google Analytics