从零搭建MongoDB Cluster分片集群

由于单台MongoDB服务器目前存在非常大的读写压力,并且在查询过程中消耗大量时间。使用8核32GB的云服务器完全不能满足现阶段数据吞吐量的要求(一天100万条数据写入,超过100万条数据读出)。当查询热数据时还能应付,但是查询冷数据时可能出现MongoDB查询非常缓慢的问题。因此我们将尝试搭建MongoDB Cluster分片集群。

MongoDB Cluster集群结构设计

为本次搭建MongoDB Cluster集群,我准备了3台8核32GB服务器,系统为CentOS 7。MongoDB集群计划切分三个分片,每个分片由3个节点的副本集组成。加上MongoDB配置服务器(Config Server,也是一个3节点的副本集),Mongos路由服务器(3个独立节点,非副本集)。因此,在每一台云服务器上将运行5个MongoDB的进程。如图所示:
MongoDB集群

MongoDB的下载和安装

目前我选择最新的稳定版MongoDB 4.0.3,在MongoDB官网下载解压即可。

tar -zxvf mongodb-linux-x86_64-4.0.3.tgz

MongoDB集群配置

由于一个MongoDB集群有3大类服务组成:

  • shard分片服务器:用于存储实际的数据块,实际生产环境中一个shard分片角色必须由几台机器组成的副本集承担,防止主机单点故障。
  • config servers配置服务器:存储了整个集群的metadata和配置信息,其中包括chunk信息等,实际生产环境中一个配置服务器角色必须由几台机器组成的副本集承担
  • mongos服务器:客户端由此接入,类似一个查询路由。转发客户端发送的所有请求且让整个集群看上去像单一数据库。
  • 副本集仲裁节点Arbiter:当预算有限时,要搭建副本集只有两个节点,这时需要加入一个仲裁节点参与投票机制。冲裁节点不存储数据,无法成为主节点,只参与投票。仲裁节点在整个集群中不是必须的,只有当每一个副本集无法满足3个节点以上时需要设置仲裁节点。

Shard分片服务器配置

为了更好的描述建立Shard分片服务器,我讲从创建副本集到创建Shard分片使用命令行一步步地演示整个流程。如果对此步骤非常熟悉的话,我们也可以通过配置文件的方式进行配置。使用配置文件就省略了创建副本集的过程。

创建MongoDB副本集
目前我有3台8核32G内存的服务器,MongoDB副本集就分别部署在三个服务器节点上。由于设计的MongoDB有三个分片,所以需要创建3个副本集。因此,三个副本集在三个节点服务器上分别监听不同端口。约定如下:

  • 副本集rs0统一监听27017端口
  • 副本集rs1统一监听27018端口
  • 副本集rs2统一监听27019端口

按照以上分配方案,分别在三个节点上运行以下命令:

./bin/mongod --port 27017 --bind_ip 0.0.0.0 --fork --dbpath /data/db-0 --logpath /data/logs/mongod-0.log --logappend --shardsvr --replSet=rs0
./bin/mongod --port 27018 --bind_ip 0.0.0.0 --fork --dbpath /data/db-1 --logpath /data/logs/mongod-1.log --logappend --shardsvr --replSet=rs1
./bin/mongod --port 27019 --bind_ip 0.0.0.0 --fork --dbpath /data/db-2 --logpath /data/logs/mongod-2.log --logappend --shardsvr --replSet=rs2

随后在MongoDB命令行中分别配置初始化副本集:

#初始化副本集rs0
mongo localhost:27017
rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'host1:27017'}, {_id: 1, host: 'host2:27017'}, {_id: 2, host: 'host3:27017'}]})
rs.isMaster() #查看结果

#初始化副本集rs1
mongo localhost:27018
rs.initiate({_id: 'rs1', members: [{_id: 0, host: 'host1:27018'}, {_id: 1, host: 'host2:27018'}, {_id: 2, host: 'host3:27018'}]})
rs.isMaster() #查看结果

#初始化副本集rs2
mongo localhost:27019
rs.initiate({_id: 'rs2', members: [{_id: 0, host: 'host1:27019'}, {_id: 1, host: 'host2:27019'}, {_id: 2, host: 'host3:27019'}]})
rs.isMaster() #查看结果

Config配置服务器配置

在MongoDB分片集群中配置服务器也需要被配置为副本集的形式提供服务。因此和配置分片服务器类似,配置服务器副本集也分散在3个节点上,并且统一监听端口20000。按照以上分配方案,分别在三个节点上运行以下命令:

./bin/mongod --port 20000 --bind_ip 0.0.0.0 --fork --dbpath /data/config --logpath /data/logs/config.log --logappend --configsvr --replSet=conf

随后随便连接一个节点进入命令行执行以下命令初始化配置服务器副本集:

mongo localhost:20000
rs.initiate({_id: 'conf', members: [{_id: 0, host: 'host1:20000'}, {_id: 1, host: 'host2:20000'}, {_id: 2, host: 'host3:20000'}]})
rs.isMaster() #查看结果

Mongos路由服务器配置

理论上一个MongoDB Cluster集群只需要运行一台Mongos路由服务器即可。因此,在一台节点上启动Mongos或在三台节点上启动Mongos都是可以的。我们约定mongos服务统一监听27016端口。启动命令如下:

#命令行中需要制定配置服务器副本集的信息
./bin/mongos --port 27016 --bind_ip 0.0.0.0 --fork --logpath /data/logs/mongos.log --logappend --configdb conf/host1:20000,host2:20000,host3:20000

MongoDB分片配置

以上服务都启动好以后,就可以连接到mongos服务器上进行分片配置。命令行如下:

#mongos路由服务器监听的端口是27016
mongo localhost:27016
use admin
db.runCommand({ addshard: 'rs0/host1:27017,host2:27017,host3:27017'})
db.runCommand({ addshard: 'rs1/host1:27018,host2:27018,host3:27018'})
db.runCommand({ addshard: 'rs2/host1:27019,host2:27019,host3:27019'})
#或者使用sh.addShard('rs0/host1:27017,host2:27017,host3:27017')

#如果是新建mongodb集群,需要创建用户
use admin;
db.createUser(
{
    user: "mongo_root",
    pwd: "MongoRoot1234",
    roles: [ { role: "root", db: "admin" }],
    passwordDigestor: "server"
  }
);
db.auth("mongo_root", "MongoRoot1234");

#查看shard分片的情况
db.adminCommand({ listShards: 1 })




在数据库上启用分片功能
到目前为止,我们已经成功的创建了一个MongoDB Cluster分片集群。然而在默认情况下,集群中的数据库是不启用分片功能的。如果要在数据库shop里面启用分片,可以使用以下命令:

#mongos路由服务器监听的端口是27016
mongo localhost:27016
#在shop数据库中创建items数据集
use shop
db.createCollection("items")
#为items创建index,否则无法在下一步指定shard片键
db.items.createIndex( { item_id: 1, _id: 1 })
#切换到admin数据库
use admin
db.runCommand({ enablesharding: "shop" });
db.runCommand({ shardcollection: 'shop.items', key: {item_id: 1, _id: 1}, unique:true})

#切换到shop数据库查看数据库情况
use shop
db.stats()

在启用集合分片时,需要指定分片的片键,MongoDB将根据片键进行分片。一般情况下选择分片策略大致有范围片键和哈希片键两种。

范围片键
范围片键是指通过数据字段的值的范围进行分片。这种分片方式的数据分布相对不如哈希片键的分片结果更均匀,但是查询操作的效率更高。

哈希片键
哈希片键是指通过对数据字段计算得到的哈希值进行分片。这种分片方式的数据分布更加均匀,但是不利于查询操作。

组合片键
上例中采用范围组合片键策略,使用了_id和item_id两个字段作为片键。这种片键的分片策略可以近似看作如下过程:

  • 先将所有数据按照item_id的范围分为m个数组
  • 在根据每个item_id划分的数组内部,再根据_id的范围分为n个数组
  • 由item_id和_id共同的范围,将所有数据划分为若干个块(chunk)
  • MongoDB中每个块存储在不同的分片中,由mongos进行维护

MongoDB Cluster分片集群扩容

向集群中增加新的shard分片副本集,会触发分片集群均衡器(Sharded Cluster Balancer)自动迁移数据块。默认情况下,MongoDB集群的均衡器balancer是自动开启的。

参考文档

部署MongoDB分片集群
MongoDB分片集群组件
MongoDB片键概述
使用配置文件启动MongoDB集群
MongoDB集群问题合集

Captain QR Code

扫码联系船长

发表回复

您的电子邮箱地址不会被公开。