在各种系统应用服务端开发中,咱们常常会遇到文件存储的问题。 常见的磁盘文件系统,DBMS传统文件流存储。今天咱们看一下基于NoSQL数据库MongoDb的存储方案。笔者环境 以CentOS 6.5,MongoDb 2.6.3, Nginx-1.4.7 为例,您须要了解Linux经常使用命令。
先来回顾一下MongoDb的内部文件结构javascript
而后是GridFs的结构html
GridFS在数据库中,默认使用fs.chunks和fs.files来存储文件。java
其中fs.files集合存放文件的信息,fs.chunks存放文件数据。linux
一个fs.files集合中的一条记录内容以下,即一个file的信息以下:nginx
{ "_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以下:c++
{ "_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中。git
在读取文件的时候,先据查询的条件,在fs.files中找到一个合适的记录,获得“_id”的值,再据这个值到fs.chunks中查找全部“files_id”为“_id”的chunk,并按“n”排序,最后依次读取chunk中“data”对象的内容,还原成原来的文件。
github
1.安装mongoDbmongodb
增长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
# /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
咱们使用以下片断代码:
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,也能够经过客户端的驱动程序来产生。
来自官方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模式的同步流程
上面讲了分片的标准,下面是具体在分片时的几种节点角色
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
若有想了解更多软件,系统 IT,企业信息化 资讯,请关注个人微信订阅号:
做者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利。
该文章也同时发布在个人独立博客中-Petter Liu Blog。