前言

我们知道 MongoDB 复制集架构只有主节点能读写,从节点只能读。如果主节点写入的压力较大,那么还是会有性能瓶颈。在Mongodb里面存在另一种集群,就是分片技术,可以满足 MongoDB 数据量大量增长的需求。当 MongoDB 存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量。

这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。

下图展示是MongoDB的分片集群架构:

Monolithich架构 mongo架构_复制集

上图中主要有如下所述三个主要组件:

  • Shard: 用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组一个replica set承担,防止主机单点故障
  • Config Server: mongod实例,存储了整个 ClusterMetadata,其中包括 chunk信息。
  • Query Routers: 前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。

Question 1:Query Routers的工作流程:

当 Query Routers 接收到客户端的指令后,Query Routers 会先到 Config Server 读取相应的配置,然后根据配置再到相应的 Shard 中去操作相应的数据。

Question 2:为什么需要 Config Server

在实际生产中,配置文件使用是比较多的,不同的项目需要有不同的配置文件。随着业务的增长,分散的配置文件文件不便于管理,所以配置文件统一管理组件就出现了。简而言之:Config-Server 就是用来实现配置统一管理和不同环境间配置的统一切换的。

分片集群配置

规划:

10个 MongoDB 实例:38017~38026

(1)configserver:

3台实例构成的复制集(实例38018~38020,1主两从,不支持arbiter)作为 configserver ,复制集名称为:configsvr

(2)shard节点:

sh1:由实例 38021~38024 构成的复制集作为第一个 shard 节点   (1主两从,其中一个节点为arbiter,复制集名字sh1)

sh2:由实例 38024~38026 构成的复制集作为第二个 shard 节点   (1主两从,其中一个节点为arbiter,复制集名字sh2)

1、前期准备

操作系统准备
   (1)redhat或cnetos6.2以上系统
   (2)系统开发包完整
   (3)ip地址和hosts文件解析正常
   (4)iptables防火墙&SElinux关闭
   (5)关闭大页内存机制
###################################################################################################
i、关闭大页内存机制:
   root用户下,在 /etc/rc.local 文件最后添加如下代码
   if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
     echo never > /sys/kernel/mm/transparent_hugepage/enabled
   fi
   if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
     echo never > /sys/kernel/mm/transparent_hugepage/defrag
   fi
		
   echo never > /sys/kernel/mm/transparent_hugepage/enabled		
   echo never > /sys/kernel/mm/transparent_hugepage/defrag

   其它系统关闭大页内存参照官方文档:https://docs.mongodb.com/manual/tutorial/transparent-huge-pages/
#####################################################################################################

为甚要关闭大页内存机制,官方给出的解释:(若是不关闭,启动mongodb时就会报错)
###################################################################################################
   Transparent Huge Pages (THP) is a Linux memory management system 
   that reduces the overhead of Translation Lookaside Buffer (TLB) 
   lookups on machines with large amounts of memory by using larger memory pages.
   However, database workloads often perform poorly with THP, 
   because they tend to have sparse rather than contiguous memory access patterns. 
   You should disable THP on Linux machines to ensure best performance with MongoDB.
###################################################################################################

ii、修改Linux资源限制配置文件 /etc/security/limits.conf
     ...
  mongod  soft  nofile  65535          #mongod用户可以打开的最大文件描述符数量,这里的数值会限制tcp连接
  mongod  soft  nproc   32767          #mongod用户在拥有32767个进程时会发出警告

在启动mongodb时,若是没有修改 /etc/security/limits.conf,就会出现相应的警告
关于 /etc/security/limits.conf 文件配置可参考此篇文章:https://www.jianshu.com/p/47336fcd22da

2、MongoDB的安装

i、下载mongodb安装包

   下载地址:https://www.mongodb.com/download-center/community/releases/archive
   可根据自己Linux的版本下载相应版本的mongodb安装包

ii、安装包下载成功后,上传到Linux系统中,并解压
  
   [root@db01 ~] # tar xf mongodb-linux-x86_64-rhel70-3.2.16.tgz

iii、创建所需用户和组,并创建mongodb目录
 
   [root@db01 ~] # useradd mongod       #创建mongod用户,用户管理mongodb数据库
   [root@db01 ~] # echo 111111 | passwd --stdin mongod    
   [root@db01 ~] # mkdir /mongodb       #创建mongodb目录,把所有和mongodb数据库相关的数据都存放在此目录下,方便管理
   [root@db01 ~] # cp -a /mongodb-linux-x86_64-rhel70-3.2.16/bin/* /mongodb/bin    #将mongodb安装包的 bin目录拷贝到/mongodb 目录下
   [root@db01 ~] # chown -R mongod:mongod /mongodb  #设置目录结构权限
   

iv、设置用户环境变量
  
   [root@db01 ~] # su - mongod         #切换到mongod用户下
   [mongod@db01 ~] # vim .bash_profile           #注意:这里修改的是mongod用户下的profile文件,也就是说,关于新配置的mongodb中的命令,只有在mongod用户下才能使用。
             ...
      export PATH=/mongodb/bin:$PATH   
   
   [mongod@db01 ~] # source .bash_profile      #让 .bash_profile中的配置立即生效

3、shard复制集配置

i、目录创建
  [mongod@db01 ~] # mkdir -p /mongodb/38021/conf  /mongodb/38021/log  /mongodb/38021/data
  [mongod@db01 ~] # mkdir -p /mongodb/38022/conf  /mongodb/38022/log  /mongodb/38022/data
  [mongod@db01 ~] # mkdir -p /mongodb/38023/conf  /mongodb/38023/log  /mongodb/38023/data
  [mongod@db01 ~] # mkdir -p /mongodb/38024/conf  /mongodb/38024/log  /mongodb/38024/data
  [mongod@db01 ~] # mkdir -p /mongodb/38025/conf  /mongodb/38025/log  /mongodb/38025/data
  [mongod@db01 ~] # mkdir -p /mongodb/38026/conf  /mongodb/38026/log  /mongodb/38026/data

tip:注意是在mongod用户下创建的这些目录。若是在root用户下创建,就需要修改这些目录的属主属组为mongod,若是不修改,则mongod用户无法操作这些目录

ii、编辑配置文件
 sh1:
 [mongod@db01 ~] # cat > /mongodb/38021/conf/mongodb.conf<<EOF 
  systemLog:
    destination: file
    path: /mongodb/38021/log/mongodb.log   
    logAppend: true
  storage:
    journal:
      enabled: true
    dbPath: /mongodb/38021/data
    directoryPerDB: true
    #engine: wiredTiger
    wiredTiger:
      engineConfig:
        cacheSizeGB: 1
        directoryForIndexes: true
      collectionConfig:
        blockCompressor: zlib
      indexConfig:
        prefixCompression: true
  net:
    bindIp: 10.0.0.51,127.0.0.1
    port: 38021
  replication:
    oplogSizeMB: 2048
    replSetName: sh1   复制集名称(自定义)
  sharding:         表名是分片相关的配置
    clusterRole: shardsvr      指定在集群中的角色    shardsvr:表明是的后端shard节点
  processManagement: 
    fork: true
  EOF
  [mongod@db01 ~] # cp  /mongodb/38021/conf/mongodb.conf  /mongodb/38022/conf/
  [mongod@db01 ~] # cp  /mongodb/38021/conf/mongodb.conf  /mongodb/38023/conf/
  [mongod@db01 ~] # sed -i 's#38021#38022#g' /mongodb/38022/conf/mongodb.conf 
  [mongod@db01 ~] # sed -i 's#38021#38023#g' /mongodb/38023/conf/mongodb.conf 


  sh2:
  [mongod@db01 ~] # cat > /mongodb/38024/conf/mongodb.conf<<EOF 
  systemLog:
    destination: file
    path: /mongodb/38024/log/mongodb.log   
    logAppend: true
  storage:
    journal:
      enabled: true
    dbPath: /mongodb/38024/data
    directoryPerDB: true
    wiredTiger:
      engineConfig:
        cacheSizeGB: 1
        directoryForIndexes: true
      collectionConfig:
        blockCompressor: zlib
      indexConfig:
        prefixCompression: true
  net:
    bindIp: 10.0.0.51,127.0.0.1
    port: 38024
  replication:
    oplogSizeMB: 2048
    replSetName: sh2
  sharding:
    clusterRole: shardsvr
  processManagement: 
    fork: true
  EOF
  [mongod@db01 ~] # cp  /mongodb/38024/conf/mongodb.conf  /mongodb/38025/conf/
  [mongod@db01 ~] # cp  /mongodb/38024/conf/mongodb.conf  /mongodb/38026/conf/
  [mongod@db01 ~] # sed -i 's#38024#38025#g' /mongodb/38025/conf/mongodb.conf 
  [mongod@db01 ~] # sed -i 's#38024#38026#g' /mongodb/38026/conf/mongodb.conf 


iii、启动所有节点,并搭建复制集
  [mongod@db01 ~] # mongod -f  /mongodb/38021/conf/mongodb.conf 
  [mongod@db01 ~] # mongod -f  /mongodb/38022/conf/mongodb.conf 
  [mongod@db01 ~] # mongod -f  /mongodb/38023/conf/mongodb.conf 
  [mongod@db01 ~] # mongod -f  /mongodb/38024/conf/mongodb.conf 
  [mongod@db01 ~] # mongod -f  /mongodb/38025/conf/mongodb.conf 
  [mongod@db01 ~] # mongod -f  /mongodb/38026/conf/mongodb.conf

  [mongod@db01 ~] # mongo --port 38021 admin       #登录mongodb中admin库,并指定端口号为38021的实例
            ...
   >config = {_id: 'sh1', members: [                            #配置名称为sh1的复制集
                          {_id: 0, host: '10.0.0.51:38021'},
                          {_id: 1, host: '10.0.0.51:38022'},
                          {_id: 2, host: '10.0.0.51:38023',"arbiterOnly":true}]
           }
   >rs.initiate(config)           #构建集群的命令

  [mongod@db01 ~] # mongo --port 38024 admin
            ...
  >config = {_id: 'sh2', members: [                             #配置名称为sh2的复制集
                          {_id: 0, host: '10.0.0.51:38024'},
                          {_id: 1, host: '10.0.0.51:38025'},
                          {_id: 2, host: '10.0.0.51:38026',"arbiterOnly":true}]
           }
  >rs.initiate(config)

 TIP:在复制集中,mongodb默认是不允许在从库中进行读和写的操作,若是想在从库中查看数据信息,需要在从库中执行"rs.slaveOK()"命令

4、config server节点的配置

i、目录创建
  [mongod@db01 ~] # mkdir -p /mongodb/38018/conf  /mongodb/38018/log  /mongodb/38018/data
  [mongod@db01 ~] # mkdir -p /mongodb/38019/conf  /mongodb/38019/log  /mongodb/38019/data
  [mongod@db01 ~] # mkdir -p /mongodb/38020/conf  /mongodb/38020/log  /mongodb/38020/data

ii、编辑配置文件
  [mongod@db01 ~] # cat > /mongodb/38018/conf/mongodb.conf <<EOF
  systemLog:
    destination: file
    path: /mongodb/38018/log/mongodb.conf
    logAppend: true
  storage:
    journal:
      enabled: true
    dbPath: /mongodb/38018/data
    directoryPerDB: true
    #engine: wiredTiger
    wiredTiger:
      engineConfig:
        cacheSizeGB: 1
        directoryForIndexes: true
      collectionConfig:
        blockCompressor: zlib
      indexConfig:
        prefixCompression: true
  net:
    bindIp: 10.0.0.51,127.0.0.1
    port: 38018
  replication:
    oplogSizeMB: 2048
    replSetName: configReplSet
  sharding:
    clusterRole: configsvr      configsvr:表明在集群中的角色是config server配置节点 
  processManagement: 
    fork: true
  EOF
  [mongod@db01 ~] # cp /mongodb/38018/conf/mongodb.conf /mongodb/38019/conf/
  [mongod@db01 ~] # cp /mongodb/38018/conf/mongodb.conf /mongodb/38020/conf/
  [mongod@db01 ~] # sed -i 's#38018#38019#g' /mongodb/38019/conf/mongodb.conf 
  [mongod@db01 ~] # sed -i 's#38018#38020#g' /mongodb/38020/conf/mongodb.conf 

iii、启动节点,并配置复制集

  [mongod@db01 ~] # mongod -f /mongodb/38018/conf/mongodb.conf 
  [mongod@db01 ~] # mongod -f /mongodb/38019/conf/mongodb.conf 
  [mongod@db01 ~] # mongod -f /mongodb/38020/conf/mongodb.conf

  [mongod@db01 ~] # mongo --port 38018 admin
           ...
  >config = {_id: 'configReplSet', members: [
                          {_id: 0, host: '10.0.0.51:38018'},
                          {_id: 1, host: '10.0.0.51:38019'},
                          {_id: 2, host: '10.0.0.51:38020'}]
           }
  >rs.initiate(config)
       ...
  >rs.status()                     #查看整体复制集状态
       ...
  >rs.isMaster()                   #查看当前是否是主节点
       ...
  >rs.conf()                       #查看复制集配置信息
       ...

TIP:config server 可以是一个节点,但是官方建议使用复制集。config server使用复制集时,复制集中不能有 arbiter 节点

mongodb 3.4版本之后,要求 config server 必须为复制集

5、mongos 节点配置

i、创建目录
  [mongod@db01 ~] # mkdir -p /mongodb/38017/conf  /mongodb/38017/log   #因为mongos节点不存储数据,故不需要创建 data 目录
  
ii、编辑配置文件
  [mongod@db01 ~] # cat >/mongodb/38017/conf/mongos.conf<<EOF
  systemLog:
    destination: file
    path: /mongodb/38017/log/mongos.log
    logAppend: true
  net:
    bindIp: 10.0.0.51,127.0.0.1
    port: 38017
  sharding:
    configDB: configReplSet/10.0.0.51:38018,10.0.0.51:38019,10.0.0.51:38020    #告诉mongos节点 config server的地址信息。将整个config server复制集都告诉mongos,这样即使config server复制集中有一台config server损坏,mongos可以自动连接复制集中的其它config server.
  processManagement: 
    fork: true
  EOF    

iii、启动mongos (注意启动mongos的命令,和启动mongod服务是不同的)
  [mongod@db01 ~] # mongos -f /mongodb/38017/conf/mongos.conf      #mongos的启动是否成功取决于config server复制集是否配置成功,若是config server复制集配置错误,那么mongos是无法启动的。

6、分片集群操作

连接到其中一个mongos(10.0.0.51),做以下配置    
此时集群中还不知道shard复制集的信息,所以要将shard集群的信息添加到集群中。

i、连接到mongs的admin数据库,并添加分片
  [mongod@db01 ~] # mongo --port 38017 admin
          ...
  mongos> db.runCommand( { addshard : "sh1/10.0.0.51:38021,10.0.0.51:38022,10.0.0.51:38023",name:"shard1"} )
          ...
  mongos> db.runCommand( { addshard : "sh2/10.0.0.51:38024,10.0.0.51:38025,10.0.0.51:38026",name:"shard2"} )
          ...
  mongos> db.runCommand( { listshards : 1 } )      #列出分片信息
          ...
  mongos> sh.status()                            #查看分片的整体状态

#shard复制集添加成功后,shard复制集的信息就会被保存在config server中。

ii、向shard集群中添加shard节点  (灵活扩容)
  [mongod@db01 ~] # mongo --port 38017 admin
  mongos> sh.help()             #查看sharding操作相关命令和用法
        ...
  mongos> sh.addShard( IP:port )        #如果是单个mongodb实例,直接加ip和端口号,如果是replset复制集,则要带上复制集名称 replset/ip:port,ip:port...
        ...
  mongos> sh.status()          #查看状态

iii、删除shard分片节点(谨慎)
  1、确认balancear是否在工作
  mongos> sh.getBalancerState()
         ...
  2、删除shard2节点(谨慎)
  mongos> db.runCommand( { removeShard: "shard2" } )
  ##注意:删除操作一定会立即触发balancer。添加和删除shard节点,都会触发mongodb进行chunk迁移;删除节点,会立即触发chunk迁移。添加节点,也会触发chunk迁移,把前面shard节点的数据迁移到信息的shard节点中,让数据分布的更均匀

 

使用分片集群

1、range 分片配置及测试

案例1:对test库下的vast表进行手工分表

i、激活数据库分片功能(若是想使用分片的功能,必须先激活指定库的分片功能)
  [mongod@db01 ~] # mongo --port 38017 admin     #进入mongos管理节点,又因为是管理性的操作,所以要在admin库下进行操作
            ...
  mongos> db.runCommand( { enablesharding : "test" } )

ii、指定分片键对collection进行分片
  mongos> use test        #切换到test库下
  mongos> db.vast.ensureIndex( { id: 1 } )       #创建索引,其中id:为要创建索引的字段;1:指定按升序创建索引,-1:按降序来创建索引。在mongodb 3.0版本以后,就使用 createIndex()方法来创建索引;了,ensureIndex()还能使用,但是只是createIndex()的别名
  mongos> use admin         #切换到admin库下    开启分片是一个管理性的功能,所以需要到admin库中进行操作。
  mongos> db.runCommand( { shardcollection : "test.vast",key : {id: 1} } )  #shardcollection:指定要分片的表和分片键

iii、集合分片验证
  mongos> use test         #切换到test下
  mongos> for(i=1;i<1000000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
  mongos> db.vast.stats()

iv、分片结果测试     测试结果可能会出现,所有的数据都被存放在shard2中,shard1中没有被存放任何数据。这是因为,测试的数据台小,还没有装满一个chunk,所以也就不会有chunk分裂和chunk迁移
  shard1中测试:
  [mongod@db01 ~] # mongo --port 38021
         ...
  >db.vast.count();

  shard2中测试:
  [mongod@db01 ~] # mongo --port 38024
         ...
  >db.vast.count();

2、Hash 分片配置及测试

案例2:对study库下的vast表进行hash分片
i、对于study库开启分片功能
  [mongod@db01 ~] # mongo --port 38017 admin
            ...
  mongos> db.runCommand( { enablesharding : "study" } )

ii、对于study库下的vast表中id字段建立hash索引
  mongos> use study             #切换到study库下
  mongos> db.vast.ensureIndex( { id: "hashed" } )      #创建hash索引

iii、开始分片
  mongos> use admin             #切换到admin库下
  mongos> sh.shardCollection( "oldboy.vast", { id: "hashed" } )       #此种开启分片方式和案例1中的开启分片方式都可以

iv、录入10w行数据测试
  mongos> use study             #切换到study库下
  mongos> for(i=1;i<100000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }

v、hash分片结果测试
  shard1中测试:
  [mongod@db01 ~] # mongo --port 38021
          ...
  mongos> use study
  mongos> db.vast.count();

  shard2中测试:
  [mongod@db01 ~] # mongo --port 38024
          ...
  mongos> use study
  mongos> db.vast.count();

3、查看分片信息

i、判断是否为Shard集群
  [mongod@db01 ~] # mongo --port 38017 admin
          ...
  mongos> db.runCommand({ isdbgrid : 1})

ii、列出所有分片信息
  mongos> db.runCommand({ listshards : 1})

iii、列出开启分片的数据库
  mongos> use config             #切换到config库下
 
  mongos> db.databases.find( { "partitioned": true } )       #列出开启数据库分片情况
  或
  mongos> config> db.databases.find()         #列出所有数据库分片情况

iv、查看分片的片键
  mongos> use config 
  mongos> db.collections.find().pretty()
  {
	  "_id" : "test.vast",
	  "lastmodEpoch" : ObjectId("58a599f19c898bbfb818b63c"),
	  "lastmod" : ISODate("1970-02-19T17:02:47.296Z"),
	  "dropped" : false,
	  "key" : {
		  "id" : 1
	  },
	  "unique" : false
  }

v、查看分片的详细信息
  [mongod@db01 ~] # mongo --port 38017 admin
           ...
  mongos> db.printShardingStatus()
  或
  mongos> sh.status()             #此命令可以查看上面几个命令的所查询到的信息

mongodb常用监控命令

  1. mongostat:查看mongo实例状态
  2. mongotop:mongodb数据库监控

 

参考文章:

https://blog.51cto.com/zengestudy/2105849