1、单机小文件的存储,逐步增加上传文件的大小,观察mongoDB中文件对磁盘分配大小的变化。
2、采用分片的方式存储大量的数据
实验一:
首先建立一个数据库gywdb,上传一个574.5kB大小的文件,代码如下:
代码如下 | 复制代码 |
View Code namespace mongoDBClient } |
运行命令:> show collections
gyw.chunks
gyw.files
可以看到得到了一个前缀为gyw的文件元数据存储的集合gyw.files和存储文件数据块的gyw.chunks
代码如下 | 复制代码 |
运行命令> db.gyw.chunks.find({},{"_id":1,"n":1}) { "_id" : ObjectId("4fc0a6d91d41c808f45cbfec"), "n" : 0 } { "_id" : ObjectId("4fc0a6d91d41c808f45cbfed"), "n" : 1 } { "_id" : ObjectId("4fc0a6da1d41c808f45cbfee"), "n" : 2 } |
得到3个块数据,因为文件总大小为574.5KB,每个块采用的是默认大小256KB,所以得到了3个块。此时磁盘文件系统中,mongoDB自动生成了3个文件分别是:
gywdb.0(大小为64MB),gywdb.1(大小为128MB),gywdb.ns(存储命名空间源数据),这里分配机制体现了mongoDB的文件分配策略,每个数据库有一个.ns文件和若干个数据文件
,数据文件以递增的数字结尾。每个新的以数字结尾的数据文件大小会加倍,直到达到最大值2GB,这是为了让小数据库不浪费太多的磁盘空间,同时让大数据使用磁盘上连续的空间。
MongoDB为了保证性能还会预分配数据文件,这意味着MongoDB服务器总是试图为每一个数据库保留一个额外的空数据文件,来避免文件分配所产生的阻塞。
接着利用上面的代码再上传一个大小为2.4MB大小的文件到mongoDB的文件系统中
代码如下 | 复制代码 |
运行命令:> db.gyw.chunks.find({},{"_id":1,"n":1,"files_id":1}) |
可以看到块中多了10个块,而且第一次上传的文件块中“files_id" 为 ObjectId("4fc0a6d91d41c808f45cbfe9"),第二次上传的文件为ObjectId("4fc0a8cf1d41c80910191102"),
这个files_id代表了这个块是属于那个文件的。如下命令显示了文件系统中文件元数据信息
代码如下 | 复制代码 |
> db.gyw.files.find() { "_id" : ObjectId("4fc0a6d91d41c808f45cbfe9"), "filename" : "百度大规模数据处理", "length" : 588276, "chunkSize" : 262144, "uploadDate" : ISODate("2012-05-26T09:48:09.357Z"), "md5" : "5e55fb7496d41a52eb90daeac9e06936" } { "_id" : ObjectId("4fc0a8cf1d41c80910191102"), "filename" : "Google三大论文中文版", "length" : 2526950, "chunkSize" : 262144, "uploadDate" : ISODate("2012-05-26T09:56:31.143Z"), "md5" : "605f1deec1a277e3d878dfc6f3491cce" } |
这个里面的"_id"值正好对应了上面块中的“files_id”
这时在观察磁盘文件系统中mongoDB自动生成的文件,发现和第一次一样,说明数据还没达到第一个数据文件gywdb.0的总大小(64MB)。
接着再利用上面的代码上传一个大小为112.2MB大小的文件到mongoDB的文件系统中,利用命令:
代码如下 | 复制代码 |
> db.gyw.files.find() { "_id" : ObjectId("4fc0a6d91d41c808f45cbfe9"), "filename" : "百度大规模数据处理", "length" : 588276, "chunkSize" : 262144, "uploadDate" : ISODate("2012-05-26T09:48:09.357Z"), "md5" : "5e55fb7496d41a52eb90daeac9e06936" } { "_id" : ObjectId("4fc0a8cf1d41c80910191102"), "filename" : "Google三大论文中文版", "length" : 2526950, "chunkSize" : 262144, "uploadDate" : ISODate("2012-05-26T09:56:31.143Z"), "md5" : "605f1deec1a277e3d878dfc6f3491cce" } { "_id" : ObjectId("4fc0b3a31d41c8099f80a9ac"), "filename" : "微软官方2010年宽屏PPT图表全集400张锐普PPT论坛首发", "length" : 117652480, "chunkSize" : 262144, "uploadDate" : ISODate("2012-05-26T10:42:43.773Z"), "md5" : "506810e215c773addc3ce10a035695d9" } |
发现多了一个文件微软官方2010年宽屏PPT图表全集400张锐普PPT论坛首发,证明上传成功了,再观察磁盘文件系统中mongoDB自动生成的文件,发现多了一个gywdb.2(大小为256MB),这证明了mongoDB文件分配机制。
实验二:数据的分布式存储即分片测试
准备:两台分片服务器(在同一台主机上,通过端口来区分,分别为:20000,20001),一台路由服务器(端口为:40000,所有的读写请求都必须经过它),一台配置服务器(端口为:30000)
代码如下 | 复制代码 |
root@ubuntu:/# mkdir -p /data/shard/s0
|
上面的命令为启动配置服务器端口为3000
# ./mongos --port 40000 --configdb localhost:30000 --fork --logpath /data/shard/log/route.log
上面的命令是启动路由服务器,注意里面的参数configdb表示配置服务器的位置,因为路由服务器启动时需要从配置服务器上获取相应的信息
下面的命令是连接路由服务器并做一些配置:
代码如下 | 复制代码 |
root@ubuntu:/usr/local/mongoDB/bin# ./mongo admin --port 40000 MongoDB shell version: 2.0.4 connecting to: 127.0.0.1:40000/admin mongos> db.runCommand({addshard:"localhost:20000"}) { "shardAdded" : "shard0000", "ok" : 1 } mongos> db.runCommand({addshard:"localhost:20001"}) { "shardAdded" : "shard0001", "ok" : 1 } mongos> db.runCommand({enablesharding:"userDB"}) { "ok" : 1 } |
上面的命令完成了将两个服务器添加到分片集群中,在端口为40000的路由服务器上建立了一个数据库userDB,并将此数据库配置为可以进行分片。
接下来通过C#编写代码,完成文件的上传,观察数据被分片存储的情况,代码如下:
代码如下 | 复制代码 |
View Code namespace mongoDBClient } |
上传了一个112.2MB的文件到路由服务器中。通过以下命令观察下此时数据库中集合情况
代码如下 | 复制代码 |
mongos> use userDB system.indexes |
此时数据库中有新增加了两个集合userdata.chunks和userdata.files,其中userdata.chunks是真正存储数据的地方。以下命令观察此集合的概况
代码如下 | 复制代码 |
mongos> db.userdata.chunks.stats() { "sharded" : false, "primary" : "shard0000", "ns" : "userDB.userdata.chunks", "count" : 449, "size" : 117711616, "avgObjSize" : 262163.95545657014, "storageSize" : 135131136, "numExtents" : 12, "nindexes" : 2, "lastExtentSize" : 26034176, "paddingFactor" : 1, "flags" : 1, "totalIndexSize" : 57232, "indexSizes" : { "_id_" : 24528, "files_id_1_n_1" : 32704 }, "ok" : 1 } |
其中 "sharded" : false表明此表还没进行分片存储,路由服务器此时将数据全部保存到分片0所对应的服务器中了,文件的大小为117711616字节,在linux下通过文件系统的命令:
代码如下 | 复制代码 |
root@ubuntu:/usr/local/mongoDB/bin# cd /data/shard/s0/userDB root@ubuntu:/data/shard/s0/userDB# ls -l 总用量 475156 drwxr-xr-x 2 root root 4096 2012-05-27 16:57 _tmp -rw------- 1 root root 67108864 2012-05-27 16:57 userDB.0 -rw------- 1 root root 134217728 2012-05-27 16:57 userDB.1 -rw------- 1 root root 268435456 2012-05-27 16:57 userDB.2 -rw------- 1 root root 16777216 2012-05-27 16:57 userDB.ns |
发现文件确实被存在分片0所对应的服务器中。
继续上传更大的文件到路由服务器,突破分片设置中的默认块的大小200MB,看是什么情况?代码仍然如上,只是修改上传的文件,上传的文件大小为:393.0MB
代码如下 | 复制代码 |
View Code namespace mongoDBClient } |
首先通过以下命令观察root@ubuntu:/data/shard/s0/userDB# ls -l
总用量 2048028
drwxr-xr-x 2 root root 4096 2012-05-27 17:22 _tmp
-rw------- 1 root root 67108864 2012-05-27 17:22 userDB.0
-rw------- 1 root root 134217728 2012-05-27 17:22 userDB.1
-rw------- 1 root root 268435456 2012-05-27 17:22 userDB.2
-rw------- 1 root root 536870912 2012-05-27 17:22 userDB.3
-rw------- 1 root root 1073741824 2012-05-27 17:22 userDB.4
-rw------- 1 root root 16777216 2012-05-27 17:22 userDB.ns
发现文件还是被存到默认的分片服务器0上。分片1上的数据还没有。尽管文件的总大小已经达到了需要分片存储的条件,即块的大小200MB
因此下面需要重新设置路由服务器,使其对集合userDB.userdata.chunks(这个里面存储了用户上传的文件)进行分片。
要想实现海量数据的分布式存储,那么就要对集合进行分片,因此片键的选择是至关重要的,它直接决定了集群中数据分布是否均衡、集群性能是否合理。那么我们究竟该选择什么样的字段来作为分片Key呢?这是个需要反复实践总结的地方。由于这里利用了分布式文件系统GridFS,因此有几点要说明(碰到错误,在网上查到的http://blog.111com.net/zhangzhaokun/article/details/6324389):GridFS
根据需求的不同,GridFS有几种不同的分片方法。基于预先存在的索引是惯用的分片办法:
1)“files”集合(Collection)不会分片,所有的文件记录都会位于一个分片上,高度推荐使该分片保持高度灵活(至少使用由3个节点构成的replica set)。
2)“chunks”集合(Collection)应该被分片,并且用索引”files_id:1”。已经存在的由MongoDB的驱动来创建的“files_id,n”索引不能用作分片Key(这个是一个分片约束,后续会被修复),所以不得不创建一个独立的”files_id”索引。使用“files_id”作为分片Key的原因是一个特定的文件的所有Chunks都是在相同的分片上,非常安全并且允许运行“filemd5”命令(要求特定的驱动)。
前面已经分析过,在userDB.userdata.chunks集合中每一个记录都有一个字段file_id,代表了此块属于哪个文件,因此这里建一个以file_id的索引,以此字段键做为片键,同一个文件的块会被分配到同一个分片下
mongos> db.userdata.chunks.ensureIndex({files_id:1})
设置片键的命令如下:
代码如下 | 复制代码 |
mongos> db.runCommand({shardcollection:"userDB.userdata.chunks",key:{files_id:1}} { "collectionsharded" : "userDB.userdata.chunks", "ok" : 1 } |
再次查看此表的状态: "sharded" : true说明此集合被分片了。
代码如下 | 复制代码 |
mongos> db.userdata.chunks.stats() |
多次执行如下代码上传文件后:执行如下命令观看系统中存在的文件
mongos> db.userdata.files.find()
{ "_id" : ObjectId("4fc1ec6c1d41c809ed4230d3"), "filename" : "微软官方2010年宽屏PPT图表全集400张锐普PPT论坛首发", "length" : 117652480, "chunkSize" : 262144, "uploadDate" : ISODate("2012-05-27T08:57:16.676Z"), "md5" : "506810e215c773addc3ce10a035695d9" }
{ "_id" : ObjectId("4fc1f2451d41c80b0f29eda1"), "filename" : "软件源代码", "length" : 412116413, "chunkSize" : 262144, "uploadDate" : ISODate("2012-05-27T09:22:13.443Z"), "md5" : "28cadbb180093dbcd15b25f0e741ae0a" }
{ "_id" : ObjectId("4fc1fe7d1d41c80b4d4a17cb"), "filename" : "新的软件源代码", "length" : 412116413, "chunkSize" : 262144, "uploadDate" : ISODate("2012-05-27T10:14:21.845Z"), "md5" : "28cadbb180093dbcd15b25f0e741ae0a" }
{ "_id" : ObjectId("4fc212541d41c80ba8e1180f"), "filename" : "新微软PPT", "length" : 117652480, "chunkSize" : 262144, "uploadDate" : ISODate("2012-05-27T11:39:00.598Z"), "md5" : "506810e215c773addc3ce10a035695d9" }
{ "_id" : ObjectId("4fc21b9e1d41c80747e207e8"), "filename" : "新微软PPT1", "length" : 117652480, "chunkSize" : 262144, "uploadDate" : ISODate("2012-05-27T12:18:38.183Z"), "md5" : "506810e215c773addc3ce10a035695d9" }
可以看到实验上传了5个文件
执行以下命令观察文件分块后在集群中的部署情况:
代码如下 | 复制代码 |
mongos> db.userdata.chunks.stats() { "sharded" : true, "flags" : 0, "ns" : "userDB.userdata.chunks", "count" : 4493, "numExtents" : 35, "size" : 1177568872, "storageSize" : 1274904576, "totalIndexSize" : 531440, "indexSizes" : { "_id_" : 163520, "files_id_1" : 155344, "files_id_1_n_1" : 212576 }, "avgObjSize" : 262089.66659247718, "nindexes" : 3, "nchunks" : 3, "shards" : { "shard0000" : { "ns" : "userDB.userdata.chunks", "count" : 4044, "size" : 1059857256, "avgObjSize" : 262081.4183976261, "storageSize" : 1139773440, "numExtents" : 23, "nindexes" : 3, "lastExtentSize" : 193486848, "paddingFactor" : 1, "flags" : 0, "totalIndexSize" : 449680, "indexSizes" : { "_id_" : 138992, "files_id_1_n_1" : 179872, "files_id_1" : 130816 }, "ok" : 1 }, "shard0001" : { "ns" : "userDB.userdata.chunks", "count" : 449, "size" : 117711616, "avgObjSize" : 262163.95545657014, "storageSize" : 135131136, "numExtents" : 12, "nindexes" : 3, "lastExtentSize" : 26034176, "paddingFactor" : 1, "flags" : 1, "totalIndexSize" : 81760, "indexSizes" : { "_id_" : 24528, "files_id_1_n_1" : 32704, "files_id_1" : 24528 }, "ok" : 1 } }, "ok" : 1 } |
执行命令观察分片的概况
代码如下 | 复制代码 |
printShardingStatus() |
至此一个简单的分布式文件存储模型实验完毕!