在Mongodb中扩展可以通过横向扩展数据来处理,这种操作叫做分片。
通过跨服务器横向划分数据集,每台服务器负责处理自己的数据部分同时不会有一台服务器会负载过重,这样分片就可以支持大数据集和高吞吐量。每一个分片都是一个独立的数据库,所有的分片共同组成单个的逻辑数据库。
分片数据服务器:
分片数据服务器就是存储实际数据的组件 它可以是一个mongod或者一个副本集,所有的分片数据合并起来就是分片集群里的完整数据集。
配置服务器:
配置服务器是一个特殊的mongod,它会保存分片集群的元数据,这些元数据描述了分片系统的状态和组织,配置服务器会将数据保存在配置数据库中,只有在平衡集群的时候对数据分布的变更时,mongodb才会将数据写到配置服务器。
mongos:
mongos是一个路由服务器,它负责将读取和写入请求从应用程序路由到分片,对于客户端来说它们不需要关心在分片内部是如果存储数据的,它们仅跟mongos交互,mongos会将读取和写入请求路由到分片。同时 mongos会缓存来片配置服务器的元数据,这样对于每一个读取和写入请求就不会让配置服务器承担过重的负荷。只有在下面这两种情况下才会从配置服务器读取数据:
在mongodb中会在集合级别对数据分片,集合是由分片键来划分的。
分片键:
在集合文档中任何索引的单一/复合字段都可以做为一个分片键。我们需要指定分片键,mongodb会根据该分片键的值来将文档划分成多块并且跨分片分发它。mongodb有下面几种方式来启用数据分发:
添加新的数据或者迁移已有的数据,或者添加和移除服务器都会导致数据分布的失衡。这就导致有一些分片负荷过重,有些分片负荷比较小,mongodb分使用下面的方式来确保平衡:
数据块划分
数据块划分是其中一个程序,它会确保数据块都是指定的大小,如果由于插入或者更新导致数据块的大小发生了变更,并且超出了默认的数据块大小,那么该数据块就会被mongos划分成两个较小的数据块,此过程会将数据块保持在指定的大小或者小于指定大小的一个分片中
平衡器
平衡器也是一个后台程序,它被用来确保所有分片的负荷都均等或者处理一种平衡状态,这个程序会管理数据块迁移。
数据块的迁移或者添加移除文档都会造成集群的失衡。出现失衡的情况时就会使用平衡器,当一个分片的数据块比其他分片多时,mongodb会跨分片自动完成数据块平衡,这个过程对用户来说是透明的。
分片服务器配置计划如下:
组件 | 类型 | IP:端口 |
---|---|---|
分片路由器 | Mongos | 192.168.70.128:27011 |
配置服务器 | Mongod | 192.168.70.128:27022 |
Shard0 | Mongod | 192.168.70.128:27017 |
Shard1 | Mongod | 192.168.70.129:27017 |
现在首先启动配置路由器
因为3.4 版本以上mongod要求分片需要以repl方式所以我们指定replSet名称
./mongod --port 27022 --bind_ip 192.168.70.128 --dbpath /data/configsvr/ --configsvr --fork --logpath /var/log/configsvr/configsvr.log --replSet configtest
启动成功后连接到控制台执行repl操作,为求简单我们只启动一台做为master
use admin
cfg={
_id:'test1',
members:[
{_id:0,host:'192.168.70.128:27022'}
]
}
rs.initiate(cfg)
接下来配置mongos:
./mongos --configdb configtest/192.168.70.128:27022 --port 27021 --fork --logpath /var/log/configdb/configdb.log --bind_ip 192.168.70.128
后面启动两个shard实例 具体启动步聚按照副本集的配置方式启动 启动命令必需带上--shardsvr否则后面通过mongos操作数据库时会报错,两个实例如下 replSetName/ip:port:
test/192.168.70.128:27017
test1/192.168.70.129:27017
shard实例启动完之后再回到mongos做最后的分片配置:
use admin
db.runCommand({addshard:"test/192.168.70.128:27017",allowLocal:true})
db.runCommand({addshard:"test1/192.168.70.129:27017",allowLocal:true})
执行脚本查看分片情况
db.runCommand({listShards:1})
mongos> db.runCommand({listShards:1})
{
"shards" : [
{
"_id" : "test",
"host" : "test/192.168.70.128:27017,192.168.70.128:27018",
"state" : 1
},
{
"_id" : "test1",
"host" : "test1/192.168.70.129:27017",
"state" : 1
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1531535857, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1531535857, 1)
}
mongos>
现在分片部署已经完成,最后为数据库集合配置分片:
我们为testdb库里的test集合创建一个分片hash健 testkey:
sh.enableSharding("testdb")
sh.shardCollection("testdb.test",{testkey:"hashed"})
{
"collectionsharded" : "testdb.test",
"collectionUUID" : UUID("022b8d32-6022-4f02-a0c6-53752cc0f7e9"),
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1531544691, 8),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1531544691, 8)
}
显示配置成功,后面我们插入一些数据测试下是否配置正确:
use testdb
for(var i=0;i<1000;i++){
db.test.insert({"testkey":randomWord(6),"a":i})
}
我们插入10000条数据,testkey为随机6位字符串 randomWord为自己写的生成随机字符串的方法执行成功后连上接192.168.70.128:27017查看数据数量:
test:PRIMARY> db.test.count()db.test.count()
484
test:PRIMARY>
再看192.168.70.129:27017的数量:
test1:PRIMARY> db.test.count()db.test.count()
516
test1:PRIMARY>
到处分片配置完成