目录
项目中运用到了mongodb进行非结构化文档的存储,需要搭建mongodb分片集群,本文详细整理了mongodb分片集群的搭建步骤,仅供参考。
1. 软硬件资源
三台虚拟机:4C/8G 100G硬盘 ,centos7.x , mongo4.2
Mongodb采用三个分片、三副本的配置矩阵见下图所示: [
如有随着数据的增多,需要更多的分片机器资源,则可以继续将数据分摊在相应的节点即可。
如果资源充足且允许,可按照如下计算方式:
- Router、Config Server可共享三台独立机器,低规格即可。路由节点最少需要2个,主要用于转发客户端请求,选择合适的数据节点进行读写操作或者合并多个数据节点返回。配置节点主要用于存储具体的分片数据的索引信息,便于路由节点进行分片数据的寻址查询。
- 分片数据节点以复制集合为单位,可以横向扩展,分片之间数据不重复(即所有分片的数据集合才有完整的数据)。可根据资源大小进行机器数量及配置的选择。例如有10T数据资源,每台PC 6TB存储(建议单个分片不超过3TB,最好2TB为佳,则一台机器最多3个分片),按照3副本方式,则最少需要 10*3/6 = 5台机器(忽略系统占用空间),mongodb为非CPU密集型数据库,CPU 选择4C,内存则根据是否索引及聚合等复杂查询8G~64G。
分片的计算方法:
A = 预估数据总量 / 单服务器可挂载的容量 (10T*3 / 2T = 15 ) 磁盘
B = 工作集索引元数据等大小/(单服务器内存容量 * 0.6)(纯文件存储可忽略 内存
C = 并发量总数 / (单服务器并发量 * 0.7 ) (我们基本可以忽略并发量) 文件描述符
分片数量 = Max(A,B,C)
资源的计算重点在于分片服务器:内存需要足够容纳热数据索引;如果不涉及太多计算,则CPU通常不会成为瓶颈;磁盘有条件可选择SSD。无论内存还是磁盘容量超过60%以上时候,即需要开始准备扩容事宜,从而使得数据后续的均衡有足够的时间和中转空间
2. 分片集群特点
客户端透明,无需特殊处理;数据自动均衡;动态扩容,无需应用下线。可以有效解决性能瓶颈和系统扩容问题,但是分片额外消耗了系统性能,管理较为复杂,不到万不得已不用。【来自极客时间,唐建法老是的建议】
3. 分片数据分方式选择
基于范围、基于Hash、基于Zone/Tag
可参考官方文档:https://docs.mongodb.com/manual/core/sharding-shard-key/
影响片键效率的主要因素:
取值基数(基数太小则不利于水平扩展,块数量受限,块大小越来越大)
取值分布(尽可能均匀分布,避免产生读写热点块)
分散写操作,集中度操作
覆盖最够多的业务场景(如查询条件)
避免单调递增/递减的片键
4. 分片数据集群搭建步骤
官方指导:https://docs.mongodb.com/manual/tutorial/deploy-shard-cluster/
配置域名解析
准备分片目录
创建第一个分片复制集并初始化
创建config复制集并初始化
初始化分片集群,加入第一个分片
创建分片表
加入第二个、第N个分片
5. 创建文件夹和相应的文件,并启动服务
(1) 下载安装包,配置环境变量
1 下载https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-4.2.6.tgz
2 tar –zxvf mongodb-linux-x86_64-rhel62-4.2.6.tgz
3 rename mongodb-linux-x86_64-rhel62-4.2.6.tgz mongo
4 /etc/profile中加入环境变量
export PATH=$PATH:/usr/mongo/bin
source /etc/profile
5 设置三台主机名称映射
echo "10.1.15.15 mongo-server1" >> /etc/hosts
echo "10.1.15.16 mongo-server2" >> /etc/hosts
echo "10.1.15.17 mongo-server3" >> /etc/hosts
(2) 创建数据、日志和配置文件目录
启动配置文件存放的文件夹:mkdir -p /usr/mongo/conf
配置服务数据存放目录:mkdir -p /usr/mongo/data/config
分片1服务数据存放目录:mkdir -p /usr/mongo/data/shard1
分片2服务数据存放目录:mkdir -p /usr/mongo/data/shard2
分片3服务数据存放目录:mkdir -p /usr/mongo/data/shard3
配置服务日志存放文件:mkdir -p /usr/mongo/log/config.log
路由服务日志存放文件:mkdir -p /usr/mongo/log/mongos.log
分片1服务日志存放文件:mkdir -p /usr/mongo/log/shard1.log
分片2服务日志存放文件:mkdir -p /usr/mongo/log/shard2.log
分片3服务日志存放文件:mkdir -p /usr/mongo/log/shard3.log
(3) 配置服务器部署(3台服务器执行相同操作)
1、在/usr/mongo/conf目录创建config.conf:
dbpath=/usr/mongo/data/config
logpath=/usr/mongo/log/config.log/config.log ###此处应该是到具体的文件,太坑了
port=27018
logappend=true
fork=true
maxConns=5000
#复制集名称
replSet=configs
#配置参数为true,标识配置服务器
configsvr=true
#允许任意机器连接
bind_ip=0.0.0.0
2、分别启动三台服务器的配置服务:
mongod -f /usr/mongo/conf/config.conf
3、连接任意一台机器执行:
mongo --port 27018
4、use admin
5、rs.initiate({_id:"configs",members:[{_id:0,host:"mongo-server1:27018"},{_id:1,host:"mongo-server2:27018"}, {_id:2,host:"mongo-server3:27018"}]})
6、rs.status()
(4) 分片服务器部署(3台服务器执行相同操作)
1、 在/usr/mongo/conf目录创建shard1.conf、shard2.conf、shard3.conf,内容如下:
2、 shard1.conf
dbpath=/usr/mongo/data/shard1 #其他2个分片对应修改为shard2、shard3文件夹
logpath=/usr/mongo/log/shard1.log/shard1.log #其他2个分片对应修改为shard2.log、shard3.log
port=27001 #其他2个分片对应修改为27002、27003
logappend=true
fork=true
maxConns=5000
storageEngine=mmapv1
shardsvr=true
replSet=shard1 #其他2个分片对应修改为shard2、shard3
bind_ip=0.0.0.0
shard2.conf
dbpath=/usr/mongo/data/shard2
logpath=/usr/mongo/log/shard2.log/shard2.log
port=27002
logappend=true
fork=true
maxConns=5000
storageEngine=mmapv1
shardsvr=true
replSet=shard2
bind_ip=0.0.0.0
shard3.conf
dbpath=/usr/mongo/data/shard3
logpath=/usr/mongo/log/shard3.log/shard3.log
port=27003
logappend=true
fork=true
maxConns=5000
storageEngine=mmapv1
shardsvr=true
replSet=shard3
bind_ip=0.0.0.0
3、 mongod -f /usr/mongo/conf/shard{1/2/3}.conf
在3台机器的相同端口形成一个分片的复制集,由于3台机器都需要这3个文件,所以根据这9个配置文件分别启动分片服务:
4、 mongo --port 27001
use admin
rs.initiate({_id:"shard1",members:[{_id:0,host:"mongo-server1:27001"},{_id:1,host:"mongo-server2:27001"},{_id:2,host:"mongo-server3:27001"}]})
5、 mongo --port 27002
use admin
rs.initiate({_id:"shard2",members:[{_id:0,host:"mongo-server1:27002"},{_id:1,host:"mongo-server2:27002"},{_id:2,host:"mongo-server3:27002"}]})
6、 mongo --port 27003
use admin
rs.initiate({_id:"shard3",members:[{_id:0,host:"mongo-server1:27003"},{_id:1,host:"mongo-server2:27003"},{_id:2,host:"mongo-server3:27003"}]})
(5) 路由服务部署(3台服务器执行相同操作)
1、创建mongos.conf文件
logpath=/usr/mongo/log/mongos.log/mongos.log
logappend = true
port = 27017
fork = true
configdb = configs/mongo-server1:27018,mongo-server2:27018,mongo-server3:27018
maxConns=200
bind_ip=0.0.0.0
2、分别在三台机器启动
mongos -f /usr/mongo/conf/mongos.conf
3、连接mongo,启动分片功能(添加分片,只需在一台机器执行即可)
mongo --port 27017
use admin
sh.addShard("shard1/mongo-server1:27001,mongo-server2:27001,mongo-server3:27001")
sh.addShard("shard2/mongo-server1:27002,mongo-server2:27002,mongo-server3:27002")
sh.addShard("shard3/mongo-server1:27003,mongo-server2:27003,mongo-server3:27003")
sh.status()
(6) 实现分片功能
官方文档:https://docs.mongodb.com/manual/tutorial/modify-chunk-size-in-sharded-cluster/
use config
db.setting.save({"_id":"chunksize","value":128}) #128M1个chunk,进行shard负载均衡的数据单元
sh.enableSharding("db_name") #开启对库的分片
use db_name
db.collection_name.createIndex({"id":1}) #以"id"作为索引
sh.shardCollection(db_name.collection_name ",{"id":1}) #根据"id"对collection_name表分片
sh.status() # 查看分片情况
至此,分片集群搭建过程完毕。
6. GridFS分片设置
项目中主要使用Mongo进行非结构化文档的存储,由于mongo中单个文档大小不能超过16M,GridFS实际上是在mongo中创建了两个集合,其中一个为索引集合,存放文档的大小以及chunk的个数,第二个集合为具体每个chunk的索引以及块的位置,并实际存放文档的Bson数据。故而在进行分片设置时候,主要针对chunks集合进行设置,可以将files_id,n或者files_id设置为分片索引,同时使用Hash方式进行索引分片。
db.fs.files.createIndex( { filename: 1, uploadDate: 1 } );
详见官方指引:https://docs.mongodb.com/manual/core/gridfs/
7. 待续
有了环境之后,后续将在Mongodb的基础上,结合springboot实现文档的存储。其中还需要解决两个主要的问题:大文件上传和下载的断点续传、已上传文档副本的秒传功能。
参考文档:
1、MongoDB实战-分片概念和原理 https://cloud.tencent.com/developer/article/1444388
2、mongodb分片模式分片键的选择 https://cloud.tencent.com/developer/article/1451897
3、mongodb集群增加登录密码验证 https://cloud.tencent.com/developer/article/1505814
4、史上最详细的 MongoDB4.0搭建分布式集群https://blog.csdn.net/zhanaolu4821/article/details/87190100