MongoDB分片集群的两种搭建方式及使用

1,924 阅读9分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第31天,点击查看活动详情

一、分片简介

分片(shard)是指在将数据进行水平切分之后,将其存储到多个不同的服务器节点上的一种扩展方式。分片在概念上非常类似于应用开发中的“水平分表”。不同的点在于,MongoDB本身就自带了分片管理的能力,对于开发者来说可以做到开箱即用。

1-1、为什么要使用分片?

MongoDB复制集实现了数据的多副本复制及高可用,但是一个复制集能承载的容量和负载是有限的。在你遇到下面的场景时,就需要考虑使用分片了:

  • 存储容量需求超出单机的磁盘容量。
  • 活跃的数据集超出单机内存容量,导致很多请求都要从磁盘读取数据,影响性能。
  • 写IOPS超出单个MongoDB节点的写服务能力。

垂直扩容(Scale Up) VS 水平扩容(Scale Out):

垂直扩容 : 用更好的服务器,提高 CPU 处理核数、内存数、带宽等

水平扩容 : 将任务分配到多台计算机上

1-2、MongoDB 分片集群架构

MongoDB 分片集群(Sharded Cluster)是对数据进行水平扩展的一种方式。MongoDB 使用 分片集群来支持大数据集和高吞吐量的业务场景。在分片模式下,存储不同的切片数据的节点被称为分片节点,一个分片集群内包含了多个分片节点。当然,除了分片节点,集群中还需要一些配置节点、路由节点,以保证分片机制的正常运作。

当请求到MongoDB的时候,首先进入到Mongos路由层,然后路由层去和Confi配置节点进行交互,用来判断当前数据请求落到哪个Shard上。

当Shard上面的数据进行迁移的时候,就需要同时更新config上面的数据,以及Mongos上面的缓存

image.png

1-3、核心概念

  • 数据分片:分片用于存储真正的数据,并提供最终的数据读写访问。分片仅仅是一个逻辑的概念,它可以是一个单独的mongod实例,也可以是一个复制集。图中的Shard1、Shard2都是一个复制集分片。在生产环境中也一般会使用复制集的方式,这是为了防止数据节点出现单点故障。

  • 配置服务器(Config Server):配置服务器包含多个节点,并组成一个复制集结构,对应于图中的ConfigReplSet。配置复制集中保存了整个分片集群中的元数据,其中包含各个集合的分片策略,以及分片的路由表等。

  • 查询路由(mongos):mongos是分片集群的访问入口,其本身并不持久化数据。mongos启动后,会从配置服务器中加载元数据。之后mongos开始提供访问服务,并将用户的请求正确路由到对应的分片。在分片集群中可以部署多个mongos以分担客户端请求的压力。

二、环境搭建

2-1、自主搭建

  • 3台Linux虚拟机,准备MongoDB环境,配置环境变量。
  • 一定要版本一致(重点),当前使用 version4.4.9

image.png

2-2-1、配置域名解析

在3台虚拟机上执行以下命令,注意替换实际 IP 地址(三个命令每台机器都需要执行

echo "192.168.253.131 mongo1 mongo01.com mongo02.com" >> /etc/hosts
echo "192.168.253.133 mongo2 mongo03.com mongo04.com" >> /etc/hosts
echo "192.168.253.134 mongo3 mongo05.com mongo06.com" >> /etc/hosts 

2-2-2、准备分片目录

在各服务器上创建数据目录,我们使用 /data,请按自己需要修改为其他目录:

在mongo01.com / mongo03.com / mongo05.com 上执行以下命令:

mkdir -p /data/mongodb/shard1/db /data/mongodb/shard1/log /data/mongodb/config/db /data/mongodb/config/log

在mongo02.com / mongo04.com / mongo06.com 上执行以下命令:

mkdir -p /data/mongodb/shard2/db /data/mongodb/shard2/log /data/mongodb/mongos/

最终三台机器上的data目录创建完毕,如下:

image.png

2-2-3、创建第一个分片用的复制集

在mongo01.com / mongo03.com / mongo05.com 上执行以下命令:

mongod --bind_ip 0.0.0.0 --replSet shard1 --dbpath /data/mongodb/shard1/db \
--logpath /data/mongodb/shard1/log/mongod.log --port 27010 --fork \
--shardsvr --wiredTigerCacheSizeGB 1  

--shardsvr 声明这是集群的一个分片

--wiredTigerCacheSizeGB 设置内存大小

2-2-4、初始化第一个分片复制集

# 进入mongo shell
mongo mongo01.com:27010
#shard1复制集节点初始化
rs.initiate({
    _id: "shard1",
    "members" : [
        {
            "_id": 0,
            "host" : "mongo01.com:27010"
        },
        {
            "_id": 1,
            "host" : "mongo03.com:27010"
        },
        {
            "_id": 2,
            "host" : "mongo05.com:27010"
        }
    ]
})
#查看复制集状态
rs.status()

image.png

2-2-5、创建 config server 复制集

在mongo01.com / mongo03.com / mongo05.com上执行以下命令:

mongod --bind_ip 0.0.0.0 --replSet config --dbpath /data/mongodb/config/db \
--logpath /data/mongodb/config/log/mongod.log --port 27019 --fork \
--configsvr --wiredTigerCacheSizeGB 1   

2-2-6、初始化 config server 复制集

# 进入mongo shell
mongo mongo01.com:27019
#config复制集节点初始化
rs.initiate({
    _id: "config",
    "members" : [
        {
            "_id": 0,
            "host" : "mongo01.com:27019"
        },
        {
            "_id": 1,
            "host" : "mongo03.com:27019"
        },
        {
            "_id": 2,
            "host" : "mongo05.com:27019"
        }
    ]
})  

2-2-7、搭建 mongos

在mongo01.com / mongo03.com / mongo05.com上执行以下命令

此步骤主要将 config servermongos进行配置

#启动mongos,指定config复制集
mongos --bind_ip 0.0.0.0 --logpath /data/mongodb/mongos/mongos.log --port 27017 --fork \
--configdb config/mongo01.com:27019,mongo03.com:27019,mongo05.com:27019  

2-2-8、mongos加入第1个分片

# 连接到mongos
mongo mongo01.com:27017
#添加分片
mongos>sh.addShard("shard1/mongo01.com:27010,mongo03.com:27010,mongo05.com:27010")
#查看mongos状态
mongos>sh.status()     

image.png

2-2-9、创建分片集合

连接到mongos, 创建分片集合
mongo mongo01.com:27017
mongos>sh.status()
#为了使集合支持分片,需要先开启database的分片功能
mongos>sh.enableSharding("company")
# 执行shardCollection命令,对集合执行分片初始化
mongos>sh.shardCollection("company.emp", {_id: 'hashed'})
mongos>sh.status()

再次查看mongos的状态信息

image.png

#插入测试数据
use company
for (var i = 0; i < 10000; i++) {
 db.emp.insert({i: i});
}
#查询数据分布
db.emp.getShardDistribution()  

目前分片集群只有一个分片:shard1,刚刚插入的10000条测试数据都存储在其中,如下:

image.png

2-2-10、创建第2个分片的复制集

在mongo02.com / mongo04.com / mongo06.com上执行以下命令:

mongod --bind_ip 0.0.0.0 --replSet shard2 --dbpath /data/mongodb/shard2/db  \
--logpath /data/mongodb/shard2/log/mongod.log --port 27011 --fork \
--shardsvr --wiredTigerCacheSizeGB 1      

2-2-11、初始化第二个分片的复制集

# 进入mongo shell
mongo mongo06.com:27011
#shard2复制集节点初始化
rs.initiate({
    _id: "shard2",
    "members" : [
        {
            "_id": 0,
            "host" : "mongo06.com:27011"
        },
        {
            "_id": 1,
            "host" : "mongo02.com:27011"
        },
        {
            "_id": 2,
            "host" : "mongo04.com:27011"
        }
    ]
})
#查看复制集状态
rs.status()    

2-2-12、mongos加入第2个分片

# 连接到mongos
mongo mongo01.com:27017
#添加分片
mongos>sh.addShard("shard2/mongo02.com:27011,mongo04.com:27011,mongo06.com:27011")
#查看mongos状态
mongos>sh.status()     

如下,通过mongos就可以看到当前集群下有两个分片,并且每个分片有3个节点

image.png

#查看数据分布
mongos>db.emp.getShardDistribution()

如下就可以看到数据从开始的shard1有一部分迁移到了shard2

image.png

如果要让集合数据分片存储,一定要对集合设置,让其支持分片,具体指令为:

sh.enableSharding("company")

2-2、mtools搭建

2-2-1、mtools结束

mtools是一套基于Python实现的MongoDB工具集,其包括MongoDB日志分析、报表生成及简易的数据库安装等功能。它由MongoDB原生的工程师单独发起并做开源维护,目前已经有大量的使用者。

mtools所包含的一些常用组件如下:

  • mlaunch支持快速搭建本地测试环境,可以是单机、副本集、分片集群。
  • mlogfilter日志过滤组件,支持按时间检索慢查询、全表扫描操作,支持通过多个属性进行信息过滤,支持输出为JSON格式。
  • mplotqueries支持将日志分析结果转换为图表形式,依赖tkinter(Python图形模块)和matplotlib模块。
  • mlogvis支持将日志分析结果转换为一个独立的HTML页面,实现与mplotqueries同样的功能。
ToolsDescription
mlogfilter合并、分割日志文件,过滤慢查询,集合扫描,格式转换等
mloginfo统计日志内的数据库信息(启停、连接、集群状态等)
mplotqueries日志转化为图表形式
mlogvis日志转化为HTML页面,与mplotqueries类似
mlaunch快速搭建本地测试环境(单机、集群、分片)

blog.rueckstiess.com/mtools/

2-2-2、安装mtools

2-2-2-1、环境准备

  • mtools需要调用MongoDB的二进制程序来启动数据库,因此需保证Path路径中包含{MONGODB_HOME}/bin这个目录
  • 需要安装Python环境,需选用Python 3.7、3.8、3.9版本。
  • python3.9安装

1.安装编译相关工具

yum -y groupinstall "Development tools"
yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel
yum install libffi-devel -y   

2.下载安装包解压

wget https://www.python.org/ftp/python/3.9.8/Python-3.9.8.tgz
tar -xvJf  Python-3.9.8.tar.xz    

3.编译安装

mkdir /usr/local/python3 #创建编译安装目录
cd Python-3.9.8
./configure --prefix=/usr/python3
make && make install      

4.创建软连接

ln -s /usr/local/python3/bin/python3 /usr/bin/python3
ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3   

5.验证是否成功

python3 -V 
pip3 -V

image.png

2-2-2-2、pip安装

安装依赖

pip3 install python-dateutil 
pip3 install psutil pymongo

image.png 安装mtools

pip3 install mtools

通过源码安装

github.com/rueckstiess…

wget https://github.com/rueckstiess/mtools/archive/refs/tags/v1.6.4.tar.gz 
#解压后进入mtools 
python setup.py install

2-2-3、使用mtools创建复制集

#准备复制集使用的工作目录
mkdir -p /data/mongo
cd /data/mongo
#初始化3节点复制集
mlaunch init --replicaset --nodes 3  

端口默认从27017开始,依次为2017,27018,27019

image.png

查看复制集状态

mongo --port 27017 
replset:PRIMARY> rs.status()

2-2-4、使用mtools创建分片集群

#准备分片集群使用的工作目录
mkdir /data/mongo-cluster
cd /data/mongo-cluster/
# 执行mlaunch init初始化集群
mlaunch init --sharded 2 --replicaset --node 3 --config 3 --csrs --mongos 3 --port 27050  

选项说明

  • --sharded 2:启用分片集群模式,分片数为2。
  • --replicaset --nodes 3:采用3节点的复制集架构,即每个分片为一致的复制集模式。
  • --config 3 --csrs:配置服务器采用3节点的复制集架构模式,--csrs是指Config Server as a Replica Set
  • --mongos 3:启动3个mongos实例进程。
  • --port 27050:集群将以27050作为起始端口,集群中的各个实例基于该端口向上递增。
  • --noauth:不启用鉴权。
  • --arbiter 向复制集中添加一个额外的仲裁器
  • --single 创建单个独立节点
  • --dir 数据目录,默认是./data
  • --binarypath 如果环境有二进制文件,则不用指定

如果执行成功,那么片刻后可以看到如下输出:

image.png

2-2-5、检查分片实例

mlaunch list命令可以对当前集群的实例状态进行检查

image.png

此时可以看到各个实例的运行状态,包括进程号以及监听的端口等。

# 显示标签
mlaunch  list --tags
# 显示启动命令
mlaunch  list --startup   

2-2-6、连接mongos,查看分片实例的情况

mongo --port 27050 
mongos> db.adminCommand({listShards:1})

image.png

2-2-7、停止、启动

如果希望停止集群,则可以使用mlaunch stop命令

image.png 再次启动集群,可以使用mlaunch start命令

image.png 使用mtools搭建测试集群是相当方便的,相比手工搭建的方式可缩减大量的时间。

三、使用分片集群

为了使集合支持分片,需要先开启database的分片功能

sh.enableSharding("shop")

执行shardCollection命令,对集合执行分片初始化

sh.shardCollection("shop.product",{productId:"hashed"},false,{numInitialChunks:4})

shop.product集合将productId作为分片键,并采用了哈希分片策略,除此以外,“numInitialChunks:4”表示将初始化4个chunk。 numInitialChunks必须和哈希分片策略配合使用。而且,这个选项只能用于空的集合,如果已经存在数据则会返回错误。

3-1、向分片集合写入数据

向shop.product集合写入一批数据

db=db.getSiblingDB("shop");
var count=0;
for(var i=0;i<1000;i++){
    var p=[];
    for(var j=0;j<100;j++){
        p.push({
            "productId":"P-"+i+"-"+j,
            name:"羊毛衫",
            tags:[
                {tagKey:"size",tagValue:["L","XL","XXL"]},
                {tagKey:"color",tagValue:["蓝色","杏色"]},
                {tagKey:"style",tagValue:"韩风"}
            ]
        });
    }
    count+=p.length;
    db.product.insertMany(p);
    print("insert ",count)
}  

3-2、查询数据的分布

db.product.getShardDistribution()

image.png