Mongodb分片集群

介绍

副本集帮助我们解决读请求扩展、高可用等问题。随着业务场景进一 步增长,可能会出现以下问题:

  • 存储容量超出单机磁盘容量

  • 活跃数据集超出单机内存容量:很多读请求需要从磁盘读取

  • 写入量超出单机 IOPS 上限

解决此问题,有两个途径: 1.扩展服务器硬件性能,比如增加磁盘和内存。 2.增加服务器数量。 从成本和便捷性上考虑,肯定是第2个更加合适。 而Mongodb分片技术就是基于第2个途径来解决以上问题的。

MongoDB 分片集群(Sharded Cluster)是对数据进行水平扩展的一种方式,分片集群用来支持大数据集和高吞吐量的业务场景。 本质上,Mongodb的分片技术就是将数据按预定的算法均匀地分布到不同的节点上,类似于磁盘的raid5。只不过它的每个节点都是一组一组的副本集。

架构

分片集群由3个组件组成: ../../_images/13.png 1.路由mongos

数据库集群请求的入口,所有的请求都通过mongos进行协调,不需要在应用程序添加一个路由选择器,mongos自己就是一个请求分发中心,它负责把对应的数据请求请求转发到对应的shard服务器上。在生产环境通常有多mongos作为请求的入口,防止其中一个挂掉所有的mongodb请求都没有办法操作。

2.配置服务器configserver

存储所有数据库元信息(路由、分片)的配置。 mongos本身没有物理存储分片服务器和数据路由信息,只是缓存在内存里,配置服务器则实际存储这些数据。 mongos第一次启动或者关掉重启就会从config server加载配置信息,以后如果配置服务器信息变化会通知到所有的mongos更新自己的状态,这样mongos就能继续准确路由。 在生产环境通常有多个 config server 配置服务器,因为它存储了分片路由的元数据,防止数据丢失!

3.分片shard

存储用户数据,不同shard保存不同用户数据

存储了一个集合部分数据的MongoDB实例,每个分片是单独的mongodb服务或者副本集,在生产环境中,所有的分片都应该是副本集

搭建

../../_images/14.png

1.机器规划 | 节点名称 | 主机名 | IP地址 | 角色 | | :—- | :—- | :—- | :—- | | 节点1 | centos8 | 192.168.195.105 | mongos、config server、shard1主节点、shard2从节点、shard3从节点 | | 节点2 | centos8-1 | 192.168.195.106 | mongos、 config server、shard1从节点、shard2从节点、shard3主节点 | | 节点3 | centos8-2 | 192.168.195.107 | mongos、 config server、shard1从节点、shard2主节点、shard3从节点 |

2.端口划分 | 角色 | 端口 | | :—- | :—- | | mongos | 20000 | | config server | 21000 | | shard1 | 27001 | | shard2 | 27002 | | shard3 | 27003 |

3.准备工作 三个节点分别执行

# 修改各自的主机名
sudo hostnamectl set-hostname centos8
sudo hostnamectl set-hostname centos8-1
sudo hostnamectl set-hostname centos8-2

# 修改hosts文件,每台加入以下全部内容
cat >> /etc/hosts <<EOF
192.168.195.105   centos8
192.168.195.106   centos8-1
192.168.195.107   centos8-2
EOF

# 关闭防火墙和selinux
sudo systemctl stop firewalld
sudo systemctl disable firewalld
sudo sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
sudo setenforce 0

4.删除之前做实验的历史数据(三个节点都操作)

systemctl stop mongodb
rm -rf /data/mongodb/*

5.节点上创建目录(三个节点上都操作)

mkdir -p /data/mongodb/{mongos,config,shard1,shard2,shard3}
chown -R mongodb /data/mongodb/

config server配置

6.config server配置 在节点1上编辑配置文件

vi /usr/local/mongodb/conf/config.conf   ## 内容如下
systemLog:
  #MongoDB发送所有日志输出的目标指定为文件
  destination: file
  #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/logs/configsvr.log"
  #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾
  logAppend: true
storage:
  #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod
  dbPath: "/data/mongodb/config"
  journal:
    #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  #启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/logs/configsvr.pid"
  #从中加载时区数据库的完整路径
  timeZoneInfo: /usr/share/zoneinfo
net:
  #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  #服务实例绑定的IP,0.0.0.0让所有机器都能连接。
  bindIp: 0.0.0.0
  #bindIp
  #绑定的端口
  port: 21000
# 安全配置
#security:
  # 配置密码文件
  #keyFile: /usr/local/mongodb/conf/keyfile
replication:
  #副本集的名称
  replSetName: "config"
sharding:
  clusterRole: configsvr

然后将节点1上的配置文件拷贝到节点2和节点3

scp /usr/local/mongodb/conf/config.conf centos8-1:/usr/local/mongodb/conf/config.conf
scp /usr/local/mongodb/conf/config.conf centos8-2:/usr/local/mongodb/conf/config.conf

编辑systemd服务脚本(三节点一样)

vi /lib/systemd/system/configsvr.service  ##内容如下
[Unit]
Description=mongodb
After=network.target remote-fs.target nss-lookup.target

[Service]
User=mongodb
Type=forking
ExecStart=/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/conf/config.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

三个节点上,启动服务

systemctl daemon-reload
systemctl start configsvr.service

登录节点1

mongosh  centos:21000  ##登录后执行如下命令,复制粘贴即可
rs.initiate(
   {
      _id: "config",
      version: 1,
      members: [
         { _id: 0, host : "centos8:21000" },
         { _id: 1, host : "centos8-1:21000"},
         { _id: 2, host : "centos8-2:21000" }
      ]
   }
)

配置shard

shard1/shard2/shard3配置,以下操作为shard1,shard2和shard3,分别将关键字shard1改为shard2和shard3即可,另外端口27001按前面的规划也替换为27002和27003 在节点1上编辑配置文件

vi /usr/local/mongodb/conf/shard1.conf   ## 内容如下

systemLog:
  #MongoDB发送所有日志输出的目标指定为文件
  destination: file
  #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/logs/shard1.log"
  #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾
  logAppend: true
storage:
  #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod
  dbPath: "/data/mongodb/shard1"
  journal:
    #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  #启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/logs/shard1.pid"
  #从中加载时区数据库的完整路径
  timeZoneInfo: /usr/share/zoneinfo
net:
  #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  #服务实例绑定的IP,0.0.0.0让所有机器都能连接。
  bindIp: 0.0.0.0
  #bindIp
  #绑定的端口
  port: 27001
# 安全配置
#security:
  # 配置密码文件
  #keyFile: /usr/local/mongodb/conf/keyfile
replication:
  #副本集的名称
  replSetName: "shard1"
sharding:
  clusterRole: shardsvr

然后将节点1上的配置文件拷贝到节点2和节点3

scp /usr/local/mongodb/conf/shard1.conf centos8-1:/usr/local/mongodb/conf/shard1.conf
scp /usr/local/mongodb/conf/shard1.conf centos8-2:/usr/local/mongodb/conf/shard1.conf

编辑systemd服务脚本(三节点一样) vi /lib/systemd/system/shard1.service ##内容如下

[Unit]
Description=mongodb
After=network.target remote-fs.target nss-lookup.target

[Service]
User=mongodb
Type=forking
ExecStart=/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/conf/shard1.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

三个节点上,启动服务

systemctl daemon-reload
systemctl start shard1.service

登录节点1

mongosh  centos:27001

rs.initiate(
   {
      _id: "shard1",
      version: 1,
      members: [
         { _id: 0, host : "centos8:27001", priority:3 },
         { _id: 1, host : "centos8-1:27001", priority:2},
         { _id: 2, host : "centos8-2:27001", priority:1}
      ]
   }
)

shard2的配置,到节点3上执行

rs.initiate(
   {
      _id: "shard2",
      version: 1,
      members: [
         { _id: 0, host : "centos8-2:27002", priority:3 },
         { _id: 1, host : "centos8:27002", priority:2},
         { _id: 2, host : "centos8-1:27002", priority:1}
      ]
   }
)

shard3的配置,到节点2上执行

rs.initiate(
   {
      _id: "shard3",
      version: 1,
      members: [
         { _id: 0, host : "centos8-1:27003", priority:3 },
         { _id: 1, host : "centos8-2:27003", priority:2},
         { _id: 2, host : "centos8:27003", priority:1}
      ]
   }
)

配置路由

在节点1上编辑配置文件

vi /usr/local/mongodb/conf/mongos.conf   ## 内容如下

systemLog:
  #MongoDB发送所有日志输出的目标指定为文件
  destination: file
  #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/logs/mongos.log"
  #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾
  logAppend: true
processManagement:
  #启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/logs/mongos.pid"
  #从中加载时区数据库的完整路径
  timeZoneInfo: /usr/share/zoneinfo
net:
  #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  #服务实例绑定的IP,0.0.0.0让所有机器都能连接。
  bindIp: 0.0.0.0
  #bindIp
  #绑定的端口
  port: 20000
# 安全配置
#security:
  # 配置密码文件
  #keyFile: /usr/local/mongodb/conf/keyfile
sharding:
  configDB: config/centos8:21000,centos8-1:21000,centos8-2:21000

然后将节点1上的配置文件拷贝到节点2和节点3

scp /usr/local/mongodb/conf/mongos.conf centos8-1:/usr/local/mongodb/conf/mongos.conf
scp /usr/local/mongodb/conf/mongos.conf centos8-2:/usr/local/mongodb/conf/mongos.conf

编辑systemd服务脚本(三节点一样)

vi /lib/systemd/system/mongos.service  ##内容如下

[Unit]
Description=mongos
After=network.target remote-fs.target nss-lookup.target

[Service]
User=mongodb
Type=forking
ExecStart=/usr/local/mongodb/bin/mongos --config /usr/local/mongodb/conf/mongos.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

三个节点上,启动服务

systemctl daemon-reload
systemctl start mongos.service

启用分片

mongosh centos:20000

sh.addShard("shard1/centos8:27001,centos8-1:27001,centos8-2:27001")
sh.addShard("shard2/centos8:27002,centos8-1:27002,centos8-2:27002")
sh.addShard("shard3/centos8:27003,centos8-1:27003,centos8-2:27003")

查看状态

sh.status()

开启认证

创建root用户

use admin
db.createUser({user:"root",pwd:"aminglinux.com",roles:["root"]})

创建keyfile,在节点1上操作

openssl rand -base64 20 > /usr/local/mongodb/conf/keyfile
chmod 400 /usr/local/mongodb/conf/keyfile
chown mongodb /usr/local/mongodb/conf/keyfile

将keyfile拷贝到另外两台机器

scp /usr/local/mongodb/conf/keyfile  centos8-1:/usr/local/mongodb/conf/keyfile
scp /usr/local/mongodb/conf/keyfile  centos8-2:/usr/local/mongodb/conf/keyfile

节点2和节点3上,更改keyfile权限

chmod 400 /usr/local/mongodb/conf/keyfile
chown mongodb /usr/local/mongodb/conf/keyfile

编辑配置文件(全部三个节点,操作一样)

cd /usr/local/mongodb/conf
##将所有配置security那部分配置前面的#删除掉
sed -i -e 's/#security/security/' -e 's/#keyFile/keyFile/' *.conf

重启所有服务(全部三个节点,操作一样)

for s in configsvr shard1 shard2 shard3 mongos ; do systemctl restart $s; done

测试

use admin
db.auth("root","aminglinux.com")

use testdb
sh.enableSharding("testdb")   ##指定要分片的数据库
sh.shardCollection("testdb.table1", {id: "hashed"} )   ##指定数据库里需要分片的集合和片键
for (var i = 1; i <= 10000; i++) db.table1.insert({id:i*123,uid:i})  ##插入测试数据
db.table1.stats()  ##查看table1状态