MongoDB分片
# mongoDB分片
# 用分片的时机
1.机器的磁盘不够用了。使用分片解决磁盘空间的问题。
2.单个mongod已经不能满足写数据的性能要求。通过分片让写压力分散到各个分片上面,使用分片服务器自身的资源。
3.想把大量数据放到内存里提高性能。和上面一样,通过分片使用分片服务器自身的资源
# 使用chunkSize注意点
MongoDB 默认的 chunkSize 为64MB,如无特殊需求,建议保持默认值;chunkSize 会直接影响到 chunk 分裂、迁移的行为。通常100-200M
chunkSize 越小,chunk 分裂及迁移越多,数据分布越均衡;反之,chunkSize 越大,chunk 分裂及迁移会更少,但可能导致数据分布不均。可能造成热点数据问题
chunkSize 太小,容易出现 jumbo chunk(即shardKey 的某个取值出现频率很高,这些文档只能放到一个 chunk 里,无法再分裂)而无法迁移;chunkSize 越大,则可能出现 chunk 内文档数太多(chunk 内文档数不能超过 250000 )而无法迁移。
chunk 自动分裂只会在数据写入时触发,所以如果将 chunkSize 改小,系统需要一定的时间来将 chunk 分裂到指定的大小。
chunk 只会分裂,不会合并,所以即使将 chunkSize 改大,现有的 chunk 数量不会减少,但 chunk 大小会随着写入不断增长,直到达到目标大小。
# 分片键
# 注意点
1.分片键是不可变。
2.分片键必须有索引。
3.分片键大小限制512bytes。
4.分片键用于路由查询。
5.MongoDB不接受已进行collection级分片的collection上插入无分片键的文档(也不支持空值插入)
# 分片键选择建议
一个好的片键对分片至关重要。片键必须是一个索引
对集合进行分片时,你需要选择一个片键,片键是每条记录都必须包含的,且建立了索引的单个字段或复合字段,MongoDB按照片键将数据划分到不同的数据块中,并将数据块均衡地分布到所有分片中。
- 1.递增的sharding key
数据文件挪动小。(优势) 因为数据文件递增,所以会把insert的写IO永久放在最后一片上,造成最后一片的写热点。同时,随着最后一片的数据量增大,将不断的发生迁移至之前的片上。
- 2.随机的sharding key
数据分布均匀,insert的写IO均匀分布在多个片上。(优势) 大量的随机IO,磁盘不堪重荷。
- 3.混合型key
大方向随机递增,小范围随机分布。 为了防止出现大量的chunk均衡迁移,可能造成的IO压力。我们需要设置合理分片使用策略(片键的选择、分片算法(range、hash))
# 分片部署
分片生产环境建议,3台,来自网图
# 架构描述
版本 mongo 3.4
mongo -version
MongoDB shell version v3.4.24
2
2个分片是副本集(node1,node2 端口:27011 ,27012,27013)
2个Config Server 副本集 (node1,node2 端口:27014,27015,27016)
2个 mongos 路由 (node1,node2 端口:30000 ,“多个配置文件port,bind_ip 有一个不一样”)
副本集建立的时候我自定义权重,没有使用仲裁者,#host:'192.168.40.85:27017',arbiterOnly:true 仲裁者
# 配置副本集 shardsvr
# node1
- 创建目录
##--node1
mkdir -p /opt/mongodb/db{1..3}
mkdir -p /opt/mongodb/{logs,conf}
2
3
4
- 生成shardsvr配置文件
# cat mongodb1.conf
dbpath=/opt/mongodb/db1
logpath=/opt/mongodb/logs/mongodb1.log
port=27011
fork=true
nohttpinterface=true
# cat mongodb2.conf
dbpath=/opt/mongodb/db2
logpath=/opt/mongodb/logs/mongodb2.log
port=27012
fork=true
nohttpinterface=true
# cat mongodb3.conf
dbpath=/opt/mongodb/db3
logpath=/opt/mongodb/logs/mongodb3.log
port=27013
fork=true
nohttpinterface=true
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- node1副本集启动
mongod --bind_ip 192.168.40.82 -f /opt/mongodb/conf/mongodb1.conf --replSet yyy --shardsvr
mongod --bind_ip 192.168.40.82 -f /opt/mongodb/conf/mongodb2.conf --replSet yyy --shardsvr
mongod --bind_ip 192.168.40.82 -f /opt/mongodb/conf/mongodb3.conf --replSet yyy --shardsvr
2
3
- 登录replSet,初始化数据,添加到副本集群里
shell > mongo 192.168.40.82:27011
> rs.initiate() #初始化, ###备份数据,会删除所有的数据
yyy:PRIMARY>
yyy:PRIMARY> rs.add({host:"192.168.40.82:27012",priority:2})
yyy:PRIMARY> rs.add({host:"192.168.40.82:27013",priority:3})
yyy:PRIMARY> rs.status()
2
3
4
5
# node2
##--node2
mkdir -p /opt/mongodb/db{1..3}
mkdir -p /opt/mongodb/logs
2
3
- 生成shardsvr配置文件
和node1配置一样,从node1复制三个mongodb.conf配置过来
- node2副本集启动
mongod --bind_ip 192.168.40.87 -f /opt/mongodb/mongodb1.conf --replSet yyy2 --shardsvr
mongod --bind_ip 192.168.40.87 -f /opt/mongodb/mongodb2.conf --replSet yyy2 --shardsvr
mongod --bind_ip 192.168.40.87 -f /opt/mongodb/mongodb3.conf --replSet yyy2 --shardsvr
2
3
- node2登录初始化数据,添加到副本集群里
shell > mongo 192.168.40.87:27011
> rs.initiate() #初始化, ###备份数据,会删除所有的数据
yyy:PRIMARY>
yyy:PRIMARY> rs.add({host:"192.168.40.87:27012",priority:2})
yyy:PRIMARY> rs.add({host:"192.168.40.87:27013",priority:3})
yyy:PRIMARY> rs.status() #检查
2
3
4
5
# 配置副本集 Config Server
只需要配置一个,Config Server 副本集
正常是要分开部署,我这里是两台node机器测试,所以只在一台上面多端口
# node1
##--node1
mkdir -p /opt/mongodb/db{4..6}
2
- 生成configserv配置文件
# cat mongodb4.conf
dbpath=/opt/mongodb/db4
logpath=/opt/mongodb/logs/mongodb4.log
logappend = true
port=27014
fork=true
nohttpinterface=true
configsvr = true
directoryperdb = true
# cat mongodb5.conf
dbpath=/opt/mongodb/db5
logpath=/opt/mongodb/logs/mongodb5.log
port=27015
fork=true
nohttpinterface=true
logappend = true
configsvr = true
directoryperdb = true
# cat mongodb6.conf
dbpath=/opt/mongodb/db6
logpath=/opt/mongodb/logs/mongodb6.log
logappend = true
port=27016
fork=true
nohttpinterface=true
configsvr = true
directoryperdb = true
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
- node1启动configserv
mongod --bind_ip 192.168.40.82 -f /opt/mongodb/mongodb4.conf --replSet configserv
mongod --bind_ip 192.168.40.82 -f /opt/mongodb/mongodb5.conf --replSet configserv
mongod --bind_ip 192.168.40.82 -f /opt/mongodb/mongodb6.conf --replSet configserv
2
3
- 登录Config server,初始化数据,添加到副本集群里
shell > mongo 192.168.40.82:27014
> rs.initiate() #初始化
configserv:OTHER> #状态变更中
configserv:PRIMARY> #状态变更中
###添加分片
configserv:PRIMARY> rs.add({host:"192.168.40.82:27015",priority:5})
configserv:PRIMARY> rs.add({host:"192.168.40.82:27016",priority:6})
configserv:PRIMARY> rs.status() #检查状态,如果需要修改权重,请看上面的文档
2
3
4
5
6
7
8
# 配置路由 mongos
1.mongos启动参数中,chunkSize这一项是用来指定chunk的大小的,单位是MB,默认大小为200MB.
2.mongos conf 配置里面的 configdb 是 Config Server 的副本集,
3.mongos 登录后,db.runCommand( 这里才是数据存放 分片副本集 )
端口使用:30000
# node 1
# cat mongodb_route.conf
#日志文件
logpath=/opt/mongodb/logs/mongodb_route.log
logappend=true
port = 30000
maxConns = 100
bind_ip = 192.168.40.82
fork = true
pidfilepath = /opt/mongodb/logs/mongo_30000.pid
configdb=configserv/192.168.40.82:27014,192.168.40.82:27015,192.168.40.82:27016 #1个或者3个,3.2 的版本后,需要加 副本集名称(configserv)
2
3
4
5
6
7
8
9
10
11
启动mongos:mongos -f mongodb_route.conf
# node 2
配置文件参数configdb和node1一样
# cat mongodb_route.conf
#日志文件
logpath=/opt/mongodb/logs/mongodb_route.log
logappend=true
port = 30000
maxConns = 100
bind_ip = 192.168.40.87
fork = true
pidfilepath = /opt/mongodb/logs/mongo_30000.pid
configdb=configserv/192.168.40.82:27014,192.168.40.82:27015,192.168.40.82:27016 #1个或者3个,3.2 的版本后,需要加 副本集名称(configserv)
2
3
4
5
6
7
8
9
10
11
启动mongos:mongos -f mongodb_route.conf
连接mongos配置分片(不是Config Server),登录:shell > mongo 192.168.40.87:30000
mongos> use admin #必须切换到 admin,包括后面的查看配置操作
mongos> db.runCommand({"addshard":"yyy/192.168.40.82:27011,192.168.40.82:27012,192.168.40.82:27013",allowLocal:true}
mongos> db.runCommand({"addshard":"yyy2/192.168.40.87:27011,192.168.40.87:27012,192.168.40.87:27013",allowLocal:true})
mongos> sh.status() #查看状态
mongos> db.printShardingStatus();
2
3
4
5
查看日志:tail -f /opt/mongodb/logs/mongodb_route.log
- 测试,检查
mongos> db.runCommand({"enablesharding":"yfk1"}); #指定yfk1分片生效
mongos> db.runCommand({"shardcollection":"yfk1.person","key":{"_id":"hashed"}}) #指定数据库里需要分片的集合和片键
mongos> show dbs
mongos> use yfk1
mongos> db.person.stats() #查看数据状态
mongos> for (var i=0;i<100000;i++){db.person.insert({"name":"yfk1"+i,"age":i})} #插入数据
mongos> db.person.stats() #查看数据状态
2
3
4
5
6
7
参考博客
http://xstarcd.github.io/wiki/sysadmin/mongos_cluster.html
https://www.cnblogs.com/ityouknow/p/7344005.html
https://www.cnblogs.com/zhchoutai/p/8757080.html
2
3