MongoDB的分布式文件存储系统

MongoDB的BSON对象存储文件有限制,大于16MB时使用GridFS。小文件可直接存储,大文件分块存储在fs.files和fs.chunks集合。GridFS读取涉及两次查询,适合大文件,不适用于小文件。分块大小256KB,不同于分片块大小64MB。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

对于MongoDB的存储基本单元BSON文档对象,字段值可以是二进制类型,基于此特点,我们可以直接在MongoDB中存储文件,但是有一个限制,由于MongoDB中单个BSON对象不能大于16MB,故而如果需要存储更大的文件,就需要GridFS了。

小文件存储系统与GridFS文件存储

我们先看下MongoDB存储小文件系统的例子:

先采用MongoDB的mongofiles执行文件上传:

D:\MongoDB\Server\3.2\bin>mongofiles.exe list
2017-03-06T13:41:03.283+0800    connected to: localhost

D:\MongoDB\Server\3.2\bin>mongofiles.exe put E:\deliveryTask.doc
2017-03-06T13:41:23.535+0800    connected to: localhost
added file: E:\deliveryTask.doc

D:\MongoDB\Server\3.2\bin>mongofiles.exe list
2017-03-06T13:41:30.114+0800    connected to: localhost
E:\deliveryTask.doc     2971

通过mongos命令查看文件存储情况:

> use test
switched to db test
> show collections
fs.chunks
fs.files
restaurants
user
> db.fs.files.find()
{ "_id" : ObjectId("58bcf683afa0fa20bc854a2b"), "chunkSize" : 261120, "uploadDat
e" : ISODate("2017-03-06T05:41:23.604Z"), "length" : 2971, "md5" : "5434b8033062
99fff57c8a54d3adf78b", "filename" : "E:\\deliveryTask.doc" }

可以看到文件上传成功了

由于本章节主要涉及到的是部分理论以及运维实践,暂不涉及具体代码的开发实现(具体代码将以Java为例在后面章节中介绍)。

上传一个大于16MB的文件试一试:

D:\MongoDB\Server\3.2\bin>mongofiles.exe put E:\synch.rar
2017-03-06T14:33:11.028+0800    connected to: localhost
added file: E:\synch.rar

D:\MongoDB\Server\3.2\bin>mongofiles.exe list
2017-03-06T14:33:15.265+0800    connected to: localhost
E:\deliveryTask.doc     2971
E:\synch.rar    24183487

通过mongos命令查看文件存储情况:

> db.fs.files.find()
{ "_id" : ObjectId("58bcf683afa0fa20bc854a2b"), "chunkSize" : 261120, "uploadDate" : ISODate("2017-03-06T05:41:23.604Z"), "length" : 2971, "md5" : "5434b803306299fff57c8a54d3adf78b", "filename" : "E:\\deliveryTask.doc" }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "chunkSize" : 261120, "uploadDate" : ISODate("2017-03-06T06:33:12.013Z"), "length" : 24183487, "md5" : "bbfe4d8579372aa0729726185997e908", "filename" : "E:\\synch.rar" }

也成功了,

查看chunks:

> db.fs.chunks.find({},{data:0})
{ "_id" : ObjectId("58bcf683afa0fa20bc854a2c"), "files_id" : ObjectId("58bcf683afa0fa20bc854a2b"), "n" : 0 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b2d"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 0 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b2e"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 1 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b2f"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 2 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b30"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 3 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b31"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 4 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b32"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 5 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b33"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 6 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b34"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 7 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b35"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 8 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b36"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 9 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b37"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 10 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b38"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 11 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b39"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 12 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b3a"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 13 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b3c"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 15 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b3b"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 14 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b3e"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 17 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b3d"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 16 }
{ "_id" : ObjectId("58bd02a7afa0fa21d4a14b3f"), "files_id" : ObjectId("58bd02a7afa0fa21d4a14b2c"), "n" : 18 }
Type "it" for more

可以看到大文件被分成了好多个chunk,那么为什么上传16MB以上的文件也会成功呢,因为我们采用的就是GridFS系统存储的文件,因为我们采用的是mongfiles方式上传的文件。

下面分别是查询、下载、删除操作:

D:\MongoDB\Server\3.2\bin>mongofiles.exe search rar
2017-03-06T14:45:31.974+0800    connected to: localhost
E:\synch.rar    24183487

D:\MongoDB\Server\3.2\bin>mongofiles.exe --local D:\mongodb_download.rar get E:\synch.rar
2017-03-06T14:47:17.841+0800    connected to: localhost
finished writing to D:\mongodb_download.rar

D:\MongoDB\Server\3.2\bin>mongofiles.exe delete E:\synch.rar
2017-03-06T14:47:56.649+0800    connected to: localhost
successfully deleted all instances of 'E:\synch.rar' from GridFS

D:\MongoDB\Server\3.2\bin>mongofiles.exe list
2017-03-06T14:48:03.886+0800    connected to: localhost
E:\deliveryTask.doc     2971

实际上,我们还可以自定义集合的前缀,默认是fs,或者设置chunk的大小,默认是256KB。

总结

那么在实际场景的分布式文件存储系统中如何确定改用哪种存储方案呢,可以采用如下方式:
1. 对于用户上传的任何文件,在客户端进行大小判断;
2. 当文件大小小于16MB时,则直接存储到MOngoDB普通集合中
3. 当文件大小大于16MB时,上传到GridFS中,利用集合fs.files以及fs.chunks来保存文件
4. 当用户下载文件时,再根据不同文件的大小属性不同到不同的集合中查找

另外,对于fs.chunks文件我们可以分片存储,片键可以选择索引字段{“files_id”},该字段尽量保证了此文件在所有被分割的chunk都在同一个片上,fs.files不需要分片,此集合只保存文件的元数据信息,数据量不大,同时还可以设置默认块大小(256KB)

需要注意的是:GridFS并不适合小文件存储,因为从GridFS中读取文件涉及到两次查询操作,先查询fs.files集合,再查询fs.chunks集合,chunks合并后获取整个文件。

需要注意的另一点是:文件分块大小为256KB,而分片的块大小默认64MB,不要搞混了。

### MongoDB 分布式文件存储机制及原理 #### GridFS 文件存储方式 为了处理大尺寸文件MongoDB 提供了名为GridFS的功能。该功能允许将单个文件拆分为多个部分并分别存储于不同的文档中[^2]。 当文件被上传至GridFS时,会被切分成固定大小的数据块,默认情况下每块大小为4 MB。这些数据块随后作为独立的文档存入`chunks`集合内。与此同时,在另一个称为`files`的集合里创建一条记录来描述整个文件的信息,包括但不限于文件名称、长度以及元数据等属性。这种设计使得即使面对超大规模文件也能保持良好的性能表现和灵活性。 #### 数据分布策略——分片技术的应用 对于非常庞大的文件集或高并发访问场景下,仅依靠单一实例难以满足需求。此时可以借助MongoDB 的分片特性进一步优化GridFS的工作模式。通过配置合适的 shard key ,能够有效地把 `files` 和 `chunks` 集合中的数据均匀散布到各个成员节点之上,从而实现负载均衡的目的;同时也便于后续扩展集群规模以应对不断增长的数据量挑战[^3]。 ```python from pymongo import MongoClient, ASCENDING client = MongoClient('mongodb://localhost:27017/') db = client['mydatabase'] # Enable sharding on the database and collections used by GridFS. admin_db = client.admin admin_db.command({'enableSharding': 'mydatabase'}) admin_db.command({ "shardCollection": "mydatabase.fs.files", "key": {"filename": 1} }) admin_db.command({ "shardCollection": "mydatabase.fs.chunks", "key": {"files_id": 1, "n": 1} }) # Create indexes to support efficient queries over chunks collection. db['fs.chunks'].create_index([("files_id", ASCENDING), ("n", ASCENDING)]) ``` 上述代码展示了如何在一个已启用分片特性的环境中设置适合GridFS使用的shard key 及必要的索引结构。这有助于提高查询效率,并确保数据能够在集群间合理分配。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值