MongoDb gridfs-ngnix文件存储方案

一个fs.files集合中的一条记下内容如下,即一个file的音讯如下:

图片 1

  1. MongoDB在多少存储上按命名空间来划分,一个collection是一个命名空间,一个目录也是一个命名空间
  2. 同一个命名空间的数码被分成很四个Extent,Extent之间采纳双向链表连接
  3. 在每个Extent中,保存了具体每一行的数据,那一个多少也是经过双向链接连接的
  4. 每一行数据存储空间不仅囊括数据占用空间,还大概包罗部分叠加空间,那使得在数量update变大后可以不移动地点
  5. 索引以BTree结构完结

资源:

GridFS官方 
Building MongoDB Applications with Binary Files Using
GridFS

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

任何有关mongodb 的局地小指示:

  • 无须拔取32位版本

MongoDB的32位版本也是不提议被接纳的,因为您只好处理2GB大小的数额。还记得首个限制么?那是MongoDB关于该限量的说明

  • 摸底官方的限制

让本人觉得感叹的是,很少有人会询问有关她们就要利用的工具的界定。幸好,MongoDB的开发人士发表了一篇MongoDB所有限制的博客,你可以提前打探相关新闻,幸免在选择进度中难堪。

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

就算已经不提议被应用了,不过MongoDB依然提供了其余一种复制策略,即主从复制。它消除了12个节点限制难题,可是却暴发了新的题目:如若需求转移集群的主节点,那么您不恐怕不得手工完毕,感到好奇?看看那几个链接吧。

  • 经过复制集已毕的数额复制效果尤其棒,不过也有限定

MongoDB中数量复制的复制集策略非常棒,很简单配置并且动用起来实在不易。但倘使集群的节点有12个以上,那么你就会遇见标题。MongoDB中的复制集有12个节点的范围,那里是题材的叙述,你可以追踪这几个题材看看是不是曾经被化解了。

图片 2

安装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的路线

  1. 配置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 

数据分片机制

图片 3

  • MongoDB的分片是指定一个分片key来开展,数据按限定分成区其他chunk,各个chunk的大大小小有限定
  • 有多少个分片节点保存那一个chunk,每一种节点保存一部分的chunk
  • 各个分片节点都以一个Replica Sets,那样保障数据的安全性
  • 当一个chunk当先其范围的最大体积时,会不同成八个小的chunk
  • 当chunk在分片节点中遍布不平均时,会掀起chunk迁移操作

然后是GridFs的结构

数据库主从同步

原理图

图片 4

上图是MongoDB选择Replica Sets方式的一块流程

  • 古铜黑箭头表示写操作写到Primary上,然后异步同步到七个Secondary上
  • 浅黛青箭头表示读操作可以从Primary或Secondary任意一个上读
  • 各类Primary与Secondary之间直接维持心跳同步检测,用于判断Replica
    Sets的景况

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

在种种系统应用服务端支付中,大家寻常会境遇文件存储的标题。
常见的磁盘文件系统,DBMS古板文书流存储。前些天大家看一下基于NoSQL数据库MongoDb的积存方案。作者环境
以CentOS 6.5,MongoDb 2.6.3,  Nginx-1.4.7
为例,您须要领会Linux常用命令。 
先来回看一下MongoDb的中间文件结构

什么样时候利用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.

结论

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

 

简单易行测试

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

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管理工具, 查看刚刚上传的文本

图片 5

终极大家在浏览器访问,若是看到图片就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参考官网,如下图:

图片 6

mongodb爆发objectid还有一个更大的优势,就是mongodb能够由此我的劳务来发出objectid,也足以通过客户端的驱动程序来暴发。

文件存入到GridFS进度中,假使文件大于chunksize,则把公文分割成四个chunk,再把那么些chunk保存到fs.chunks中,最终再把公文音信存入到fs.files中。

启动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

分片时服务器角色

图片 7

地点讲了分片的规范,上面是切实在分片时的两种节点角色

  • 客户端访问路由节点mongos来开展数据读写
  • config服务器保存了多少个映射关系,一个是key值的间隔对应哪一个chunk的映照关系,另一个是chunk存在哪一个分片节点的炫耀关系
  • 路由节点通过config服务器获取数据音讯,通过这么些音讯,找到真正存放数据的分片节点开展对应操作
  • 路由节点还会在写操作时判断当前chunk是还是不是高于限定大小,如果超出,就分列成八个chunk
  • 对此按分片key举办的询问和update操作来说,路由节点会查到实际的chunk然后再开展有关的做事
  • 对此不按分片key举行的查询和update操作来说,mongos会对所有下属节点发送请求然后再对回到结果举办合并
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...")     //文件的二进制数据,这里省略了具体内容
}
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.files集合存放文件的消息,fs.chunks存放文件数量。

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

网站地图xml地图