MongoDb gridfs-ngnix文件存储方案 - 图片

http://www.cnblogs.com/wintersun/p/4622205.html

在各类系统应用服务端开发中,我们经常会遇到文件存储的问题。 常见的磁盘文件系统,DBMS传统文件流存储。今天我们看一下基于NoSQL数据库MongoDb的存储方案。笔者环境 以CentOS 6.5,MongoDb 2.6.3,  Nginx-1.4.7 为例,您需要了解Linux常用命令。
先来回顾一下MongoDb的内部文件结构

  1. MongoDB在数据存储上按命名空间来划分,一个collection是一个命名空间,一个索引也是一个命名空间
  2. 同一个命名空间的数据被分成很多个Extent,Extent之间使用双向链表连接
  3. 在每一个Extent中,保存了具体每一行的数据,这些数据也是通过双向链接连接的
  4. 每一行数据存储空间不仅包括数据占用空间,还可能包含一部分附加空间,这使得在数据update变大后可以不移动位置
  5. 索引以BTree结构实现

然后是GridFs的结构

GridFS在数据库中,默认使用fs.chunks和fs.files来存储文件。

其中fs.files集合存放文件的信息,fs.chunks存放文件数据。

一个fs.files集合中的一条记录内容如下,即一个file的信息如下:


1

2

3

4

5

6

7

8

9

10

{

"_id" : ObjectId("4f4608844f9b855c6c35e298"),       //唯一id,可以是用户自定义的类型

"filename" : "CPU.txt",      //文件名

"length" : 778,      //文件长度

"chunkSize" : 262144,    //chunk的大小

"uploadDate" : ISODate("2012-02-23T09:36:04.593Z"), //上传时间

"md5" : "e2c789b036cfb3b848ae39a24e795ca6",      //文件的md5值

"contentType" : "text/plain"     //文件的MIME类型

"meta" : null    //文件的其它信息,默认是没有”meta”这个key,用户可以自己定义为任意BSON对象

}

对应的fs.chunks中的chunk如下:


1

2

3

4

5

6

{

"_id" : ObjectId("4f4608844f9b855c6c35e299"),    //chunk的id

"files_id" : ObjectId("4f4608844f9b855c6c35e298"),  //文件的id,对应fs.files中的对象,相当于fs.files集合的外键

"n" : 0,     //文件的第几个chunk块,如果文件大于chunksize的话,会被分割成多个chunk块

"data" : BinData(0,"QGV...")     //文件的二进制数据,这里省略了具体内容

}

文件存入到GridFS过程中,如果文件大于chunksize,则把文件分割成多个chunk,再把这些chunk保存到fs.chunks中,最后再把文件信息存入到fs.files中。

在读取文件的时候,先据查询的条件,在fs.files中找到一个合适的记录,得到“_id”的值,再据这个值到fs.chunks中查找所有
“files_id”为“_id”的chunk,并按“n”排序,最后依次读取chunk中“data”对象的内容,还原成原来的文件。

安装Install与配置

1.安装mongoDb

增加MongoDB Repository,不清楚vim,请参考VIM

vim /etc/yum.repos.d/mongodb.repo

如果是64bit的

[mongodb]

name=MongoDB Repository

baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/

gpgcheck=0

enabled=1

32bit的系统:

[mongodb]

name=MongoDB Repository

baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/i686/

gpgcheck=0

enabled=1

然后安装,会提示Y/N:

yum install mongo-10gen mongo-10gen-server

启动:

service mongod start

查看状态

service mongod status

停止

service mongod stop

更多,关于3.0以上版本,请参考官网。

2.安装nginx及nginx-gridfs

依赖库、工具

# yum -y install pcre-devel openssl-devel zlib-devel

# yum -y install gcc gcc-c++

下载nginx-gridfs源码

# git clone https://github.com/mdirolf/nginx-gridfs.git

# cd nginx-gridfs

# git checkout v0.8

# git submodule init

# git submodule update

下载nginx源码,编译安装。(高版本支持不好)

# wget http://nginx.org/download/nginx-1.4.7.tar.gz

# tar zxvf nginx-1.4.7.tar.gz

# cd nginx-1.4.7

# ./configure --with-openssl=/usr/include/openssl --add-module=../nginx-gridfs/

# make -j8 && make install –j8

注意蓝色字符配置成对应nginx-gridfs的路径

3. 配置nginx-gridfs

vim /usr/local/nginx/conf/nginx.conf

在 server 节点中添加 location 节点

location /img/ {

gridfs testdb

field=filename

type=string;

mongo 192.168.0.159:27017;

}

location /files/ {

gridfs testdb

field=_id

type=objectid;

mongo 192.168.0.159:27017;

}

这里我们的mongo服务在IP 192.168.0.159。

如果不指定 field,默认为 MongoDB 的自增ID,且type为int

配置参数介绍:

gridfs:nginx识别插件的关键字

testdb:db名

[root_collection]: 选择collection,如root_collection=blog, mongod就会去找blog.files与blog.chunks两个块,默认是fs

[field]: 查询字段,保证mongdb里有这个字段名,支持_id, filename, 可省略, 默认是_id

[type]: 解释field的数据类型,支持objectid, int, string, 可省略, 默认是int

[user]: 用户名, 可省略

[pass]: 密码, 可省略

mongo: mongodb url

启动nginx服务

# /usr/local/nginx/sbin/nginx

可能出现:

Nginx [emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use)

这时可用使用命令关闭占用80端口的程序

sudo fuser -k 80/tcp

简单测试

用原生的命令行上传一个文件

mongofiles put 937910.jpg --local ~/937910_100.jpg --host 192.168.0.159 --port 27017 --db testdb --type jpg

937910.jpg是我们提前下载好一个图片文件,注意我们没有指定collection,默认是fs

http://www.robomongo.org/安装robomongo管理工具, 查看刚刚上传的文件

最后我们在浏览器访问,如果看到图片就OK了

http://192.168.0.159/img/937910.jpg

对于.net环境下mongodb CSharpDriver  1.10.0 从Nuget:

Install-Package mongocsharpdriver -Version 1.10.0

我们使用如下片段代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

int nFileLen = fileUploadModel.FileBytes.Length;

MongoGridFSSettings fsSetting = new MongoGridFSSettings() { Root = CollectionName };

MongoGridFS fs = new MongoGridFS(mongoServer, MongoDatabaseName, fsSetting);

//调用Write、WriteByte、WriteLine函数时需要手动设置上传时间

//通过Metadata 添加附加信息

MongoGridFSCreateOptions option = new MongoGridFSCreateOptions();

option.Id = ObjectId.GenerateNewId();

var currentDate = DateTime.Now;

option.UploadDate = currentDate;

option.Aliases = alias;

BsonDocument doc = new BsonDocument();

//文档附加信息存储

if(fileUploadModel.DocExtraInfo!=null&&fileUploadModel.DocExtraInfo.Count>0)

{

    foreach(var obj in fileUploadModel.DocExtraInfo)

    {

        if (!doc.Elements.Any(p => p.Name == obj.Key))

        {

            doc.Add(obj.Key, obj.Value);

        }

    }

}

option.Metadata = doc;

//创建文件,文件并存储数据

using (MongoGridFSStream gfs = fs.Create(fileUploadModel.FileName, option))

{

    gfs.Write(fileUploadModel.FileBytes, 0, nFileLen);

    gfs.Close();

}

log.ErrorFormat("附件标识:{0} 文件名:{1} 上传成功", alias, fileUploadModel.FileName);

return option.Id.ToString();

注意,目前gridfs-ngnix不支持_id类型是GUID的,关于ObjectId参考官网,如下图:

mongodb产生objectid还有一个更大的优势,就是mongodb可以通过自身的服务来产生objectid,也可以通过客户端的驱动程序来产生。

什么时候使用Gridfs

来自官方2.6.10版本 手册内容

For documents in a MongoDB collection, you should always use GridFS for storing files larger than 16 MB.  In some situations, storing large files may be more efficient in a MongoDB database than on a system-level filesystem.

• If your filesystem limits the number of files in a directory, you can use GridFS to store as many files as needed.

• When you want to keep your files and metadata automatically
synced and deployed across a number of systems and facilities. When
using geographically distributed replica sets MongoDB can distribute
files and their metadata automatically to a number of mongod instances
and  facilities.

• When you want to access information from portions of large
files without having to load whole files into memory, you can use GridFS
to recall sections of files without reading the entire file into
memory.

Do not use GridFS if you need to update the content of the
entire file atomically. As an alternative you can store multiple
versions of each file and specify the current version of the file in the
metadata. You can update the metadata field that indicates “latest”
status in an atomic update after uploading the new version of the file,
and later remove previous versions if needed.

Furthermore, if your files are all smaller the 16 MB BSON
Document Size limit, consider storing the file manually within a single
document. You may use the BinData data type to store the binary data.
See your drivers documentation for details on using BinData.

数据库主从同步

原理图

上图是MongoDB采用Replica Sets模式的同步流程

  • 红色箭头表示写操作写到Primary上,然后异步同步到多个Secondary上
  • 蓝色箭头表示读操作可以从Primary或Secondary任意一个上读
  • 各个Primary与Secondary之间一直保持心跳同步检测,用于判断Replica Sets的状态

数据分片机制

  • MongoDB的分片是指定一个分片key来进行,数据按范围分成不同的chunk,每个chunk的大小有限制
  • 有多个分片节点保存这些chunk,每个节点保存一部分的chunk
  • 每一个分片节点都是一个Replica Sets,这样保证数据的安全性
  • 当一个chunk超过其限制的最大体积时,会分裂成两个小的chunk
  • 当chunk在分片节点中分布不均衡时,会引发chunk迁移操作

分片时服务器角色

上面讲了分片的标准,下面是具体在分片时的几种节点角色

  • 客户端访问路由节点mongos来进行数据读写
  • config服务器保存了两个映射关系,一个是key值的区间对应哪一个chunk的映射关系,另一个是chunk存在哪一个分片节点的映射关系
  • 路由节点通过config服务器获取数据信息,通过这些信息,找到真正存放数据的分片节点进行对应操作
  • 路由节点还会在写操作时判断当前chunk是否超出限定大小,如果超出,就分列成两个chunk
  • 对于按分片key进行的查询和update操作来说,路由节点会查到具体的chunk然后再进行相关的工作
  • 对于不按分片key进行的查询和update操作来说,mongos会对所有下属节点发送请求然后再对返回结果进行合并

其它关于mongodb 的一些小提示:

  • 不要使用32位版本

MongoDB的32位版本也是不建议被使用的,因为你只能处理2GB大小的数据。还记得第一个限制么?这是MongoDB关于该限制的说明

  • 了解官方的限制

让我感到惊讶的是,很少有人会查询关于他们将要使用的工具的限制。幸好,MongoDB的开发人员发布了一篇MongoDB所有限制的博客,你可以提前了解相关信息,避免在使用过程中难堪。

  • 主从复制不会确保高可用性

尽管已经不建议被使用了,不过MongoDB还是提供了另外一种复制策略,即主从复制。它解决了12个节点限制问题,不过却产生了新的问题:如果需要改变集群的主节点,那么你必须得手工完成,感到惊讶?看看这个链接吧。

  • 通过复制集实现的数据复制效果非常棒,不过也有限制

MongoDB中数据复制的复制集策略非常棒,很容易配置并且使用起来确实不错。但如果集群的节点有12个以上,那么你就会遇到问题。MongoDB中的复制集有12个节点的限制,这里是问题的描述,你可以追踪这个问题看看是否已经被解决了。

结论

Gridfs最适合大文件存储 ,特别是视频,音频,大型图片超过16MB大小的文件。小型文件也可以存储,不过需要付出2次查询代价(metadata与file content) [Tip#18 50 Tips and Tricks for MongoDB Developers]。
不要修改存储文件的内容,而是更新文件元数据如版本,或上传新版本的文件,删除老版本的文件。对于大量文件存储时,需要多个数据节点,复制,数据分片等。
别基于nginx访问图片文件,浏览器没有缓存。 从互联网存储图片案例来看,图片大都是jpg,
png与缩略图文件,分存式文件系统(DFS)会是更好的解决方案。

资源:

GridFS官方

Building MongoDB Applications with Binary Files Using GridFS

时间: 2024-08-03 10:14:37

MongoDb gridfs-ngnix文件存储方案 - 图片的相关文章

121. 请简要说明linux操作系统下你所了解的文件存储方案

请简要说明linux操作系统下你所了解的文件存储方案 RPM包安装 如何解决依赖性关系 Linux系统下有几种安装方式及卸载方式 你了解linux内核调优吗?请介绍下调优的原则及相关参数 当linux操作系统中没有/etc/sysconfig/iptables文件时,如何恢复. 在什么条件下可以用"service 服务名 start|stop"启动服务? 请列举出常用的系统工具,如网络测试.io性能测试 系统检测方式等 请简要说明nagios监控远程服务器的原理或示意图. 请说明LVS

MongoDb gridfs-ngnix文件存储方案

      在各类系统应用服务端开发中,我们经常会遇到文件存储的问题. 常见的磁盘文件系统,DBMS传统文件流存储.今天我们看一下基于NoSQL数据库MongoDb的存储方案.笔者环境 以CentOS 6.5,MongoDb 2.6.3,  Nginx-1.4.7 为例,您需要了解Linux常用命令. 先来回顾一下MongoDb的内部文件结构 MongoDB在数据存储上按命名空间来划分,一个collection是一个命名空间,一个索引也是一个命名空间 同一个命名空间的数据被分成很多个Extent

基于mapfile的小文件存储方案

1.采用mapfile存储小文件,会自动创建两个sequenceFile文件:data和index.数据存储在data中,index存储data中存储的文件的key(排好序的).这样可以实现小文件的合并存储,并且实现按key的快速索引. 2.代码: 文件存储: /**     * 将指定的文件写入文件系统,指定次数     * @param p    写入路径     * @param image    写入文件内容     * @param count    写入数量     * @throw

MongoDb GridFS的使用

MongoDb GridFS 是MongoDB的文件存储方案,主要用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片.音频等),对大文件有着更好的性能. 要在C#中使用GridFS,首先安装Nuget包: MongoDB.Driver.GridFS Bucket GridFS中的数据也是分集合存储的,每个集合叫一个bucket,每个bucket里面可以存储多个文件: 在C#中使用bucket和使用集合差不多,创建一个GridFSBucket对象即可. var bucket = ne

浅析MongoDB数据库的海量数据存储应用

[摘要]当今已进入大数据时代,特别是大规模互联网web2.0应用不断发展及云计算所需要的海量存储和海量计算发展,传统的关系型数据库已无法满足这方面的需求.随着NoSQL数据库的不断发展和成熟,可以较好地解决海量存储和海量计算方面的应用需求.本文重点描述作为NoSQL之一MongoDB数据库在海量数据存储方面的应用. 1 引言NoSQL,全称是“Not Only Sql”,指的是非关系型的数据库.这类数据库主要有这些特点:非关系型的.分布式.开源的.水平可扩展的.原始目的是为了大规模web应用,这

MongoDB——GridFS

GridFS是一个规范的存储和检索文件超过16 mb的bson文档大小限制. 而不是将文件存储在一个文档中,GridFS文件分为部分,或块,每个块作为一个单独的文档.使用FridFS与使用分片无 关.在默认情况下网格文件系统块大小限制为255 k.GridFS文件系统使用两个集合存储文件.一个收集存储文件块, 其他商店文件元数据. 当你查询GridFS文件系统存储文件时,驱动或客户端将重新组装块.你可以通过GridFS文件系统上执行范围查询 文件存储.你也可以从任意部分的文件访问信息,你可以"跳

MongoDB GridFS最佳应用概述

<MongoDB GridFS最佳应用概述> 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs GridFS是MongoDB数据库之上的一个简单文件系统抽象.如果你熟悉Amazon S3的话,那么GridFS与之相似.为什么像MongoDB这样的NoSQL数据库会提供这样的一个文件层抽象呢? 一.使用GridFS的理由 理由如下: 1)存储用户产生的文件内容 大多数Web应用都允许用户上传文件.当用户使用关系数据库时,这些用户产生的文件会存储在文件系

IIs 网站应用程序与虚拟目录的区别及高级应用说明(文件分布式存储方案)[转]

IIs 网站应用程序与虚拟目录的区别及高级应用说明(文件分布式存储方案) 对于IIS网站,大伙用的比较多,就不啰嗦了.   今天和说说大伙比较少使用的"IIS应用程序”和虚拟目录的区别及高级应用场景,文件分布式存储方案. 1:IIS网站: 一个网站,基本就是一个站点,绑定N个域名,绑定N个IP,然后设定一个应用程序池,基本就跑起来了,一个网站可以新建无数个应用程序和虚拟目录. 一行就带过了,大伙都懂,不多说. 2:应用程序(同一域名下程序的独立开发,独立部署的最佳应用策略): 我们发现,IIS网

PHP操作MongoDB GridFS 存储文件,如图片文件

GridFS是MongoDB的一个内置功能,它提供一组文件操作的API以利用MongoDB存储文件,GridFS的基本原理是将文件保存在两个Collection中,一个保存文件索引,一个保存文件内容,文件内容按一定大小分成若干块,每一块存在一个Document中,这种方法不仅提供了文件存储,还提供了对文件相关的一些附加属性(比如MD5值,文件名等等)的存储. 01 <?php 02 // 初始化gridfs 03 $conn = new Mongo(); // 连接MongoDB 04 $db