返回 导航

其他

hangge.com

MongoDB - 分布式集群搭建部署详解2(分片Sharding 模式)

作者:hangge | 2022-01-17 08:10
    前文我介绍了 MongoDB 集群的副本模式(点击查看),本文接着介绍分片(Sharding)模式。MongoDB 的分片机制允许创建一个包含许多台机器的集群,将数据子集分散在集群中,每个分片维护着一个数据集合的子集。与副本集相比,使用集群架构可以使应用程序具有更强大的数据处理能力。
    构建一个 MongoDB 的分片集群,需要三个重要的组件,分别是分片服务器(Shard Server)、配置服务器(Config Server)和路由服务器(Route Server):
  • Shard Server:每个 Shard Server 都是一个 mongod 数据库实例,用于存储实际的数据块。整个数据库集合分成多个块存储在不同的 Shard Server 中。在实际生产中,一个 Shard Server 可由几台机器组成一个副本集来承担,防止因主节点单点故障导致整个系统崩溃。
  • Config Server:这是独立的一个 mongod 进程,保存集群和分片的元数据,在集群启动最开始时建立,保存各个分片包含数据的信息。
  • Route Server:这是独立的一个 mongos 进程,Route Server 在集群中可作为路由使用,客户端由此接入,让整个集群看起来像是一个单一的数据库,提供客户端应用程序和分片集群之间的接口。Route Server 本身不保存数据,启动时从 Config Server 加载集群信息到缓存中,并将客户端的请求路由给每个 Shard Server,在各 Shard Server 返回结果后进行聚合并返回客户端。
    在实际生产环境中,为了满足高可用性和高可扩展性的需求,并不会单纯只采用分片模式。而是将副本集和分片是结合起来使用的,即每一个分片服务器又会由多台机器组成的一个副本集来承担,从而防止某一分片单点故障导致整个系统奔溃。下面通过样例进行演示如何搭建副本集+分片集群模式。

二、搭建分片(Sharding)+副本集(Replica Set)集群模式

1,环境准备

   这里我们准备三台 CentOS 服务器作用于搭建包含三个分片的集群(并且每个分片又由三个节点的副本集来承担),因此每台服务器上都会包含 5 个服务,具体如下:
注意:这里每个分片副本集的主节点分别使用不同的服务器,起到分散压力的效果。
26.47.136.14 26.47.136.15 26.47.136.16
route server(端口:24017 route server(端口:24017 route server(端口:24017
config server(端口:24000 config server(端口:24000 config server(端口:24000
shard server1 主节点(端口:24001 shard server1 副本节点(端口:24001 shard server1 副本节点(端口:24001
shard server2 副本节点(端口:24002 shard server2 主节点(端口:24002 shard server2 副本节点(端口:24002
shard server3 副本节点(端口:24003 shard server3 副本节点(端口:24003 shard server3 主节点(端口:24003

2,安装 MongoDB

(1)首先访问官网(点击跳转),寻找适合 CentOS 系统的下载地址:

(2)分别登录三台服务器,使用 wget 命令下载安装包(后续步骤在三台服务器上都是同样操作):
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-4.4.10.tgz

(3)执行如下命令将安装包解压:
tar -zxvf mongodb-linux-x86_64-rhel62-4.4.10.tgz

(4)将解压出来的文件夹拷贝到指定目录:
mv mongodb-linux-x86_64-rhel62-4.4.10 /usr/local/mongodb

(5)进入 mongodb 文件夹:
cd /usr/local/mongodb

(6)分别在每台机器建立 confrouteconfigshard1shard2shard3 六个目录,因为 route 不存储数据,只需要建立日志文件目录即可:
mkdir -p conf
mkdir -p route/log
mkdir -p config/db
mkdir -p config/log
mkdir -p shard1/db
mkdir -p shard1/log
mkdir -p shard2/db
mkdir -p shard2/log
mkdir -p shard3/db
mkdir -p shard3/log

(7)最后各服务器还要执行下面命令配置 firewall 防火墙策略:
firewall-cmd --permanent --add-port=24017/tcp
firewall-cmd --permanent --add-port=24000/tcp
firewall-cmd --permanent --add-port=24001/tcp
firewall-cmd --permanent --add-port=24002/tcp
firewall-cmd --permanent --add-port=24003/tcp
firewall-cmd --reload

3,配置启动 config server(配置服务器)

(1)分别在三台服务器上添加相关配置文件:
提示mongodb3.4 以后要求配置服务器也创建副本集,不然集群搭建不成功。
vi /usr/local/mongodb/conf/config.conf

(2)在文件中填写如下内容:
pidfilepath = /usr/local/mongodb/config/log/configsrv.pid
dbpath = /usr/local/mongodb/config/db
logpath = /usr/local/mongodb/config/log/congigsrv.log
logappend = true
 
bind_ip = 0.0.0.0
port = 24000
fork = true
 
#标明这是一个配置服务器集群
configsvr = true

#副本集名称
replSet = configs
 
#设置最大连接数
maxConns = 20000

(3)保存退出后,执行如下命令启动三台服务器的 config server
cd /usr/local/mongodb/bin
./mongod -f /usr/local/mongodb/conf/config.conf

(4)接着我们要初始化配置副本集,首先连接任意一个节点的 config server
/usr/local/mongodb/bin/mongo 26.47.136.14:24000

(5)执行如下命令设置副本集配置:
各参数说明:
  • cfg 是可以任意的名字,当然最好不要是 mongodb 的关键字,confconfig 都可以。
  • 最外层的 _id 表示配置文件中 replica set 的名字
  • members 里包含的是所有节点的地址。
cfg = {
    _id : "configs",
    members : [
    {_id : 0, host : "26.47.136.14:24000" },
    {_id : 1, host : "26.47.136.15:24000" },
    {_id : 2, host : "26.47.136.16:24000" }
    ]
}

(6)最后执行如下命令使配置生效:
rs.initiate(cfg)

(7)稍等一会执行如下命令查看副本集状态:
rs.status()

(8)可以看到副本集的启动配置已完成,至此 config server 已部署完毕:

4,配置启动第 1 个分片服务(shard1 server)

(1)分别在三台服务器上添加相关配置文件:
vi /usr/local/mongodb/conf/shard1.conf

(2)在文件中填写如下内容:
pidfilepath = /usr/local/mongodb/shard1/log/shard1.pid
dbpath = /usr/local/mongodb/shard1/db
logpath = /usr/local/mongodb/shard1/log/shard1.log
logappend = true

bind_ip = 0.0.0.0
port = 24001
fork = true
 
#副本集名称
replSet = shard1
 
#标明这是一个分片副本集集群;
shardsvr = true
 
#设置最大连接数
maxConns = 20000

(3)保存退出后,执行如下命令启动三台服务器的 shard1 server
cd /usr/local/mongodb/bin
./mongod -f /usr/local/mongodb/conf/shard1.conf

(4)接着我们要初始化副本集,首先连接任意一个节点的 shard1 server
/usr/local/mongodb/bin/mongo 26.47.136.14:24001

(5)执行如下命令使用 admin 数据库:
use admin

(6)然后执行如下命令设置副本集配置:
cfg = {
    _id : "shard1",
     members : [
         {_id : 0, host : "26.47.136.14:24001", priority: 3},
         {_id : 1, host : "26.47.136.15:24001", priority: 2},
         {_id : 2, host : "26.47.136.16:24001", priority: 1}
     ]
 }

(7)最后执行如下命令使配置生效:
rs.initiate(cfg)

(8)稍等一会执行如下命令查看副本集状态:
rs.status()

(9)可以看到副本集的启动配置已完成(其中 26.47.136.14 作为主节点),至此 shard1 server 已部署完毕:

5,配置启动第 2 个分片服务(shard2 server)

(1)分别在三台服务器上添加相关配置文件:
vi /usr/local/mongodb/conf/shard2.conf

(2)在文件中填写如下内容:
pidfilepath = /usr/local/mongodb/shard2/log/shard2.pid
dbpath = /usr/local/mongodb/shard2/db
logpath = /usr/local/mongodb/shard2/log/shard2.log
logappend = true

bind_ip = 0.0.0.0
port = 24002
fork = true
 
#副本集名称
replSet = shard2
 
#标明这是一个分片副本集集群;
shardsvr = true
 
#设置最大连接数
maxConns = 20000

(3)保存退出后,执行如下命令启动三台服务器的 shard2 server
cd /usr/local/mongodb/bin
./mongod -f /usr/local/mongodb/conf/shard2.conf

(4)接着我们要初始化副本集,首先连接任意一个节点的 shard2 server
/usr/local/mongodb/bin/mongo 26.47.136.14:24002

(5)执行如下命令使用 admin 数据库:
use admin

(6)然后执行如下命令设置副本集配置:
cfg = {
    _id : "shard2",
     members : [
         {_id : 0, host : "26.47.136.14:24002", priority: 1},
         {_id : 1, host : "26.47.136.15:24002", priority: 3},
         {_id : 2, host : "26.47.136.16:24002", priority: 2}
     ]
 }

(7)最后执行如下命令使配置生效:
rs.initiate(cfg)

(8)稍等一会执行如下命令查看副本集状态:
rs.status()

(9)可以看到副本集的启动配置已完成(这次 26.47.136.15 作为主节点),至此 shard2 server 已部署完毕:

6,配置启动第 3 个分片服务(shard3 server)

(1)分别在三台服务器上添加相关配置文件:
vi /usr/local/mongodb/conf/shard3.conf

(2)在文件中填写如下内容:
pidfilepath = /usr/local/mongodb/shard3/log/shard3.pid
dbpath = /usr/local/mongodb/shard3/db
logpath = /usr/local/mongodb/shard3/log/shard3.log
logappend = true

bind_ip = 0.0.0.0
port = 24003
fork = true
 
#副本集名称
replSet = shard3
 
#标明这是一个分片副本集集群;
shardsvr = true
 
#设置最大连接数
maxConns = 20000

(3)保存退出后,执行如下命令启动三台服务器的 shard3 server
cd /usr/local/mongodb/bin
./mongod -f /usr/local/mongodb/conf/shard3.conf

(4)接着我们要初始化副本集,首先连接任意一个节点的 shard3 server
/usr/local/mongodb/bin/mongo 26.47.136.14:24003

(5)执行如下命令使用 admin 数据库:
use admin

(6)然后执行如下命令设置副本集配置:
cfg = {
    _id : "shard3",
     members : [
         {_id : 0, host : "26.47.136.14:24003", priority: 2},
         {_id : 1, host : "26.47.136.15:24003", priority: 1},
         {_id : 2, host : "26.47.136.16:24003", priority: 3}
     ]
 }

(7)最后执行如下命令使配置生效:
rs.initiate(cfg)

(8)稍等一会执行如下命令查看副本集状态:
rs.status()

(9)可以看到副本集的启动配置已完成(这次 26.47.136.16 作为主节点),至此 shard3 server 已部署完毕:

7,配置启动路由服务器(route server)

(1)分别在三台服务器上添加相关配置文件:
vi /usr/local/mongodb/conf/route.conf

(2)在文件中填写如下内容:
pidfilepath = /usr/local/mongodb/route/log/route.pid
logpath = /usr/local/mongodb/route/log/route.log
logappend = true

bind_ip = 0.0.0.0
port = 24017
fork = true

#监听的配置服务器
configdb = configs/26.47.136.14:24000,26.47.136.15:24000,26.47.136.16:24000
 
#设置最大连接数
maxConns = 20000

(3)保存退出后,执行如下命令启动三台服务器的 route server
注意:这里启动命令使用的是 mongos,而不是上面的 mongod
cd /usr/local/mongodb/bin
./mongos -f /usr/local/mongodb/conf/route.conf

(4)接着将路由服务器和分片副本集串联起来。首先连接任意一个节点的 route server
/usr/local/mongodb/bin/mongo 26.47.136.14:24017

(5)执行如下命令使用 admin 数据库:
use admin

(6)执行如下命令将副本集添加到分片集中:
sh.addShard("shard1/26.47.136.14:24001,26.47.136.15:24001,26.47.136.16:24001");
sh.addShard("shard2/26.47.136.14:24002,26.47.136.15:24002,26.47.136.16:24002");
sh.addShard("shard3/26.47.136.14:24003,26.47.136.15:24003,26.47.136.16:24003");

(7)然后执行如下命令查看集群状态:
sh.status()

(8)显示如下内容说明整个集群已经搭建完毕:

附:分片测试

(1)由于并不是所有数据库和集合都需要分片。所以要对一个集合分片,首先要对这个集合的数据库启用分片,我们连接任意一个 route server
/usr/local/mongodb/bin/mongo 26.47.136.14:24017

(2)执行如下命令使用 admin 数据库:
use admin

(3)假设我们需要让 hangge 这个数据库启用分片,只需要执行如下命令,便可以对该数据库内的集合进行分片了:
sh.enableSharding("hangge")

(4)切换到 hangge 数据库:
use hangge

(5)接着执行如下命令往 user 集合中插入 10 万条数据:
for(var i=100000;i<200000;i++){  
  db.users.insert({"username" : "user"+i , "created_at" : new Date()});  
} 

(6)查看集群信息,发现目前所有数据都插入到了第 1 个分片(shard1)中,这个是由于我们没有对集合指定分片键(shard key),因此该集合还不是个分片集合:
每个数据库创建时都会有一个 primary shard(不一定都是第 1 个分片):
  • 如果该数据库下没有启用分片的集合,其所有数据都会存储到 primary shard
  • 如果该数据库下启用分片(即调用 shardCollection 命令)的集合,刚开始会生成一个 [minKey, maxKey]chunk,该 chunk 初始会存储在 primary shard 上,然后随着数据的写入,不断的发生 chunk 分裂及迁移。
sh.status();


(8)执行如下命令查看 users 集合的分片情况,也提示我们该集合不是一个分片集合:
db.users.getShardDistribution()

(9)对集合分片时,我们要选择一个分片键(shard key)。分片键是集合的一个键,MongoDB 根据这个键拆分数据。由于只有被索引过的键才能够作为分片键,假设我们需要用 username 作为分片键,首先要在该键上创建索引:
关于分片键(shard key)的注意事项:
  • shard key 在分片完毕后是不能修改的,一个集合上只能有一个 shard key
  • shard key 上必须有索引(可以是以 shard key 开头的联合索引),如何集合不存在插入数据时 mongodb 会为 shard key 创建索引。但如果是已经存在的集合那么必须手动为 shard key 创建索引。
  • 在分片集合中只有 _id shard key 前缀的索引可以是 unique index,其他索引只能是普通索引。如果一个普通 key 上有 unique index 那么你不能以其他 key shard key collection 进行 sharding
db.users.ensureIndex({"username" : 1})

(10)接着执行如下命令让 users 集合依据 username 对集合进行分片: 
(1)mongodb 提供了 2 种策略来对集合进行分片:
  • 范围(range)分片,可以使用多个字段作为分片键,并将数据划分为由分片键确定的连续范围。如:sh.shardCollection("hangge.users", {"username" : 1})
  • 哈希(hash)分片:对单列使用 hash 索引作为分片键。如:sh.shardCollection("hangge.users", {"username" : "hashed"})
(2)本样例使用的是范围分片,如果使用哈希分片的话,前面创建索引时索引类型也要改成哈希类型,即:db.users.ensureIndex({"username" : "hashed"})
sh.shardCollection("hangge.users", {"username" : 1})

(11)再次查看 users 集合的分片情况,虽然目前已经是分片集合了,但是所有的数据仍然在 shard1 分片上。这是因为启用分片之后,数据会以 chunk 为单位(默认 64MB)根据片键均匀的分散到后端 1 或多个 shard 上。但目前记录数还没有超过阀值,因此只有 1chunk,不会分裂。
db.users.getShardDistribution()

(12)为了便于观察数据分片,我们这里将 chunk 大小设置为 1MB(这个值大小可以自由设置为 1~1024MB 之间):
use config
db.settings.save({_id:"chunksize",value:1})

(13)虽然我们将 chunk 大小改下了,但 chunk 自动分裂只在插入的时候生效。我们再次切换到 hangge 数据库,并往 users 集合再插入 10 万条记录(执行时间会比较久,需要耐心等待): 
use hangge
for(var i=200000;i<300000;i++){  
  db.users.insert({"username" : "user"+i , "created_at" : new Date()});  
} 

(14)再次查看 users 集合的分片情况,可以发现数据已经均匀分布在三个分片上了:
db.users.getShardDistribution()

(15)而执行如下命令可以看到各个 chunk 包含的数据范围以及对应分片信息:
提示:由于 chunks 数量比较多,所以我们加了个 verbose 参数保证所有信息都能打印出来。否则会报“mongoDB sh.status() too many chunks to print
sh.status({"verbose":1})
评论

全部评论(0)

回到顶部