本文共 3828 字,大约阅读时间需要 12 分钟。
分片(sharding)是指将数据拆分,将其分散存在不同的机器上的过程。将数据分散到不同的机器上,不需要功能强大的大型计算机就可以存储更多的数据,处理更大的负载。
手动分片:几乎所有的数据库软件都能进行手动分片。应用需要维护与不同数据库服务器的链接,管理不同服务器上的数据,存储、查询都在不同服务器上进行。这种方法可以很好地工作,但是不易维护,从集群中增删节点困难,调整数据分布和负载模式也不轻松。
自动分片:mongodb支持自动分片,集群自动切分数据,做负载均衡。可以摆脱手动分片的管理困扰。
Mongodb分片的基本思想就是将集合切分成小块。这些块分散到若干片里面,每个片只负责总数据的一部分。应用程序不必知道哪片对应哪些数据,甚至不需要知道数据已经被拆分了,所以之前需要启动一个路由进程,即mongos。
Mongos知道所有数据的存放位置,所以应用可以连接它来正常发送请求。对应用来说,它仅知道连接了一个普通的mongod。Mongos隐藏了分片的细节,对客户端来说是透明的。跟普通的mongod没什么两样。
Mongod-server:mongodb进程服务器,一般指具体分片的服务器
mongoConfig-server:配置服务器,存储了集群的配置信息:数据和片的对应关系。Mongos不永久存放数据,所以需要个地方存放分片配置。它会从配置服务器获取同步数据。
Mongs-server:路由进程,一般客户端连接的是这个。它路由所有请求,然后将结果聚合。它本身并不存储数据或者配置信息(但会缓存配置服务器的信息)。
1. 机器的磁盘不够用了
2. 单个mongod已经不能满足写数据的性能需求了
3. 湘江大量数据放在内存中提高性能。
一般来说,先要从不分片开始,然后在需要时将其转换成分片的。
分片时,需要从集合里选一个键,用该键的值作为数据拆分的依据,这个键被称为片键(shard key)。
如:用name作为片键,第一片可能会存放名字以A-F开头的文档,第二片存储G-P开头的名字,第三片存储Q-Z的名字。随着添加、删除片,MongoDB会重新平衡数据,使每片的流量都比较均衡,数据量也在合理范围内。
建立分片有两步:启动实际的服务器,然后决定怎么切分数据.
分片一般会有3个组成部分:
a.片
片就是保存子集合数据的容器,片可是单个的mongod服务器(开发和测试用),也可以是副本集(生产用).所以一片
有多台服务器,也只能有一个主服务器,其他的服务器保存相同的数据.
b.mongos
mongos就是MongoDB配的路由器进程.它路由所有的请求,然后将结果聚合.它本身并不存储数据或者配置信息
但会缓存配置服务器的信息.
c.配置服务器
配置服务器存储了集群的配置信息:数据和片的对应关系.mongos不永久存房数据,所以需要个地方存放分片的配置.
它会从配置服务器获取同步数据.
目标:192.168.229.79 、192.168.229.80 两台服务器作为mongod服务器,分别为shard1,shard2. 192.168.229.80 作为配置和路由服务器。
前提:下载mongo包,解压,安装目录为:/export/servers/mongodb-linux-x86_64-2.0.4
1. 在79上启动mongod进程
mkdir -p ./data/shard1 bin/mongod -shardsvr -port 27017 -dbpath=./data/shard1/ -logpath=./data/shard1.log --fork |
2. 在80上启动mongod进程
mkdir -p ./data/shard2 bin/mongod -shardsvr -port 27017 -dbpath=./data/shard2/ -logpath=./data/shard2.log --fork |
通过ps命令查看下进程,如图:
如果没启动成功看下data目录的权限,设为root权限:
sudo chmod -R 777 /data/shard11 |
3. 在80上启动mongconfig进程
mkdir /data/config bin/mongod -configsvr -dbpath=./data/config -port 20000 -logpath=./data/config.log --fork |
config启动一台即可,同样通过ps命令查看是否已启动。
注意上述三个步骤的命令,mongod是-shardsvr,config是configsvr。
4. 在80上启动mongos进程
bin/mongos -configdb 192.168.229.80:20000 -port 30000 -chunkSize 1 -logpath=./data/mongos.log --fork |
注意上述几个标蓝的内容:
命令:configdb
192.168.229.80:20000:这个是步骤3中的配置服务器的ip和端口
chunkSize:一般默认是64M,但是为了测试,我们把它改小,设为1M。
Chunks:mongodb不是一个分片上存储一个空间,而是每个分片包含多个区间,每个区间就是一个块。
平衡:如果存在多个可用的分片,只要块的数量足够多,mongodb就会把数据迁移到其他分片上,这个迁移的过程叫做平衡。
5. 链接mongos
如图:我在192.168.192.75上链接80的mongs进程
6. 添加片
db.runCommand({"addshard":"192.168.229.79:27017"}) db.runCommand({"addshard":"192.168.229.80:27017"}) |
如果顺利,你应该能看到{ ”ok“ : 1}的字样。这样你就成功的把两个shard加入了分片。现在你还需要制定分片的规则。
7. 激活分片设置
db.runCommand({"enablesharding": "ndmongo"}) |
8. 添加片键
db.runCommand({"shardcollection":"mydb.user", "key":{"_id":1}}) |
Mydb:我的测试数据库名称
User: 我的测试集合名称
Key: "_id"为我定义的文档的一个字段。
如:
9. 查看状态
通过:
db.printShardingStatus() |
如图:
10. 执行测试数据
mongos> for(i=0;i<1000000;i++){ db.user.insert({ "_id":i}); } |
注意,这里一定要从mongos进程添加数据,最开始我从单片(79)上添加了1万条,发现从mongos查询不到。
11. 查询平衡结果
分片在自动移动:
80:
:79:
查看mongos状态:
继续查看79:
查看80:
再次查看mongos状态:
可以看到这次平衡了。
> db.users.save({"name":"zhangsan"})
_filename.empty()
而80上是ok的。
最后怀疑是没有空间所致,查看目录,果然,mydb没有空间可以预分配:
删除admin数据库:
重新插入数据,结果ok:
如图:
可以看到里面有2种文件,一种是mydb.n(n表示数字,从0开始,由于我用的是64位机器,所以文件从64M开始,每次翻倍,直到2G后每次都生成2G),这是数据文件,数据文件在内部分为很多块,每一块保存一个名字空间的数据,块与块之间用链表连接,每块中的每条数据间也用链表连接。还有一个是16m的文件mydb.ns,mydb.ns是一个命名空间文件,用来保存名字空间对应的元数据,mydb.ns是一个hashtable,保存了每个名字空间中的储存信息,包括大小,块数,第一块位置,最后一块位置,索引信息等,而块的位置又通过文件序号(后面跟的数字)与文件中的偏移量来确定。
需要注意的是,我现在数据库里面只有一条不到2k的数据,为什么会有2个数据文件,一个64m,一个128m呢?
这正是由mongodb的存储空间预先分配决定的,当你开始往64m的文件中存储数据时,同时mongodb会预先分配一个128m的文件空间,并且用0来填充,这样每次都有一个文件的空间是完全没有存放数据的,虽然浪费了一定大小的空间,但是也免去了每次写入时分配空间消耗的时间,加快了存储速度。
看一下我在网上找的一张图片,mongodb的文件内部存储结构:
mongodb在数据存储上按命名空间来划分,一个Collection是一个命名空间,一个索引也是一个命名空间。
同一个命名空间的数据被分成很多个Extent,Extent之间使用双向链表来连接。
在每一个Extent中,保存了具体每一行的数据,这些数据也是通过双向链表来连接的。
参考: