设为首页 收藏本站
查看: 797|回复: 0

[经验分享] 将网站中用户上传的零散小文件存储在MongoDB中的.net解决方案

[复制链接]

尚未签到

发表于 2015-7-10 10:28:09 | 显示全部楼层 |阅读模式
  这几年来Web服务器中用户文件的存储一直是我的一个心病,基于成本考虑,网站初始没有单独的服务器可供存储专用,基于上就只能放在Web站点所在 的机器上,所以目录式存储就顺理成章了。然后,当数据量大到这个分区放不下的时候,只好加硬盘,而如果不想改变原来读写代码,就要把原来的整个目录再复制 到新的分区上。虽然在Uploads目录下通过日期建立子目录,可以通过在IIS中将不同日期的子目录使用虚拟目录指向不同磁盘的方式,但是这样同样会导 致另外一些非Web式的处理程序无法读取文件的真实位置。后来虽然采购了专用的存储服务器,但是使用的IPSAN存储方式,对Windows服务器来讲, 它还是个普通的硬盘分区。当同一个分区上文件数量达到一定量的时候,光分区表本身的容量就已经是个恶梦,无论是性能还是文件的安全性,一旦系统崩溃,这些 海量文件根本恢复不出来。以前找到的最好的解决方案是一种Hash存储的服务器,通过Api或者HTTP接口调用,返回一个Key(就是文件的MD5), 读取文件的时候也使用这个MD5,同时还可以解决内容一样文件名不同的文件重复浪费空间的问题。不过这个方案国内没有成熟的提供商,EMC家倒是有,40 万起。
  现在终于有了另一个便宜的解决方案,那就是MongoDB的GridFS。在其官方文档中对于适用场景的解释是:1、大量文件。2、用户上传的文 件。3、经常需要修改的文件。不适用的场景:1、少量静态文件。2、需要经常原子级修改的文件。作为初始的使用环境,只需要一个Server。当内容的量 大到一定程度的时候,就可以很容易的建立负载均衡,同时,所有的零散小文件都存储在有限的几个大文件中,备份也变得简单了。而且MongoDB会自动把需 要使用的数据放到内存中,虽然内存使用量会增加不少,但是性能却比直接读写目录文件还要快。
  另外,还有一个好处,它提供了原生Windows程序,而且是单一exe文件,使用极其方便。虽然性能和稳定性可能不如Linux版,不过,目前应该够用了。以后随时可以单独加一台大内存大硬盘的Linux服务器专门用来做存储。
  下载:(win2008 64位版)
  http://downloads.mongodb.org/win32/mongodb-win32-x86_64-2008plus-2.0.5.zip
  下载后直接解压到任意目录,里面的mongod.exe就是服务主程序,在你准备用来存储文件的地方建立一个data目录,再建一个logs目录,就可以把这个程序安装成windows服务来运行了。用cmd进入程序所在的目录,执行
  mongod.exe –dbpath=f:/mongo/data –logpath=f:/mongo/logs/ –logappend –directoryperdb –install
  服务就安装完成了,可以进入服务管理启动它,然后去logs目录下看看里面的日志,有没有出现错误就可以了。
  在.net中读写mongodb也很简单,去git下载官方C#驱动,https://github.com/mongodb/mongo-csharp-driver,自己编译一下项目,引用生成的两个dll就可以了。
  读写前需要两个固定的变量:
  MongoServer server = MongoServer.Create(“mongodb://localhost:27017″);
  MongoDatabase db = server.GetDatabase(“Main”);
  每一个名字的db会自动创建一个独立的目录,以后拆分到独立的服务器也会方便一些。这两个连接可以每次建立新连接,也可以建立一个连接,放到静态变量里全局调用。
  剩下的事就容易多了:
  把文件保存到db里:
  db.GridFS.Upload(stream, fullPath);
  这个stream可以是HttpPostedFile.InputStream对象,所以对于用户上传的文件,直接把这个变量传进来就可以了,也可 以是一个本地文件的路径,它会自己去读这个文件,后面的FullPath变量是这个文件的文件名,也是该文件在系统中的身份标志,所以必须使用带完整路径 的文件名,当然,可以使用相对路径,它只是个标志,没有实际用途。所以对于原来的计算出一个路径,然后调用file.SaveAs(path)的代码,只 需要改成上面这个db.GridFS.Upload(file.InputStream, path);就OK了。其它代码全部都不影响。
  读取db中的某个文件:
  var file = db.GridFS.FindOne(path); 这个path就是保存的时候传入的那个文件名,返回的这个对象包含了文件的大小,ContentType,要读取内容可以使用:
  using (var stream = file.OpenRead())
{
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
}
  就得到了完整内容的byte数组,返回给用户或者进行其它操作就可以了。
  删除文件:db.GridFS.Delete(path);
  当我批量把原来的某个目录下500多M的900多个文件写入数据库以后,在数据库目录下生成了四个存储文件,大小分别是 64M,128M,256M,512M,估计继续写下去下面生成的文件就1G了,另外有一个16M的索引文件。服务占用内存400多M。并不是所有文件都 会读到内存里,只是把最近用到的会放到内存里面,所以目前也不用太担心内存占用问题。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-85139-1-1.html 上篇帖子: MongoDB数据库常用命令 下篇帖子: MongoDB学习笔记——初体验
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表