Linux搭建MongoDB分片集群
一、介绍
1、基本介绍
MongoDB部署架构分为单机、复制集群、分片集群。单机适合学习用,分片集群比较复杂且运维难度高。
分片集群是把大型数据集进行拆分,分片到多个MongoDB节点上,这些节点组成了分片集群。分片结构如下:
2、词汇表
Shard:分片,存储集群中的一部分数据。可以是单个mongo服务器,也可以是复制集。生产环境推荐使用复制集。
Config Server:配置服务器。存储集群的元数据,比如集群的分片信息。mongos 启动时会从配置服务器读取元数据到内存中。配置服务器必须是复制集。
Routers:mongos 路由。负责接收客户端请求,并将请求路由到集群内部对应的分片上。
Shard Key:分片键。对于每个需要分片的 collection,通过指定分片键进行分片。分片键必须是索引字段或者是组合索引的左前缀。
Range分区:范围分区算法。分片键必须是数字或者字符串类型,根据分片键将数据分成不同的 chunk,每个 chunk 互相临近但不重叠。
Hash分区:哈希分区算法。计算分片键的hash值,并以此作为 Range 分区。这种方式可以将document更加随机的分散到不同 chunk 上
二、环境准备
虚拟机三台(Centos7.6),分别安装好MongoDB。
分片集群中,一共10个节点:2个分片(每个分片是3个复制集), 1个config(3个复制集),1个路由。
服务网格信息如下:
角色 | IP | Node |
分片0复制集 | 192.168.20.100:27017、192.168.20.101:27017、192.168.20.102:27017 | 1主1从1仲裁 |
分片1复制集 | 192.168.20.100:27018、192.168.20.101:27018、192.168.20.102:27018 | 1主1从1仲裁 |
config复制集 | 192.168.20.100:28018、192.168.20.101:28018、192.168.20.102:28018 | 1主2从 |
mongos节点 | 192.168.20.100:29019 |
三、搭建 Shard
1、在100/101/102机器上,创建目录:
mkdir -p /usr/local/mongo/share/data/db #分片0的数据保存路径
mkdir -p /usr/local/mongo/share/data/db2 #分片1的数据保存路径
mkdir -p /usr/local/mongo/share/conf
mkdir -p /usr/local/mongo/share/pids
mkdir -p /usr/local/mongo/share/logs
2、在100/101/102机器上,/usr/local/mongo/share/conf 目录下,添加分片0复制集的配置文件:mongo.conf :
#数据保存路径
dbpath=/usr/local/mongo/share/data/db/
#日志保存路径
logpath=/usr/local/mongo/share/logs/mongo.log
#进程描述文件
pidfilepath=/usr/local/mongo/share/pids/mongo.pid
#日志追加写入
logappend=true
#复制集名称
replSet=rs0
bind_ip_all=true
#mongo端口
port=27017
#操作日志容量
oplogSize=10000
#开启子进程
fork=true
#代表当前节点是一个shard节点
shardsvr=true
3、在100/101/102机器上,/usr/local/mongo/share/conf 目录下,添加分片1复制集的配置文件:mongo2.conf :
#数据保存路径
dbpath=/usr/local/mongo/share/data/db2/
#日志保存路径
logpath=/usr/local/mongo/share/logs/mongo2.log
#进程描述文件
pidfilepath=/usr/local/mongo/share/pids/mongo2.pid
#日志追加写入
logappend=true
#复制集名称
replSet=rs1
bind_ip_all=true
#mongo端口
port=27018
#操作日志容量
oplogSize=10000
#开启子进程
fork=true
#代表当前节点是一个shard节点
shardsvr=true
4、在100/101/102机器上,分别启动 mongod 服务:
#分片0(rs0)
/usr/local/mongo/bin/mongod -f /usr/local/mongo/share/conf/mongo.conf
#分片1(rs1)
/usr/local/mongo/bin/mongod -f /usr/local/mongo/share/conf/mongo2.conf
5、登录复制集:
#分片0(rs0)
/usr/local/mongo/bin/mongo --host 192.168.20.100 --port 27017
#分片1(rs1)
/usr/local/mongo/bin/mongo --host 192.168.20.100 --port 27018
6、初始化复制集:
#分片0(rs0)
rs.initiate({
_id:"rs0",
members:[
{_id:0, host:"192.168.20.100:27017", priority:3},
{_id:1, host:"192.168.20.101:27017", priority:2},
{_id:2, host:"192.168.20.102:27017", arbiterOnly:true}
]
});
#分片1(rs1)
rs.initiate({
_id:"rs1",
members:[
{_id:0, host:"192.168.20.100:27018", priority:3},
{_id:1, host:"192.168.20.101:27018", priority:2},
{_id:2, host:"192.168.20.102:27018", arbiterOnly:true}
]
});
四、搭建Config Server
1、在100/101/102机器上,创建目录:
mkdir -p /usr/local/mongo/config-server/data/db
mkdir -p /usr/local/mongo/config-server/conf
mkdir -p /usr/local/mongo/config-server/pids
mkdir -p /usr/local/mongo/config-server/logs
2、在100/101/102机器上,/usr/local/mongo/config-server/conf 目录下,添加复制集的配置文件:mongo-cfg.conf
dbpath=/usr/local/mongo/config-server/data/db
logpath=/usr/local/mongo/config-server/logs/mongo.log
pidfilepath=/usr/local/mongo/config-server/pids/mongo.pid
logappend=true
replSet=rs_conf
bind_ip_all=true
port=28018
oplogSize=10000
fork=true
#代表当前节点是一个config节点
configsvr=true
3、在100/101/102机器上,分别启动配置复制集:
/usr/local/mongo/bin/mongod -f /usr/local/mongo/config-server/conf/mongo-cfg.conf
4、登录复制集:
/usr/local/mongo/bin/mongo --host 192.168.20.100 --port 28018
5、初始化复制集:
rs.initiate({
_id:"rs_conf",
configsvr: true,
members:[
{_id:0, host:"192.168.20.100:28018", priority:2},
{_id:1, host:"192.168.20.101:28018", priority:1},
{_id:2, host:"192.168.20.102:28018", priority:1}
]
});
五、搭建Router
本案例只配置了一个Router,生产环境通常配置多个。Router不需要数据目录(dbpath),只需要提供 config server 信息
1、在100机器上,创建目录:
mkdir -p /usr/local/mongo/router/conf
mkdir -p /usr/local/mongo/router/pids
mkdir -p /usr/local/mongo/router/logs
2、在 /usr/local/mongo/router/conf 目录下,创建 Router 的配置文件:mongo-router.conf
configdb=rs_conf/192.168.20.100:28018,192.168.20.101:28018,192.168.20.102:28018
logpath=/usr/local/mongo/router/logs/mongos.log
pidfilepath=/usr/local/mongo/router/pids/mongos.pid
port=29019
fork=true
bind_ip_all=true
3、启动 Router 服务:
/usr/local/mongo/bin/mongos -f /usr/local/mongo/router/conf/mongo-router.conf
4、连接 Router 节点:
/usr/local/mongo/bin/mongo --host 192.168.20.100 --port 29019
5、切换到 admin 库
use admin
6、添加分片信息:
#分片0
db.runCommand({addShard: "rs0/192.168.20.100:27017,192.168.20.101:27017,192.168.20.102:27017", name: "share0"});
#分片1
db.runCommand({addShard: "rs1/192.168.20.100:27018,192.168.20.101:27018,192.168.20.102:27018", name: "share1"});
7、查看分片:
db.runCommand({listshards: 1})
8、查看分片状态:
sh.status()
六、测试
1、测试分片--哈希策略
连接 Router 节点并切换到 admin 库。对测试库 xwjdb 开启分片功能:
sh.enableSharding("xwjdb")
对集合 account 分片,分片键为 nickname,分片策略为哈希:
sh.shardCollection("xwjdb.account", {"nickname": "hashed"})
切换到 xwjdb 库。向 account 集合中,循环插入1000条数据:
use xwjdb
for(var i=1; i<=1000; i++){db.account.insert({_id: i+"", nickname: "xwj"+i})}
分别连接 分片0 和 分片1 节点,并切换到 xwjdb 库。查询 account 集合数据条数:
use xwjdb
db.account.count()
分片0的数据是505条,分片2是495条,总数正好是1000条,说明数据分片成功了
结论:基于哈希策略的分片算法,数据会均匀的分配到不同的分片节点上
2、测试分片-范围策略
数据块(chunk)默认大小是64M,填满后才会考虑向其它片的数据块填充数据,因此,为了测试可以将其改小,这里改为1M:
use config
db.setting.save({"_id": "chunksize", "value": 1})
切换到 admin 库。对测试库 testdb 开启分片功能:
sh.enableSharding("testdb")
对集合 person 分片,分片键为主键id,分片策略为范围:
sh.shardCollection("testdb.person",{_id:1});
切换到库 testdb。向 person 集合中,批量插入4000000条数据(数据少了可能只落在一个分片上):
use testdb
var arr=[]
for(var i=1; i<=4000000; i++){arr.push({"_id":i,"username":"user"+i,"createdate":new Date()})}
db.person.insertMany(arr)
分别连接 分片0 和 分片1 节点,并切换到 testdb 库。查询 account 集合数据条数:
use testdb
db.person.count()
七、其它
1、一个集合只能有一个分片键
2、库和集合默认是不分片的,对于不分片的库或者集合,数据均会保存在 primary shard上,直到开启分片才会在集群中分布
3、删除所有数据和日志信息(删除后,所有配置信息也被删掉了):
rm -rf /usr/local/mongo/config-server/logs/*
rm -rf /usr/local/mongo/config-server/data/db/*
rm -rf /usr/local/mongo/share/data/db/*
rm -rf /usr/local/mongo/share/data/db2/*
rm -rf /usr/local/mongo/share/logs/*
rm -rf /usr/local/mongo/router/logs/*
4、删除分片键命令:
use config
db.collections.remove( { _id: "testdb.person" } )
db.chunks.remove( { ns: "testdb.person" } )
db.locks.remove( { _id: "testdb.person" } )
use admin
db.adminCommand("flushRouterConfig")
5、查询chunk大小:
use config
db.setting.find()
八、踩坑
1、config server复制集初始化时,报错:
问题原因:搭建config server复制集时,不能有仲裁节点(Arbiters),否则初始化失败
解决办法:复制集使用一主两从
作者:南辞、归
本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。
博主的文章没有高度、深度和广度,只是凑字数。由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。
博主是利用读书、参考、引用、抄袭、复制和粘贴等多种方式打造成自己的文章,请原谅博主成为一个无耻的文档搬运工!