分片是指将数据拆分分散存在不同的机器上的过程。不同的数据被存放到不同的子集中,每个子集存放在独立的分片上,每个数据分片又可以独立运行在不同的MongoDB上,相当于**MySQL的分库分表和Redis的Cluster模式**<br />MongoOS相当于路由,与Nginx类似,指定访问的分片数据库;ConfigServers存储群集的元数据和配置设置,**3.4版本以后必须为复制集**;每个分片包含分片数据的子集,且都可以部署为副本集<br /> ![sharded-cluster-production-architecture.bakedsvg.png](https://cdn.nlark.com/yuque/0/2021/png/21405095/1626704630923-96489057-f495-49cb-a0db-861e7007d37d.png#clientId=u1cc7e0b5-f224-4&from=ui&height=355&id=u2ab61a92&margin=%5Bobject%20Object%5D&name=sharded-cluster-production-architecture.bakedsvg.png&originHeight=440&originWidth=620&originalType=binary&ratio=1&size=52542&status=done&style=stroke&taskId=u6886b444-bc1b-47aa-b5fb-d34274c0189&width=500)<br />** 分片架构图解**
分片操作组件:
主分片:
集群中的每个数据库都会选择一个分片作为主分片,主分片负责存储所有不需要分片的集合;创建数据库时,数据最少的分片将作为主分片。主分片可以手动指定,但代价较高(与数据数量有关,迁移过程中无法提供服务),应尽量避免这类操作。
分片片键:
MongoDB对某个字段的值或则哈希值创建一个可能的最大值和最小值范围,在范围内不断划分,每个不同的分片管理不同的数据段(划分区域),文档的字段所在哪个取值范围就归哪个区域的分片。这个字段被是分片片键,片键选定后无法更改(5.0版本支持修改),且不保证范围相近的字段保存在同一个分片上。分片规则包含哈希分片和范围分片两种方式。
例如文档数据为 {x:-80,y=”100”,z=”你好”},x为-80,根据以值划分规则就会被归纳到下图分片1的位置
分片片键的选址范围必须很广,例如布尔类型就不适合作为片键值;分片片键分布必须平衡(即大多数文档数据的该值不能相同);片键值需避免单向的增大或减小,例如 _id包含了时间戳,属于单向增大,存在海量数据中数据分布不均的情况,因此不适合作为数据分片字段。
当指定要使用的字段数据相差的范围很小,可考虑额外添加其他数据相差范围较大的字段组成复合片键扩大划分范围;当业务需求必须使用一个单向字段作为分片字段时,可考虑使用哈希值进行划分
注意点:
1. 片键值被用来将集合内的文档数据划分为数据段
2. 片键必须对应一个索引或索引前缀(单键或复合键)
3. 可以用片键值来生成哈希片键值来划分范围
4. 同一个集合只能有一个分片
5. 范围分片字段如果没有填满数据块,分片效果将会非常差,若出现该情况需要**先删除该集合,手动修改数据块大小,添加完毕后再修改回去**,默认为64M
集群平衡(平衡器):
当分片中的数据段随着时间不断增多,将会出现某些分片数据量远大于其他分片的情况。为了保证所有分片内的数据进行平均分布,MongoDB将会进行动态处理,会将过大的数据段分裂成较小的数据段。数据端分裂ton过更新元数据进行实现。触发条件:数据段尺寸过大或数据量过多;新增或更新文档时可能触发;
在集群中如果出现分片数量不平均情况,MongoDB将会启用平衡器进行监测分片上的数据段,发现不平衡情况时将会对数据段进行迁移,触发条件:最大和最小的分片上数据段相差过大
配置服务器:
在配置时必须未复制集(副节点)。储存各分片数据段列表和范围(元数据)、集群的认证和授权信息;不同的集群不能使用同一配置服务器,会照成依赖性,导致出现潜在问题
主节点故障时,配置服务器进入只读模式,该模式下数据分段分裂和集群平衡将无法进行;整个复制集故障,分片集群将不可用
Mongos:
相当于Nginx,Mongos通过判断用户请求搜索值(分片值)选择具体数据库,但当请求的字段不为分片字段时,Mongos将会把请求数据发送给所有的分片(数据库)进行查询。
也用于对数据的添加和分片的指定,流程:开启数据库分片支持 > 设置分片规则 > 添加数据。如果需要删除分片策略,应先删除集合再建立分片策略,最后再插入数据
登录方式和MongoDB登录一致,都使用Mongo,但启动使用的是Mongos
请求数据传给所有分片进行查询
数据分片搭建:
创建两个分片节点副本集(3+3)+一个配置节点副本集(3)+两个路由节点(2),共11个服务节点的数据分片集群案例。以上一章已搭建好复制集的虚拟机为基础,需要先关闭所有MongDB进程以避免端口冲突。
分片系统部署架构图
第一套副本集搭建:
准备存放数据和日志的目录:
mkdir -p /mongodb/sharded_cluster/myshardrs01_27018/log \ &
mkdir -p /mongodb/sharded_cluster/myshardrs01_27018/data/db \ &
mkdir -p /mongodb/sharded_cluster/myshardrs01_27118/log \ &
mkdir -p /mongodb/sharded_cluster/myshardrs01_27118/data/db \ &
mkdir -p /mongodb/sharded_cluster/myshardrs01_27218/log \ &
mkdir -p /mongodb/sharded_cluster/myshardrs01_27218/data/db
新建配置文件创建27018节点:
vim /mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
systemLog:
destination: file
path: "/mongodb/sharded_cluster/myshardrs01_27018/log/mongod.log"
logAppend: true
storage:
dbPath: "/mongodb/sharded_cluster/myshardrs01_27018/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/mongodb/sharded_cluster/myshardrs01_27018/log/mongod.pid"
net:
bindIp: 0.0.0.0
port: 27018
replication:
replSetName: myshardrs01
sharding:
#分片角色
clusterRole: shardsvr
新建配置文件创建27118节点:
vim /mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
systemLog:
destination: file
path: "/mongodb/sharded_cluster/myshardrs01_27118/log/mongod.log"
logAppend: true
storage:
dbPath: "/mongodb/sharded_cluster/myshardrs01_27118/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/mongodb/sharded_cluster/myshardrs01_27118/log/mongod.pid"
net:
bindIp: 0.0.0.0
port: 27118
replication:
replSetName: myshardrs01
sharding:
#分片角色
clusterRole: shardsvr
新建配置文件创建27218节点:
vim /mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
systemLog:
destination: file
path: "/mongodb/sharded_cluster/myshardrs01_27218/log/mongod.log"
logAppend: true
storage:
dbPath: "/mongodb/sharded_cluster/myshardrs01_27218/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/mongodb/sharded_cluster/myshardrs01_27218/log/mongod.pid"
net:
bindIp: 0.0.0.0
port: 27218
replication:
replSetName: myshardrs01
sharding:
#分片角色
clusterRole: shardsvr
启动三个节点:
/usr/local/mongo/bin/mongod -f /mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
/usr/local/mongo/bin/mongod -f /mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
/usr/local/mongo/bin/mongod -f /mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21405095/1626793958414-1eaf2d9e-bf11-46f7-9b41-650e8fb3ed08.png#clientId=u9fe65c96-1d06-4&from=paste&height=43&id=u2855e721&margin=%5Bobject%20Object%5D&name=image.png&originHeight=86&originWidth=1366&originalType=binary&ratio=1&size=21491&status=done&style=stroke&taskId=u32367415-c2d8-439b-b082-68309a5005a&width=683)<br />**第一套副本启动完毕**
进入27018端口,初始化主节点:
/usr/local/mongo/bin/mongo --port 27018 登录27018端口
rs.initiate() 初始化主节点
rs.add("192.168.182.147:27118") 添加副节点
rs.addArb("192.168.182.147:27218") 添加仲裁节点
第二套副本集搭建:
准备存放数据和日志的目录:
mkdir -p /mongodb/sharded_cluster/myshardrs02_27318/log \ &
mkdir -p /mongodb/sharded_cluster/myshardrs02_27318/data/db \ &
mkdir -p /mongodb/sharded_cluster/myshardrs02_27418/log \ &
mkdir -p /mongodb/sharded_cluster/myshardrs02_27418/data/db \ &
mkdir -p /mongodb/sharded_cluster/myshardrs02_27518/log \ &
mkdir -p /mongodb/sharded_cluster/myshardrs02_27518/data/db
新建配置文件创建27318节点:
vim /mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
systemLog:
destination: file
path: "/mongodb/sharded_cluster/myshardrs02_27318/log/mongod.log"
logAppend: true
storage:
dbPath: "/mongodb/sharded_cluster/myshardrs02_27318/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/mongodb/sharded_cluster/myshardrs02_27318/log/mongod.pid"
net:
bindIp: 0.0.0.0
port: 27318
replication:
replSetName: myshardrs02
sharding:
#分片角色
clusterRole: shardsvr
新建配置文件创建27418节点:
vim /mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
systemLog:
destination: file
path: "/mongodb/sharded_cluster/myshardrs02_27418/log/mongod.log"
logAppend: true
storage:
dbPath: "/mongodb/sharded_cluster/myshardrs02_27418/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/mongodb/sharded_cluster/myshardrs02_27418/log/mongod.pid"
net:
bindIp: 0.0.0.0
port: 27418
replication:
replSetName: myshardrs02
sharding:
#分片角色
clusterRole: shardsvr
新建配置文件创建27518节点:
vim /mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
systemLog:
destination: file
path: "/mongodb/sharded_cluster/myshardrs02_27518/log/mongod.log"
logAppend: true
storage:
dbPath: "/mongodb/sharded_cluster/myshardrs02_27518/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/mongodb/sharded_cluster/myshardrs02_27518/log/mongod.pid"
net:
bindIp: 0.0.0.0
port: 27518
replication:
replSetName: myshardrs02
sharding:
#分片角色
clusterRole: shardsvr
启动三个节点:
/usr/local/mongo/bin/mongod -f /mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
/usr/local/mongo/bin/mongod -f /mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
/usr/local/mongo/bin/mongod -f /mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21405095/1626794625229-5197ec05-9fd9-4f7a-9909-53e07852c8fa.png#clientId=u4bee8ce9-cf4b-4&from=paste&height=65&id=uacc2652b&margin=%5Bobject%20Object%5D&name=image.png&originHeight=130&originWidth=1365&originalType=binary&ratio=1&size=36720&status=done&style=stroke&taskId=ub3cd6b81-8615-4880-9e44-65278871c51&width=682.5)<br />**第二套副本启动完毕**
进入27318端口,初始化主节点:
/usr/local/mongo/bin/mongo --port 27318 登录27018端口
rs.initiate() 初始化主节点
rs.add("192.168.182.147:27418") 添加副节点
rs.addArb("192.168.182.147:27518") 添加仲裁节点
配置服务器集群搭建:
准备存放数据和日志的目录:
mkdir -p /mongodb/sharded_cluster/myconfigrs_27019/log \ &
mkdir -p /mongodb/sharded_cluster/myconfigrs_27019/data/db \ &
mkdir -p /mongodb/sharded_cluster/myconfigrs_27119/log \ &
mkdir -p /mongodb/sharded_cluster/myconfigrs_27119/data/db \ &
mkdir -p /mongodb/sharded_cluster/myconfigrs_27219/log \ &
mkdir -p /mongodb/sharded_cluster/myconfigrs_27219/data/db
新建配置文件创建27019节点:
vim /mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
systemLog:
destination: file
path: "/mongodb/sharded_cluster/myconfigrs_27019/log/mongod.log"
logAppend: true
storage:
dbPath: "/mongodb/sharded_cluster/myconfigrs_27019/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/mongodb/sharded_cluster/myconfigrs_27019/log/mongod.pid"
net:
bindIp: 0.0.0.0
port: 27019
replication:
replSetName: myconfigrs
sharding:
clusterRole: configsvr
新建配置文件创建27119节点:
vim /mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
systemLog:
destination: file
path: "/mongodb/sharded_cluster/myconfigrs_27119/log/mongod.log"
logAppend: true
storage:
dbPath: "/mongodb/sharded_cluster/myconfigrs_27119/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/mongodb/sharded_cluster/myconfigrs_27119/log/mongod.pid"
net:
bindIp: 0.0.0.0
port: 27119
replication:
replSetName: myconfigrs
sharding:
clusterRole: configsvr
新建配置文件创建27219节点:
vim /mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
systemLog:
destination: file
path: "/mongodb/sharded_cluster/myconfigrs_27219/log/mongod.log"
logAppend: true
storage:
dbPath: "/mongodb/sharded_cluster/myconfigrs_27219/data/db"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/mongodb/sharded_cluster/myconfigrs_27219/log/mongod.pid"
net:
bindIp: 0.0.0.0
port: 27219
replication:
replSetName: myconfigrs
sharding:
clusterRole: configsvr
启动三个节点:
/usr/local/mongo/bin/mongod -f /mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
/usr/local/mongo/bin/mongod -f /mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
/usr/local/mongo/bin/mongod -f /mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
配置服务器集群启动成功
进入27019端口,初始化主节点:
/usr/local/mongo/bin/mongo --port 27019 登录27019端口
rs.initiate() 初始化主节点
rs.add("192.168.182.147:27119") 添加副节点
rs.add("192.168.182.147:27219") 添加副节点
MongoOS路由节点一搭建:
准备存放数据和日志的目录:
mkdir -p /mongodb/sharded_cluster/mymongos_27017/log
新建配置文件创建27017节点:
sharding.configDB用来指定配置服务器,参数为 :分片名/IP
vi /mongodb/sharded_cluster/mymongos_27017/mongos.conf
systemLog:
destination: file
path: "/mongodb/sharded_cluster/mymongos_27017/log/mongod.log"
logAppend: true
processManagement:
fork: true
pidFilePath: "/mongodb/sharded_cluster/mymongos_27017/log/mongod.pid"
net:
bindIp: 0.0.0.0
port: 27017
sharding:
#指定配置节点副本集
configDB: myconfigrs/192.168.182.147:27019,192.168.182.147:27119,192.168.182.147:27219
使用MongoOS启动:
/usr/local/mongo/bin/mongos -f /mongodb/sharded_cluster/mymongos_27017/mongos.conf
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21405095/1626830711437-0d6c4b98-6d3b-48e9-a84d-c66986baffd3.png#clientId=u4df5f438-f49d-4&from=paste&height=101&id=u1e308430&margin=%5Bobject%20Object%5D&name=image.png&originHeight=201&originWidth=1365&originalType=binary&ratio=1&size=58469&status=done&style=stroke&taskId=udd582fe0-32ad-4179-92af-c86d12f0a1f&width=682.5)<br />**MongoOS启动完毕**
进入27017端口,初始化MongOS:
/usr/local/mongo/bin/mongo --port 27017 登录27017端口
MongoOS路由节点一连接分片集群:
登录MongOS节点一进行分片配置,没有配置分片将无法进行数据保存
常用命令:
如果只剩下一个分片,将无法删除。移除时会自动转移分片数据
sh.addShard("<名称>/<hostname><:port>") 添加分片,指定复制集的IP和端口号
use admin
db.runCommand({ removeShard: "分片名" } ) 根据分片名移除分片
sh.enableSharding("库名") 对数据库开启分片功能
sh.status() 查看分片状态
sh.shardCollection("数据库.集合名",{"分片字段":"分片规则"},boolean) 指定集合选择分片字段进行分片,布尔值代表是否唯一索引,默认否
sh.isBalancerRunning() 查看平衡器是否工作
sh.getBalancerState() 查看平衡器状态
连接副本集:
#连接第一套副本集:
sh.addShard("myshardrs01/192.168.182.147:27018,192.168.182.147:27118,192.168.182.147:27218")
#连接第二套副本集:
sh.addShard("myshardrs02/192.168.182.147:27318,192.168.182.147:27418,192.168.182.147:27518")
查看分片状态
Hash分片案例:
对 articledb.comment 创建一个哈希分片并添加1000条测试数据
sh.shardCollection("articledb.comment",{"nickname":"hashed"}) 创建nickname字段的hash分片
哈希分片创建成功
查看分片状态:
默认为非唯一索引、开启平衡器、建立四个区域
创建数据:
use articledb 选择分片数据库
for(var i=1;i<=1000;i++) {db.comment.insert({_id:i+"",nickname:"BoBo"+i})} 添加测试数据
登录第一套副本集查看分片数据:
/usr/local/mongo/bin/mongo --port 27018
use arcitledb
db.comment.count()
获得507个数据
登录第二套副本集查看分片数据:
/usr/local/mongo/bin/mongo --port 27318
use arcitledb
db.comment.count()
获得493个数据
范围分片案例:
对 articledb.author创建一个范围分片并添加20000条测试数据
sh.shardCollection("articledb.author",{"age":1})
查看分片状态:
默认为非唯一索引、开启平衡器、建立一个区域
创建数据:
use articledb
for(var i=1;i<=20000;i++) {db.author.save({"name":"BoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBo"+i,"age":NumberInt(i%120)})}
数据添加成功
再次查看分片状态发现依旧为一个分片,原因是该分片规则没有把数据块填满导致不会进行范围切割,因此需要修改数据块大小,这里以1M为例
#删除集合:
db.author.drop()
#切换到配置数据库修改数据块大小:
use config
db.settings.save( { _id:"chunksize", value: 1 } )
#重新添加分片和数据:
sh.shardCollection("articledb.author",{"age":1})
use articledb
for(var i=1;i<=20000;i++) {db.author.save({"name":"BoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBo"+i,"age":NumberInt(i%120)})}
#还原数据块大小:
use config
db.settings.save( { _id:"chunksize", value: 64 } )
修改数据块后分片成功
MongoOS路由节点二搭建:
准备存放数据和日志的目录:
mkdir -p /mongodb/sharded_cluster/mymongos_27117/log
新建配置文件创建27117节点:
vi /mongodb/sharded_cluster/mymongos_27117/mongos.conf
systemLog:
destination: file
path: "/mongodb/sharded_cluster/mymongos_27117/log/mongod.log"
logAppend: true
processManagement:
fork: true
pidFilePath: "/mongodb/sharded_cluster/mymongos_27117/log/mongod.pid"
net:
bindIp: 0.0.0.0
port: 27117
sharding:
#指定配置节点副本集
configDB: myconfigrs/192.168.182.147:27019,192.168.182.147:27119,192.168.182.147:27219
使用MongoOS启动:
/usr/local/mongo/bin/mongos -f /mongodb/sharded_cluster/mymongos_27117/mongos.conf
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21405095/1626839451966-19fb90db-da6d-44da-b8ac-bead454181e5.png#clientId=u6ec7158d-f8f8-4&from=paste&height=93&id=u25899b38&margin=%5Bobject%20Object%5D&name=image.png&originHeight=178&originWidth=958&originalType=binary&ratio=1&size=40444&status=done&style=stroke&taskId=u0109b683-80ab-4b8f-a79d-d819834cbf3&width=500)<br />**MongoOS启动完毕**
MongoCompass连接分片:
与单机Mongo连接操作一致,指定 IP 和 端口号 即可
使用客户端进行登录
SpringBoot连接数据分片:
在配置文件中指定连接的Mongos地址即可
spring:
data:
mongodb:
uri: mongodb://192.168.182.147:27017,192.168.182.147:27117/articledb
写入数据的时候,会选择一个路由:
清除所有节点数据:
一、查询出所有节点服务并杀掉进程号:
#强制关闭(有数据损坏风险)
ps -ef | grep mongo
kill -9 进程号
#依次登录手动关闭
mongo --port 27017
use admin
db.shutdownServer()
二、清除所有节点数据:
#清除节点一数据:
rm -rf /mongodb/sharded_cluster/myshardrs01_27018/data/db \ &
rm -rf /mongodb/sharded_cluster/myshardrs01_27118/data/db \ &
rm -rf /mongodb/sharded_cluster/myshardrs01_27218/data/db \ &
#清除节点二数据:
rm -rf /mongodb/sharded_cluster/myshardrs02_27318/data/db \ &
rm -rf /mongodb/sharded_cluster/myshardrs02_27418/data/db \ &
rm -rf /mongodb/sharded_cluster/myshardrs02_27518/data/db \ &
#清除配置服务器数据:
rm -rf /mongodb/sharded_cluster/myconfigrs_27019/data/db \ &
rm -rf /mongodb/sharded_cluster/myconfigrs_27119/data/db \ &
rm -rf /mongodb/sharded_cluster/myconfigrs_27219/data/db \ &
#清除路由数据:
rm -rf /mongodb/sharded_cluster/mymongos_27017/data/db/*.* \ &
rm -rf /mongodb/sharded_cluster/mymongos_27117/data/db/*.* \ &
三、查看或修改有问题的配置文件
四、依次启动所有节点除路由节点之外的所有节点
五、对数据分片副本集和配置副本集进行初始化和相关配置
六、启动mongos节点
七、登录mongos,在其上进行分片操作
关闭所有节点:
分为手动关闭和强制关闭,强制关闭即kill命令,但有数据损坏风险,若出现该情况需要进行数据修复
手动关闭步骤:
1、关闭分片服务器副本集中的服务,依次关闭仲裁节点、副本节点、主节点
mongo --port 端口 按顺序进入副本集端口
rs.stepDown() 告知副本集说本机要下线
use admin 切换到admin库
db.shutdownServer() 关闭服务
2、关闭配置服务器副本集的服务,建议依次关闭副本节点、主节点
3、关闭路由服务器的服务,建议依次关闭两个路由节点
数据修复:
单机和集群的操作一致,都是删除数据后再进行修复,路径为配置文件中的 dbPath 路径
1、先删除集群中主节点的lock数据:
rm -f /mongodb/replica_sets/myrs_27017/data/db/*.lock \
rm -f /mongodb/replica_sets/myrs_27018/data/db/*.lock \
rm -f /mongodb/replica_sets/myrs_27019/data/db/mongod.lock \
2、选择工具进行数据修复:
/usr/local/mongodb/bin/mongod --repair --dbpath=/mongodb/replica_sets/myrs_27017/data/db
/usr/local/mongodb/bin/mongod --repair --dbpath=/mongodb/replica_sets/myrs_27018/data/db
/usr/local/mongodb/bin/mongod --repair --dbpath=/mongodb/replica_sets/myrs_27019/data/db