1、mongo分片集群
MongoDB分片集群是一种可扩展的数据库架构,用于处理大量数据和高并发访问。它将数据分成多个分片,并将这些分片分布在多个服务器上,从而实现数据的平衡存储和并行处理 。
通过使用MongoDB的分片集,可以实现数据库的水平拓展,提供更大的存储容量和处理能力。分片集还提供了高可用性和冗余备份,以及更好的负载均衡和查询性能。但是在部署和维护分片集时需要考虑一些额外的因素和复杂性。
mongo分片集群节点角色
配置服务器(Config Server):
- 配置服务器存储了分片集群的元数据和配置信息,包括分片节点信息、分片键范围和分片副本集信息等。
- 配置服务器通常是一个复制集,由多个节点组成。
- 配置服务器由路由服务器使用,以确定查询如何路由到相应的分片服务器。
分片服务器(Shard Server):
- 分片服务器存储实际的数据,它们负责处理读写操作和存储分片数据。
- 分片服务器可以是独立的MongoDB实例或者是一个副本集。
- 通过将数据按照分片键进行分发,分片服务器实现了数据的分散存储。
路由服务器(mongos):
- 路由服务器是MongoDB分片集群的入口点,负责将客户端请求路由到适当的分片服务器。
- 客户端连接到路由服务器,并通过它来与整个分片集群进行通信。
- 路由服务器维护了整个集群的元数据和配置信息,并使用此信息来正确路由请求。
- 客户端在连接到路由服务器时,不需要关心分片和配置服务器的具体细节,所有操作都通过路由服务器进行。
分片集群部署架构图如下:
2、docker搭建分片集群
2.1、分片集节点分配
本文演示案例,集群总共10个节点,每个节点信息如下:
目录名称 | 作用 | 端口 |
mongocfg01 | 配置服1 | 27018 |
mongocfg01 | 配置服2 | 27019 |
mongocfg01 | 配置服3 | 27020 |
mongoshared01 | 分片1子节点1 | 27021 |
mongoshared02 | 分片1子节点2 | 27022 |
mongoshared03 | 分片1子节点3 | 27023 |
mongoshared04 | 分片2子节点1 | 27024 |
mongoshared05 | 分片2子节点2 | 27025 |
mongoshared06 | 分片2子节点3 | 27026 |
mongoroute01 | 路由服 | 27030 |
2.2、配置配置服节点
创建config副本集(3个节点)
新建mongocfg01目录,并创建conf,data,logs三个子目录
conf子目录新建mongod.conf文件
##设置数据存储目录
dbpath=/data/db
##设置日志存储文件
##logpath=data/log/mongod.log
##日志追加模式
logappend=true
##允许客户端任意ip连接
bind_ip=0.0.0.0
##绑定端口
port=27017
##副本集名称
replSet=cfg
复制多2个子目录
cp -r mongocfg01 mongocfg02
cp -r mongocfg01 mongocfg03
同时启动3个conf服容器,注意启动参数--configsvr ,标记实例作为分片集群中的配置服务器
echo "创建config服,三个节点"
for i in {1..3}; do
let "port=27017+i"
docker run -d --name mongocfg0$i -p $port:27017 --privileged=true -v ./mongocfg0$i/data:/data/db -v ./mongocfg0$i/conf:/data/configdb -v ./mongocfg0$i/logs:/data/log/ mongo -f /data/configdb/mongod.conf --configsvr
done
配置conf服副本集
##进入其中一个conf服容器
docker exec -it mongocfg01 mongo
##配置副本集
rs.initiate({_id:"cfg",configsvr:true,members:[{_id:0,host:"192.168.0.121:27018"},{_id:1,host:"192.168.0.121:27019"},{_id:2,host:"192.168.0.121:27020"}]})
也可以不进入容器,利用mongo的--eval参数,直接在命令行执行
docker exec -it mongocfg01 mongo --eval 'rs.initiate({_id:"cfg",configsvr:true,members:[{_id:0,host:"192.168.0.121:27018"},{_id:1,host:"192.168.0.121:27019"},{_id:2,host:"192.168.0.121:27020"}]});'
2.3、配置分片服节点
分片即可以选择单节点部署。但为了提高可用性,推荐用副本集进行部署。
创建分片1(3个节点),分片2(3个节点),注意启动参数--shardsvr ,标记实例作为分片集群中的分片服务器
echo "创建分片1,三个节点"
for i in {1..3}; do
let "port=27020+i"
docker run -d --name mongoshared0$i -p $port:27017 --privileged=true -v ./mongoshared0$i/data:/data/db -v ./mongoshared0$i/conf:/data/configdb -v ./mongoshared0$i/logs:/data/log/ mongo -f /data/configdb/mongod.conf --shardsvr --replSet "shared01"
done
配置分片1副本集
echo "配置分片1副本集"
docker exec -it mongoshared01 mongo --eval 'rs.initiate({_id:"shared01",members:[{_id:0,host:"192.168.0.121:27021"},{_id:1,host:"192.168.0.121:27022"},{_id:2,host:"192.168.0.121:27023"}]})'
分片2类似脚本
echo "创建分片2,三个节点"
for i in {4..6}; do
let "port=27020+i"
docker run -d --name mongoshared0$i -p $port:27017 --privileged=true -v ./mongoshared0$i/data:/data/db -v ./mongoshared0$i/conf:/data/configdb -v ./mongoshared0$i/logs:/data/log/ mongo -f /data/configdb/mongod.conf --shardsvr --replSet "shared02"
done
sleep 3
echo "配置分片2副本集"
docker exec mongoshared04 mongo --eval 'rs.initiate({_id:"shared02",members:[{_id:0,host:"192.168.0.121:27024"},{_id:1,host:"192.168.0.121:27025"},{_id:2,host:"192.168.0.121:27026"}]})'
2.4、配置路由服节点
创建路由服务器,启动参数-configdb,该参数与 mongos
(MongoDB分片路由器)一起使用,指定配置服务器的连接字符串。mongos
需要知道配置服务器的位置,以便能够访问集群的元数据。
--entrypoint "mongos" 修改容器入口为mongos,默认为mongo
echo "创建路由服务器"
docker run --name mongoroute -d -p 27030:27017 --privileged=true -v ./mongoroute/data:/data/db -v ./mongoroute/conf:/data/configdb --entrypoint "mongos" mongo --configdb rs_configsvr/192.168.0.121:27018,192.168.0.121:27019,192.168.0.121:27020
将分片添加到集群
echo "添加分片到集群"
docker exec -it mongoroute mongo --eval 'sh.addShard("shared01/192.168.0.121:27021,192.168.0.121:27022,192.168.0.121:27023")'
docker exec -it mongoroute mongo --eval 'sh.addShard("shared02/192.168.0.121:27024,192.168.0.121:27025,192.168.0.121:27026")'
3、分片集测试数据
3.1、进入mongos容器
##进入route服
docker exec -it mongoroute mongo
3.2、分片sh命令
分片sh命令,是类似副本集rs的操作,相关命令如下:
命令 | 作用 |
sh.shardCollection("<database>.<collection>", <shard key>) | 将集合设置分片 |
sh.addShard("<shard connection string>") | 添加分片 |
sh.removeShard("<shard identifier>") | 删除分片 |
sh.enableSharding("<database>") | 启动分片 |
sh.disableSharding("<database>") | 停用分片 |
3.3、数据库启动分片
要对一个特定的集合进行分片,首先需要在集合的数据库上启用分片。如下所示:
mongos> sh.enableSharding("game")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1718881323, 2),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1718881323, 1)
}
3.4、选择合理的分片键类型
对表字段增加分片键
在MongoDB分片集群中,可以使用哈希分片和范围分片两种方式进行数据的分片。
-
哈希分片(Hash Sharding):哈希分片通过对分片键的哈希值进行取模运算来确定数据应该存储在哪个分片上。这种分片方式可以保证数据的均匀分布,但会导致数据的局部性降低。
-
范围分片(Range Sharding):范围分片根据分片键的值范围来确定数据应该存储在哪个分片上。例如,可以将分片键设置为时间戳,按照时间范围进行分片。这种分片方式可以保持数据的局部性,但可能导致数据在分片上的分布不均衡。
选择使用哪种分片方式取决于具体的业务需求和数据特征。如果对数据的读写操作具有随机访问模式,可以考虑使用哈希分片,以保证数据的均匀分布,从而获得更好的吞吐量。如果对数据的读写操作具有顺序访问模式,并且希望保持数据的局部性,可以考虑使用范围分片。
mongos> sh.shardCollection("game.player", {"_id":"hashed"})
{
"collectionsharded" : "game.player",
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1718881394, 36),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1718881394, 30)
}
3.5、插入测试数据
mongos> for (i=1; i<=1000; i=i+1){
... db.player.insert({"i":i})
... };
WriteResult({ "nInserted" : 1 })
mongos> db.player.find().count()
1000
确定分片分布
##进入分片1的主节点
docker exec -it mongoshared01 mongo
##查询分片里的数据
shared01:PRIMARY> db.player.find().count()
487
##进入分片2的主节点
docker exec -it mongoshared04 mongo
##查询分片里的数据
shared04:PRIMARY> db.player.find().count()
513
也可以直接用stats()查询
3.5、动态增加分片
#!/bin/bash
echo "创建分片3,三个节点"
for i in {7..9}; do
let "port=27020+i"
docker run -d --name mongoshared0$i -p $port:27017 --privileged=true -v ./mongoshared0$i/data:/data/db -v ./mongoshared0$i/conf:/data/configdb -v ./mongoshared0$i/logs:/data/log/ mongo -f /data/configdb/mongod.conf --shardsvr --replSet "shared03"
done
sleep 3
echo "动态配置分片3副本集"
docker exec mongoshared07 mongo --eval 'rs.initiate({_id:"shared03",members:[{_id:0,host:"192.168.0.121:27027"},{_id:1,host:"192.168.0.121:27028"},{_id:2,host:"192.168.0.121:27029"}]})'
echo "添加分配到route服"
docker exec -it mongoroute mongo --eval 'sh.addShard("shared03/192.168.0.121:27027,192.168.0.121:27028,192.168.0.121:27029")'
需要注意的是,通过命令行执行--eval参数的时候,需要稍微停顿片刻,确保容器内部完成。前面的脚本也是同样的道理。如果确实报错了,那就等待片刻之后,再手动执行吧。
然而,动态添加分片之后,发现,数量变多了。分别到各个分片查询之后,发现有些数据重复了。这是因为数据迁移的临时数据,等数据迁移完毕,数量就会正常了。至于什么时候迁移完成,笔者还没找到方法,只能等。
3.6、编写重置脚本
每次搭建的过程中,如果配置不小心弄错了,需要重新开始,一行一行命令写很麻烦,写个脚本,一键清除下吧。(除了删除容器,同时一定要把卷的数据删除)
#!/bin/bash
for i in {1..3}; do
docker rm -f mongocfg0$i
sudo rm -rf mongocfg0$i/data/*
done
for i in {1..9}; do
docker rm -f mongoshared0$i
sudo rm -rf mongoshared0$i/data/*
done
docker rm -f mongoroute
sudo rm -rf mongoroute/data/*
sleep 3
for i in {1..3}; do
sudo rm -rf mongocfg0$i/data/*
done
for i in {1..9}; do
sudo rm -rf mongoshared0$i/data/*
done
sudo rm -rf mongoroute/data/*
echo "清除完毕"