1、概述
分片(sharding)是一种跨多台机器分布数据的方法, MongoDB使用分片来支持具有非常大的数据集和高吞吐量操作的部署。
换句话说:分片(sharding)是指将数据拆分,将其分散在不同的机器上的过程。有时也用分区(partitioning)来表示这个概念。将数据分散到不同的机器上,不需要功能强大的大型计算机就可以储存更多的数据,处理更多的负载。
具有大型数据集或高吞吐量应用程序的数据库系统可能会挑战单个机器的容量。例如,高查询率会耗尽机器的CPU容量。
有两种解决系统增长的方法:垂直扩展和水平扩展。
垂直扩展意味着增加单个机器的容量,例如使用更强大的CPU,添加更多RAM或增加存储空间量。但单个机器的硬件配置具有上限性。
水平扩展意味着将整体数据集进行划分并分散在多个机器上。虽然单个机器的总体速度或容量可能不高,但每台机器只处理整体数据集的子集,可以提供比单个高速大容量机器更高的效率。扩展容量也仅仅是根据需要添加额外的机器,这比单个机器的高端硬件的总体成本更低,同时带来的问题是基础架构和部署维护的复杂性增加。
MongoDB支持通过分片进行水平扩展。
2、分片集群角色
如上图所示,是本文分片集群的目标架构。
mongos充当路由器,如果要实现对数据进行分片,则必须通过mongos向集群写入数据。
config server为配置服务器,存储集群的元数据和配置设置。从MongoDB3.4版本开始必须将config server部署为副本集。有关副本集的知识请自行查阅相关资料。
分片是真正存储数据的MongoDB服务器,每个分片存储一部分数据集,这里我们搭建三个分片(要求至少两个分片)。为了简便,分片服务器以单点方式部署。
3、开始搭建
下面开始真正的搭建分片集群,分如下步骤:
- 节点规划
- 安装分片服务器并启动
- 安装配置服务器并启动
- 初始化配置服务副本集
- 安装路由服务器
- 向路由服务器添加分片
3.1、节点规划
准备三台虚拟机,比如我的:
主机名 |
IP |
安装服务 |
hadoop102 |
192.168.31.134 |
分片1、配置服务 |
hadoop103 |
192.168.31.135 |
分片2、配置服务、路由服务 |
hadoop104 |
192.168.31.135 |
分片3、配置服务 |
3.2、安装分片服务器并启动
分片服务器其实就是单点的MongoDB服务器,只不过配置略有不同。
systemLog:
destination: file
path: "/usr/local/mongodb/mongo-4.4.8/logs/mongod.log"
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod
dbPath: "/usr/local/mongodb/mongo-4.4.8/data/db"
journal:
#启用或禁用持久性日志以确保数据文件保持有效和可恢复
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式
fork: true
net:
# 服务实例绑定的IP,默认是localhost
bindIp: localhost,192.168.31.134
#绑定的端口,默认是27017
port: 27017
sharding:
# 分片角色
clusterRole: shardsvr
与单点MongoDB配置的区别是:多了一个sharding.clusterRole: shardsvr。
在hadoop102、hadoop103、hadoop104上都安装上一个分片服务,并通过如下命令启动分片实例。
bin/mongod -f conf/mongod.conf
3.3、安装配置服务器并启动
配置服务也是一个MongoDB服务,只不过它的分片角色为configsvr。
另外,由于配置服务需要部署为副本集,因为还需要添加配置replication.replSetName: myconfigrs。
systemLog:
destination: file
path: "/usr/local/mongodb/mongo-config/logs/mongod.log"
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod
dbPath: "/usr/local/mongodb/mongo-config/data/db"
journal:
#启用或禁用持久性日志以确保数据文件保持有效和可恢复
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式
fork: true
net:
# 服务实例绑定的IP,默认是localhost
bindIp: localhost,192.168.31.134
#绑定的端口,默认是27017
port: 27019
replication:
replSetName: myconfigrs
sharding:
# 分片角色
clusterRole: configsvr
在hadoop102、hadoop103、hadoop104上都安装上一个配置服务,并通过如下命令启动配置实例。
bin/mongod -f conf/mongod.conf
3.4、初始化配置服务副本集
由于上一步中只是启动了三个配置服务,之间还没有任何联系,因为还不能称之为副本集。
首先通过MongoDB自带的客户端连接上配置服务主节点(这里将hadoop102作为主节点)。
bin/mongo --host hadoop102 --port 27019
然后依次执行如下命令。
rs.initiate()
rs.add("192.168.31.135:27019")
rs.add("192.168.31.136:27019")
3.5、安装路由服务器
路由服务器mongos的配置如下所示。
systemLog:
destination: file
path: "/usr/local/mongodb/mongos/logs/mongos.log"
logAppend: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式
fork: true
net:
# 服务实例绑定的IP,默认是localhost
bindIp: localhost,192.168.31.135
#绑定的端口,默认是27017
port: 27021
sharding:
#指定配置节点副本集
configDB: myconfigrs/hadoop102:27019,hadoop103:27019,hadoop104:27019
然后通过如下命令启动路由实例。
bin/mongos -f conf/mongos.conf
3.6、向路由服务器添加分片
此时,还不能向路由服务器写入数据,因为路由服务器还不知道具体存储数据的分片。
首先通过MongoDB自带的客户端连接上路由节点。
bin/mongo --host hadoop103 --port 27021
然后依次执行如下命令添加分片。
sh.addShard("192.168.31.134:27017")
sh.addShard("192.168.31.135:27017")
sh.addShard("192.168.31.136:27017")
大功告成!
4、数据写入测试
分片集群已经成功启动了,那到底能不能用呢?下面通过写入数据测试分片集群是否正常工作。
首先连接上路由节点,使用demo库并开启路由功能。
bin/mongo --host hadoop103 --port 27021
use demo
sh.enableSharding("demo")
MongoDB支持两种分片方式:Hash分片与Range分片。
这里我们使用student集合,并按name属性进行Hash分片
sh.shardCollection("demo.student",{name:"hashed"})
操作分片集群最常用的一个命令是sh.status(),这里我们执行一下。
在执行结果的database字段下面,就有demo库的分片信息了,如下图所示。
接下来插入10条数据。
db.student.insert({name:"刘备"})
db.student.insert({name:"关羽"})
db.student.insert({name:"张飞"})
db.student.insert({name:"赵云"})
db.student.insert({name:"黄忠"})
db.student.insert({name:"马超"})
db.student.insert({name:"诸葛亮"})
db.student.insert({name:"曹操"})})
db.student.insert({name:"周瑜"})
db.student.insert({name:"孙权"})
执行db.student.find()命令,能查出整体数据集,如下图所示。
使用客户端连接分片1,只能查出部分数据集,如下图所示。分片2、分片3同理。
bin/mongo --host hadoop102 --port 27017
如此,就达到了分片的目的。
5、索引与分片
创建分片键时MongoDB会默认创建一个索引,比如创建Hash分片则会默认创建一个Hash索引。
经验证得知,即使删除该Hash索引,即分片键上无任何索引时,数据也能进行正常地分片。
MongoDB不支持在Hash索引上指定唯一约束,可以通过在该分片键上指定一个带有唯一约束的非Hash索引来实现唯一功能。
db.student.createIndex({ "name": 1 }, { unique: true })