初识 MongoDB 分片

分片是指将数据拆分,拆分后存放在不同的机器上的过程,以此来降低单个服务器的压力,同时也解决单个服务器硬盘空间不足的问题,让我们可以用廉价的机器实现高性能的数据架构。

有的小伙伴不理解分片和副本集的差异,一言以蔽之:副本集上每个备份节点存储的数据都是相同的,分片上存储的数据则是不同的。好了,本文我们就先来看看分片环境的搭建。

环境准备

准备三台已经装好了 MongoDB 的服务器,地址分别是:

1
2
3
192.168.248.128
192.168.248.135
192.168.248.136

本文使用的 MongoDB 版本为 3.4.9

规划

首先我们需要三台配置服务器,配置服务器相当于集群的大脑,配置服务器中保存着集群和分片的元数据,即每个分片都包含了哪些数据信息,这些数据都是保存在配置服务器中的,我这里将开启三个配置服务器实例,这三个配置服务器将运行在三个 MongoDB 服务器上,地址分别如下:

1
2
3
192.168.248.128:20000
192.168.248.135:20000
192.168.248.136:20000

接下来需要一个 Mongos 实例,Mongos 对请求进行路由,Mongos 扮演的角色有点类似于一个门面,我们以后访问的时候,直接访问 Mongos 即可,再由 Mongos 将请求路由到不同的分片上去,Mongos 在启动时会去访问配置服务器,它将从配置服务器中获取数据的存储信息,Mongos 我将启动在如下服务器上:

1
192.168.248.128:30000

最后需要三个分片实例,三个分片依然运行在三台服务器上,如下:

1
2
3
192.168.248.128:27017
192.168.248.135:27017
192.168.248.136:27017

搭建配置服务器

配置服务器中不需要太多的空间和资源,因为配置服务器上保存的只是数据的分布表,不保存具体的数据,具体的数据都保存在分片上,配置服务器中 1KB 的空间约为 200MB 的真实数据。注意,从 MongoDB3.4 开始,配置服务器要做成集群的方式。

由于配置服务器是独立的 mongod 进程,所以我们可以像启动普通的 MongoDB 服务一样启动配置服务器,只是这里的配置不同罢了。

我这里以 192.168.248.128 服务器为例来讲述配置服务器的配置启动,另外两台服务器如法炮制即可:

  1. 在 mongodb 解压目录下创建 db20000 文件夹,用来存储配置服务器中的数据。
  2. 复制一份 mongodb.conf,命名为 mongodb20000.conf,修改文件内容如下:
1
2
3
4
5
6
dbpath=/opt/mongodb/db20000
logpath=/opt/mongodb/logs/mongodb20000.log
port=20000
fork=true
configsvr=true
replSet=rs

注意 dbpath 改为我们第一步创建的目录,端口号改为 20000 (这个随意,只要该端口没被占用即可), configsvr 表示这是一个配置服务器,另外由于我们的配置服务器要做成备份集,所以要设置 replSet。

3.做好前两步之后,执行如下命令启动配置服务器:

1
mongod -f /opt/mongodb/bin/mongodb20000.conf

最后,在另外两台服务器上重复上面三个步骤。

三台服务器上都启动成功之后,参考我们之前的MongoDB 副本集搭建一文,将这三台配置服务器配成一个副本集,副本集的配置我这里就不再赘述。

搭建Mongos

Mongos 实例我们可以启动在任意一台服务器上,我这里就启动在 192.168.248.128上,Mongos 的配置步骤如下:

1.复制一份 mongodb.conf,命名为 mongos.conf,修改内容:

1
2
3
4
logpath=/opt/mongodb/logs/mongos.log
port=30000
fork=true
configdb=rs/192.168.248.128:20000,192.168.248.135:20000,192.168.248.136:20000

因为 mongos 中不需要保存数据,所以不需要 dbpath,端口号改为 30000,configdb 表示三个配置服务器的地址,注意最前面的 rs 表示配置服务器副本集的名称。

2.配置完成后,执行如下命令启动 mongos:

1
mongos -f /opt/mongodb/bin/mongos.conf

搭建三个分片

三个分片实际上就是三个普通的 MongoDB 服务器,给大家看下我的配置文件:

1
2
3
4
5
dbpath=/opt/mongodb/db
logpath=/opt/mongodb/logs/mongodb.log
port=27017
fork=true
shardsvr=true

注意多了个 shardsvr 表示这是一个分片服务器。
然后在三台服务器上分别执行如下命令启动分片:

1
mongod -f /opt/mongodb/bin/mongodb.conf

添加分片

上面三个步骤完成之后,我们就进入到 mongos 的 shell 命令行了,如下:

1
mongo --port=30000

然后我们可以通过如下命令查看一下分片的当前状态:

1
sh.status()

执行结果如下(部分):

1
2
3
4
5
--- Sharding Status ---
sharding version: {
}
shards:
databases:

shards 表示分片服务器,目前还没有,databases 表示分片的库,目前也还没有,接下来我们通过如下命令添加分片服务器:

1
2
3
sh.addShard("192.168.248.128:27017")
sh.addShard("192.168.248.135:27017")
sh.addShard("192.168.248.136:27017")

添加三个分片服务器,然后再执行 sh.status(),结果如下(部分):

1
2
3
4
5
6
7
8
9
--- Sharding Status ---
sharding version: {
}
shards:
{ "_id" : "shard0000", "host" : "192.168.248.128:27017", "state" : 1 }
{ "_id" : "shard0001", "host" : "192.168.248.135:27017", "state" : 1 }
{ "_id" : "shard0002", "host" : "192.168.248.136:27017", "state" : 1 }
databases:
{ "_id" : "test", "primary" : "shard0000", "partitioned" : false }

设置集合分片

接下来我们来设置集合的分片,首先执行如下命令表示给某个数据库分片:

1
sh.enableSharding("sang")

对集合分片时,需要选择一个片键,片键实际上就是集合中的一个键,MongoDB 将根据这个片键来拆分数据,我们需要先对片键建立索引,如下:

1
db.c1.ensureIndex({x:1})

然后以 x 为片键,对 c1 集合进行分片,如下:

1
sh.shardCollection("sang.c1",{x:1})

做完这些之后,再执行 sh.status() 命令,查看目前状态,结果如下(部分):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
--- Sharding Status ---
sharding version: {
}
shards:
{ "_id" : "shard0000", "host" : "192.168.248.128:27017", "state" : 1 }
{ "_id" : "shard0001", "host" : "192.168.248.135:27017", "state" : 1 }
{ "_id" : "shard0002", "host" : "192.168.248.136:27017", "state" : 1 }
databases:
{ "_id" : "test", "primary" : "shard0000", "partitioned" : false }
{ "_id" : "sang", "primary" : "shard0001", "partitioned" : true }
sang.c1
shard key: { "x" : 1 }
unique: false
balancing: true
chunks:
shard0001 1
{ "x" : { "$minKey" : 1 } } -->> { "x" : { "$maxKey" : 1 } } on : shard0001 Timestamp(1, 0)

做完上面这些之后,我们再做两个操作:

1.设置自动分片:

1
sh.setBalancerState(true)

2.设置 chunksize,chunksize 这一项是用来指定 chunk 的大小的,为了方便测试分片效果,我们把 chunksize 指定为 1MB,即当这个分片中插入的数据大于 1M 时开始进行数据分片

1
db.settings.save({_id:"chunksize",value:1})

OK,做好这些之后,大功告成。

测试

测试方式很简单,我们直接在 mongos 的命令行向 sang 的 c1 集合中插入 50000 条数据,然后再查看这些数据的分布,就知道分片有没有成功了:

1
for(var i=0;i<50000;i++){db.c1.insert({x:Math.random()*1000000,name:"hahah"+i})}

然后执行 db.c1.stats() ,结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
{
"sharded" : true,
"capped" : false,
"ns" : "sang.c1",
"count" : 50000,
"size" : 2688890,
"storageSize" : 1781760,
"totalIndexSize" : 1978368,
"avgObjSize" : 53,
"nindexes" : 2,
"nchunks" : 5,
"shards" : {
"shard0000" : {
"ns" : "sang.c1",
"size" : 926504,
"count" : 17229,
"avgObjSize" : 53,
"storageSize" : 462848,
"capped" : false,
"nindexes" : 2,
"totalIndexSize" : 516096,
"indexSizes" : {
"_id_" : 184320,
"x_1" : 331776
},
"ok" : 1
},
"shard0001" : {
"ns" : "sang.c1",
"size" : 392593,
"count" : 7299,
"avgObjSize" : 53,
"storageSize" : 667648,
"capped" : false,
"nindexes" : 2,
"totalIndexSize" : 737280,
"indexSizes" : {
"_id_" : 253952,
"x_1" : 483328
},
"ok" : 1
},
"shard0002" : {
"ns" : "sang.c1",
"size" : 1369793,
"count" : 25472,
"avgObjSize" : 53,
"storageSize" : 651264,
"capped" : false,
"nindexes" : 2,
"totalIndexSize" : 724992,
"indexSizes" : {
"_id_" : 237568,
"x_1" : 487424
},
"ok" : 1
}
}
}

OK,看到如上结果,说明我们的数据已经分布在三个分片服务器中了。

好了,MongoDB 中分片环境的搭建我们就先说到这里,小伙伴们有问题欢迎留言讨论。
参考资料:

  1. 《MongoDB权威指南第2版》

喜欢这篇文章吗?扫码关注公众号【江南一点雨】【江南一点雨】专注于 SPRING BOOT+微服务以及前后端分离技术,每天推送原创技术干货,关注后回复 JAVA,领取松哥为你精心准备的 JAVA 干货!

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×