一、Sharding分片技术

  1、分片概述

  当数据量比较大的时候,我们需要把数分片运行在不同的机器中,以降低CPU、内存和Io的压力,Sharding就是数据库分片技术。

  MongoDB分片技术类似MySQL的水平切分和垂直切分,数据库主要由俩种方式做Sharding:垂直扩展和横向切分。

  垂直扩展的方式就是进行集群扩展,添加更多的CPU,内存,磁盘空间等。

  横向切分则是通过数据分片的方式,通过集群统一提供服务:

mongodb分片性能优化 mongodb分片策略_mongodb分片性能优化

 

 

 二、MongoDB分片架构原理

  (1)MongoDB的Sharding架构

  

mongodb分片性能优化 mongodb分片策略_副本集_02

 其中,Router负责接受访问,然后去config服务器中查询元数据,将数据存储信息返回给Router,Router服务器根据元数据的存储信息在分片服务器上读取或者写入数据。

 (2)MongoDB分片架构中的角色

 a、数据分片(Shards)

 用来保存数据,保证数据的高可用性和一致性。可以是一个单独的mongod实例,也可以是一个副本集。在生产环境下Shard一般是一个Replica Set,以防止该数据片的单点故障。所有Shard中有一个PrimaryShard,里面包含未进行划分的数据集合:

mongodb分片性能优化 mongodb分片策略_服务器_03

 

 

 b、查询路由(Query Routers)

   路由就是mongos的实例,客户端直接连接mongos,由mongos把读写请求路由到指定的Shard上去。

  一个Sharding集群,可以有一个mongos,也可以有多个mongos以减轻客户端请求的压力。

c、配置服务器(Config servers)

 保存集群的元数据(metadata),包含各个Shard的路由规则。

Sharding分片技术(混合模式)高可用方案的架构图如下:

mongodb分片性能优化 mongodb分片策略_服务器_04

 

 

    1)Sharding分片技术(混合模式)高可用架构下MongoDB数据写入流程

mongodb分片性能优化 mongodb分片策略_mongodb分片性能优化_05

 

 

  第一步:客户端访问路由服务器(Mongos),路由服务器接收到请求。

  第二步:路由服务器将客户端访问配置服务器,配置服务器(Config)根据根据请求信息将数据信息写入到元数据中。

  第三步:配置服务器将根据自身记录的元数据信息,指定数据存储位置,并将元数据信息(数据存储位置)返回给路由服务器。

  第四步:路由服务器根据Config服务器返回的配置信息,将数据存储到mongod中(数据存储服务器)。存储服务器对数据进行备份和分片存储。

 2)高可用集群下从MongoDB读取数据流程

mongodb分片性能优化 mongodb分片策略_mongodb分片性能优化_06

 

 

   第一步:Mongos接受客户端请求,根据并判断请求是否合理(数据库地址是否正确,连接数是否超过最大)

  第二步:路由服务器与客户端建立连接,并根据请求信息,去Config服务器中查询元数据信息。

 第三步:config服务器将数信息返回给路由服务器。

 第四步: config服务器根据元数据信息(数据存储位置),去MongoD服务器中,查询数据。

 第五步:数据服务器将数据查询结果返回给路由服务器。

三、Sharding分片高可用方案搭建过程

1、MongoDB机器信息

192.168.86.131

192.168.86.132

192.168.86.133

mongos

mongos

mongos

config server

config server

config server

shard server1 主节点

shard server1 副节点

shard server1 仲裁

shard server2 仲裁

shard server2 主节点

shard server2 副节点

shard server3 副节点

shard server3 仲裁

shard server3 主节点

 2、端口分配

mongos:20000
config:21000
shard1:27001
shard2:27002
shard3:27003

3、下载并且安装

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-amazon-4.0.9.tgz
tar -xzvf mongodb-linux-x86_64-amazon-4.0.9.tgz  -C /usr/local/

4、建立软连接并配置path信息

cd /usr/local/
ln -s  /usr/local/mongodb-linux-x86_64-amazon-3.6.2 /usr/local/mongodb

 进入到/etc/profile中配置MongoDB的全局变量信息

vi /etc/profile
# MongoDB 环境变量内容
export MONGODB_HOME=/usr/local/mongodb
export PATH=$MONGODB_HOME/bin:$PATH

 生效环境变量

 source  /etc/profile

5、为服务器建立日志和数据目录

分别在每台机器建立conf、mongos、config、shard1、shard2、shard3六个目录,因为mongos不存储数据,只需要建立日志文件目录即可。

mkdir -p /usr/local/mongodb/conf \
mkdir -p /usr/local/mongodb/mongos/log \
mkdir -p /usr/local/mongodb/config/data \
mkdir -p /usr/local/mongodb/config/log \
mkdir -p /usr/local/mongodb/shard1/data \
mkdir -p /usr/local/mongodb/shard1/log \
mkdir -p /usr/local/mongodb/shard2/data \
mkdir -p /usr/local/mongodb/shard2/log \
mkdir -p /usr/local/mongodb/shard3/data \

6、config server配置服务器

mongodb3.4版本以后要求配置服务器也创建副本集,不然集群搭建不成功。
(三台机器)添加配置文件

vi /usr/local/mongodb/conf/config.conf

## 配置文件内容
pidfilepath = /usr/local/mongodb/config/log/configsrv.pid
dbpath = /usr/local/mongodb/config/data
logpath = /usr/local/mongodb/config/log/congigsrv.log
logappend = true
 
bind_ip = 0.0.0.0
port = 21000
fork = true
 
#declare this is a config db of a cluster;
configsvr = true

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

启动三台服务器的config server

mongod -f /usr/local/mongodb/conf/config.conf

登录任意一台配置服务器,初始化配置副本集
连接 MongoDB

mongo --port 21000

配置config变量

config = {
    _id : "configs",
    members : [
    {_id : 0, host : "192.168.86.131:21000" },
    {_id : 1, host : "192.168.86.132:21000" },
    {_id : 2, host : "192.168.86.133:21000" }
    ]
}

  初始化副本集

rs.initiate(config)

 

  其中,"_id" : "configs"应与配置文件中配置的 replicaction.replSetName 一致,"members" 中的 "host" 为三个节点的 ip 和 port
响应内容如下

> config = {
... _id : "configs",
... members : [
... {_id : 0, host : "192.168.86.131:21000" },
... {_id : 1, host : "192.168.86.132:21000" },
... {_id : 2, host : "192.168.86.133:21000" }
... ]
... }
{
    "_id" : "configs",
    "members" : [
        {
            "_id" : 0,
            "host" : "192.168.86.131:21000"
        },
        {
            "_id" : 1,
            "host" : "192.168.86.132:21000"
        },
        {
            "_id" : 2,
            "host" : "192.168.86.133:21000"
        }
    ]
}
> rs.initiate(config);
{
    "ok" : 1,
    "operationTime" : Timestamp(1517369899, 1),
    "$gleStats" : {
        "lastOpTime" : Timestamp(1517369899, 1),
        "electionId" : ObjectId("000000000000000000000000")
    },
    "$clusterTime" : {
        "clusterTime" : Timestamp(1517369899, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}
configs:SECONDARY>

此时会发现终端上的输出已经有了变化。

//从单个一个
>
//变成了
configs:SECONDARY>

 查询状态

configs:SECONDARY> rs.status()

7、配置分片服务器

  7.1设置第一个分片服务器

(三台机器)设置第一个分片副本集
配置文件

vi /usr/local/mongodb/conf/shard1.conf

#配置文件内容
#——————————————–
pidfilepath = /usr/local/mongodb/shard1/log/shard1.pid
dbpath = /usr/local/mongodb/shard1/data
logpath = /usr/local/mongodb/shard1/log/shard1.log
logappend = true

bind_ip = 0.0.0.0
port = 27001
fork = true
 
#副本集名称
replSet = shard1
 
#declare this is a shard db of a cluster;
shardsvr = true
 
#设置最大连接数
maxConns = 20000

 启动三台服务器的shard1 server 

mongod -f /usr/local/mongodb/conf/shard1.conf

登陆任意一台服务器,初始化副本集(除了192.168.86.133),因为仲裁服务器没有访问权限,负责会初始化失败。
连接 MongoDB

 mongo --port 27001

使用admin数据库

admin

定义副本集配置

config = {
    _id : "shard1",
     members : [
         {_id : 0, host : "192.168.86.131:27001" },
         {_id : 1, host : "192.168.86.132:27001" },
         {_id : 2, host : "192.168.86.133:27001" , arbiterOnly: true }
     ]
 }

 初始化副本集配置

rs.initiate(config)

响应内容如下
> use admin
switched to db admin
> config = {
...     _id : "shard1",
...      members : [
...          {_id : 0, host : "192.168.86.131:27001" },
...          {_id : 1, host : "192.168.86.132:27001" },
...          {_id : 2, host : "192.168.86.133:27001" , arbiterOnly: true }
...      ]
...  }
{
    "_id" : "shard1",
    "members" : [
        {
            "_id" : 0,
            "host" : "192.168.86.131:27001"
        },
        {
            "_id" : 1,
            "host" : "192.168.86.132:27001"
        },
        {
            "_id" : 2,
            "host" : "192.168.86.133:27001",
            "arbiterOnly" : true
        }
    ]
}
> rs.initiate(config)
{ "ok" : 1 }

 此时会发现终端上的输出已经有了变化。

//从单个一个
>
//变成了
shard1:SECONDARY>

查询状态

shard1:SECONDARY> rs.status()

7.2设置第二和第三个分片服务器 

第二、第三个服务器配置过程同上,只需将配置文件中的服务器名称改为shard2、shard3,将端口改为27002,27003即可,仲裁服务器分别选择第二个和第三个。

8、配置路由服务器 mongos

 8.1 配置并初始化

(三台机器)先启动配置服务器和分片服务器,后启动路由实例启动路由实例:

vi /usr/local/mongodb/conf/mongos.conf

#内容
pidfilepath = /usr/local/mongodb/mongos/log/mongos.pid
logpath = /usr/local/mongodb/mongos/log/mongos.log
logappend = true

bind_ip = 0.0.0.0
port = 20000
fork = true

#监听的配置服务器,只能有1个或者3个 configs为配置服务器的副本集名字
configdb = configs/192.168.86.131:21000,192.168.86.132:21000,192.168.86.133:21000
 
#设置最大连接数
maxConns = 20000

 启动三台服务器的mongos server

mongos -f /usr/local/mongodb/conf/mongos.conf

8.2 串联路由服务器

目前搭建了mongodb配置服务器、路由服务器,各个分片服务器,不过应用程序连接到mongos路由服务器并不能使用分片机制,还需要在程序里设置分片配置,让分片生效。
登陆任意一台mongos

mongo --port 20000

使用admin数据库
use  admin

串联路由服务器与分配副本集

sh.addShard("shard1/192.168.86.131:27001,192.168.86.132:27001,192.168.86.123:27001");
sh.addShard("shard2/192.168.86.131:27002,192.168.86.132:27002,192.168.86.133:27002");
sh.addShard("shard3/192.168.86.131:27003,192.168.86.132:27003,192.168.86.133:27003");

查看集群状态

sh.status()

响应内容如下

mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("5a713a37d56e076f3eb47acf")
  }
  shards:
        {  "_id" : "shard1",  "host" : "shard1/192.168.86.131:27001,192.168.86.132:27001",  "state" : 1 }
        {  "_id" : "shard2",  "host" : "shard2/192.168.86.132:27002,192.168.86.133:27002",  "state" : 1 }
        {  "_id" : "shard3",  "host" : "shard3/192.168.86.131:27003,192.168.86.133:27003",  "state" : 1 }
  active mongoses:
        "4.0.9" : 3
  autosplit:
        Currently enabled: yes
  balancer:
        Currently enabled:  yes
        Currently running:  no
        Failed balancer rounds in last 5 attempts:  0
        Migration Results for the last 24 hours: 
                No recent migrations
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }

mongos>

四、启用集合分片

  目前配置服务、路由服务、分片服务、副本集服务都已经串联起来了,但我们的目的是希望插入数据,数据能够自动分片。连接在mongos上,准备让指定的数据库、指定的集合分片生效。
登陆任意一台mongos

mongo --port 20000

使用admin数据库

use  admin

指定testdb分片生效,如下图:

db.runCommand( { enablesharding :"testdb"});

或

mongos> sh.enablesharding("testdb")

指定数据库里需要分片的集合和片键,哈希id分片(注意:分片的字段数据应该是变化的,不然分片不成功),如下图: 

db.runCommand( { shardCollection : "testdb.table1",key : {"name": "hashed"} } );

或

mongos> sh.shardCollection("testdb.table1", {"name": "hashed"})

通过命令查看mongodb路由服务器上的shards集合会有数据展示,如下图:

mongodb分片性能优化 mongodb分片策略_mongodb分片性能优化_07

通过命令查看mongodb路由服务器上的chunks集合会有数据展示,如下图

mongodb分片性能优化 mongodb分片策略_服务器_08

我们设置testdb的 table3 表需要分片,根据 id 或name自动分片到 shard1 ,shard2,shard3 上面去。要这样设置是因为不是所有mongodb 的数据库和表 都需要分片!
测试分片配置结果
切换到 testdb 数据库

use  testdb;
for(i=1;i<=100000;i++){db.table3.insert({"id":i,"name":"penglei"})};

总条数 

db.table1.aggregate([{$group : {_id : "$name", totle : {$sum : 1}}}])

查看分片情况如下

mongodb分片性能优化 mongodb分片策略_mongodb分片性能优化_09

 

mongodb分片性能优化 mongodb分片策略_服务器_10

 

mongodb分片性能优化 mongodb分片策略_服务器_11

  结论数据基本均匀

分组查看总数量是:100000

mongodb分片性能优化 mongodb分片策略_副本集_12