美文网首页MongoDB入门与进阶
mongoDB高级篇-mongo分片初体验

mongoDB高级篇-mongo分片初体验

作者: 逐梦々少年 | 来源:发表于2021-05-18 17:34 被阅读0次

    如果说复制集是mongo为了备份数据,将一份数据存储在多台实例上的一种集群架构的话,那么当我们的数据存储过多,最好能将数据分开存储,这个时候就可以使用mongo的另一个多实例部署架构--数据分片

    分片的概念就是将数据拆分,将其分散存储在不同机器上的过程。在很多中间件都有类似的概念,有些中间件中叫做'分区'概念,其实也是与分片类似的说法。基本上现代主流数据库都支持,用户手动管理,将数据存储在不同的集合中,连接彼此独立,但是手动维护带来的问题就是维护难度的增大,整体分片的调整,如增加节点,删除节点难度都变得很困难。而在MongoDB中,内部集成了自动分片功能,可以让分片操作对用户不可见,从而简化手动管理的成本。

    分片初体验

    想要开始搭建一个分片集群,我们先理解一下这个集群中的几个组件以及其作用,由于分片集群的目标一般是想要满足五台、十台甚至更多的实例,对外仅仅是和连接单机mongo一样,因此必须有其他组件帮忙隐藏其中的一些细节,因此整个mongo的分片集群架构就可以分成如下这样:

    1621232061692.png
    分片集群的三大组件

    我们可以看到整个MongoDB Sharding集群中大体可以分为三个组件:

    数据分片 -- shards

    数据分片用于保存数据,保证了数据的高可用和一致性,这里每一个shard可以是独立的mongod实例,也可以是一个复制集,防止出现单点的故障问题。当然也可以选择把所有的shard的复制集放在一个服务器中启动多个mongod实例,在sharding中,每个node的database数据库可以选择分片也可以选择不分片,每一个db中都有一个独立的primary shard,在未分片的集合中就是存在于各自的primary shard中的

    查询路由 -- mongos

    我们可以看到,当我们想要连接分片集群,将数据分开存储,或者想要从分开存储的分片集群中,将我们想要的数据聚集查询出来,为了隐藏其中的细节,这个时候就需要使用查询路由--mongos了,客户端连接不是直接连接分片集群中,而是连接到mongos,通过mongos进行一次路由过程的操作分发,而mongos通过查询维护的一个“内容列表”,里面记录了每个分片中按照什么规则(分片键)存储数据,每个分片中包含了哪些内容等,而客户端的请求到达mongos以后,mongos会根据记录的内容,选择性将请求分发到对应的一个或者多个分片服务实例上,然后再将所有分片的响应结果进行合并再统一输出给客户端程序,从而实现了屏蔽分片的细节,流程大体如下:

    1614761108966.png

    配置服务器 -- Config Server

    配置服务器就是用于存储分片集群的配置信息的元数据,其中包含了mongos需要的shard的路由规则,路由键等信息,在mongo 3.2版本开始config server可以配置成为replica set了,在3.4以后官方已经规定config server必须为replica set,并且为了保证生产环境的稳定,rs中至少要有三个副本集成员存在

    分片集群上手初体验

    现在我们开始搭建一个简单的分片架构,在mongo3.4以后的版本中,一个分片集群,shard节点的数量至少要是两个,而config节点和路由mongos节点则至少需要一个,因此我们这里来通过在一台服务器上启动多个节点的方式 模拟分片架构,搭建两个shards复制集作为两个shard节点,搭建一个config server复制集作为config节点,而mongos我们则使用单节点启动方式,快速搭建一个分片集群架构快速上手体验一下

    配置shards
    cd /etc;
    #首先创建一下shard的log存放的目录
    mkdir -p /var/log/mongodb_shard;
    mkdir -p /var/log/mongo_shard1;
    mkdir -p /var/log/mongo_shard2;
    mkdir -p /var/log/mongodb_shard3;
    #接着创建shard的数据库文件存放目录
    mkdir -p /var/lib/mongo_shard;
    mkdir -p /var/lib/mongo_shard1;
    mkdir -p /var/lib/mongo_shard2;
    mkdir -p /var/lib/mongo_shard3;
    #创建shard启动配置文件存放目录
    mkdir mongo_shard/;
    mkdir mongo_shard1/;
    mkdir mongo_shard2/;
    mkdir mongo_shard3/;
    #创建pidFilePath存放目录
    mkdir -p /var/run/mongo_shard;
    mkdir -p /var/run/mongo_shard1;
    mkdir -p /var/run/mongo_shard2;
    mkdir -p /var/run/mongo_shard3;
    #将mongo的配置文件分别cp到这些目录中,这里我们cp的是上篇文章中我们配置的复制集的配置文件,否则配置文件中还要配置复制集
    cp -r mongod1.conf mongo_shard/mongod.conf;
    cp -r mongod1.conf mongo_shard1/mongod.conf;
    cp -r mongod1.conf mongo_shard2/mongod.conf;
    cp -r mongod1.conf mongo_shard3/mongod.conf;
    #vim修改每一个shard的config启动参数,主要修改systemLog下的path,storage下的dbPath,processManagement下的pidFilePath,这里我们分别修改为上面创建的log目录,db存储目录,以及pidFilePath存放目录,net下的启动端口这里分别修改为30017、30018和30019、30020,除此之外,由于shard我们要创建成为两个rs,因此,replication下的replSetName参数,mongo_shard和mongo_shard1我们将其指定为shard,mongo_shard和mongo_shard1我们将其指定为shard2,代表几个shard组成的复制集名称分别叫shard和shard2
    vim mongo_shard/mongod.conf;
    vim mongo_shard1/mongod.conf;
    vim mongo_shard2/mongod.conf;
    vim mongo_shard3/mongod.conf;
    

    这里我们需要注意,由于当前的角色是shard,因此我们在给常规的配置文件参数修改后,还要添加sharding相关的配置,代表当前的角色为shard,如下:


    1614847222095.png

    添加如下配置即可:

    sharding:
      # 分片角色
      clusterRole: shardsvr
    

    下面是一个配置好的shard的mongod.conf的完整配置示例:

    # mongod.conf
    # where to write logging data.
    systemLog:
      destination: file
      logAppend: true
      path: /var/log/mongodb_shard/mongod.log
    
    # Where and how to store data.
    storage:
      dbPath: /var/lib/mongo_shard
      journal:
        enabled: true
    #  engine:
    
    #  wiredTiger:
    
    # how the process runs
    processManagement:
      fork: true  #后台启动进程
      pidFilePath: /var/run/mongo_shard/mongod.pid  
      timeZoneInfo: /usr/share/zoneinfo
    
    # network interfaces
    net:
      port: 30017
      bindIp: 0.0.0.0  # Enter 0.0.0.0,:: to bind to all IPv4 and IPv6 addresses or, alternatively, use the net.bindIpAll setting.
    
    #security:
    
    #operationProfiling:
    
    #replication:
    replication:
     replSetName: shard
    #sharding:
    sharding:
      # 分片角色
      clusterRole: shardsvr
    
    ## Enterprise-Only Options
    
    #auditLog:
    
    #snmp:
    

    将所有的shard的目录和文件配置准备完成,我们开始将其分别启动,组成rs复制集:

    /usr/bin/mongod -f /etc/mongo_shard/mongod.conf;
    /usr/bin/mongod -f /etc/mongo_shard1/mongod.conf;
    /usr/bin/mongod -f /etc/mongo_shard2/mongod.conf;
    /usr/bin/mongod -f /etc/mongo_shard3/mongod.conf;
    #查看当前进程是否都存在
    ps -ef|grep mongo
    #可以看到 已经启动完成了
    root     113935      1 13 02:35 ?        00:00:02 /usr/bin/mongod -f /etc/mongo_shard/mongod.conf
    root     114005      1 26 02:35 ?        00:00:03 /usr/bin/mongod -f /etc/mongo_shard1/mongod.conf
    root     114151      1 41 02:35 ?        00:00:03 /usr/bin/mongod -f /etc/mongo_shard2/mongod.conf
    root     114252      1 41 02:35 ?        00:00:03 /usr/bin/mongod -f /etc/mongo_shard3/mongod.conf
    root     114341   2433  0 02:35 pts/0    00:00:00 grep --color=auto mongo
    #登录shard复制集的任意一个节点,初始化复制集
    /usr/bin/mongo --port 30017;
    #初始化复制集 
    rs.initiate({ _id:"shard", members:[{ _id:0, host:"127.0.0.1:30017" },{ _id:1, host:"127.0.0.1:30018" }] });
    #登录shard2复制集的任意一个节点,初始化复制集
    /usr/bin/mongo --port 30019;
    #初始化复制集 
    rs.initiate({ _id:"shard2", members:[{ _id:0, host:"127.0.0.1:30019" },{ _id:1, host:"127.0.0.1:30020" }] });
    
    配置config server

    用于存储分片配置的Config Server我们这里仅仅配置成一个master-slave的rs即可:

    cd /etc;
    #首先创建一下config_server的log存放的目录
    mkdir -p /var/log/mongo/config_master;
    mkdir -p /var/log/mongo/config_slave;
    #接着创建config_server的数据库文件存放目录
    mkdir -p /var/lib/mongo/config_master;
    mkdir -p /var/lib/mongo/config_slave;
    #创建config_server启动配置文件存放目录
    mkdir mongo_config_master/;
    mkdir mongo_config_slave/;
    #创建pidFilePath存放目录
    mkdir -p /var/run/mongo_config_master;
    mkdir -p /var/run/mongo_config_slave;
    #将mongo的配置文件分别cp到这些目录中,这里我们cp的是上篇文章中我们配置的复制集的配置文件,否则配置文件中还要配置复制集
    cp -r mongod1.conf mongo_config_master/mongod.conf;
    cp -r mongod1.conf mongo_config_slave/mongod.conf;
    #vim修改每一个config_server的config启动参数,主要修改systemLog下的path,storage下的dbPath,processManagement下的pidFilePath,这里我们分别修改为上面创建的log目录,db存储目录,以及pidFilePath存放目录,net下的启动端口这里分别修改为37017和37018,除此之外,由于这里的节点我们要创建成为一个主-从的rs,因此,replication下的replSetName参数我们将其定义成config,代表几个节点组成的复制集名称叫config
    vim mongo_config_master/mongod.conf;
    vim mongo_config_slave/mongod.conf;
    

    与上面shard的处理方式几乎一样,当然这里唯一的区别就是,分片角色的配置,上面是shard,这里需要配置为config,如下:

    #sharding:
    sharding:
      # 分片角色
      clusterRole: configsvr
    

    一切配置准备好以后,我们开始启动config server复制集,完成初始化操作:

    /usr/bin/mongod -f /etc/mongo_config_master/mongod.conf;
    /usr/bin/mongod -f /etc/mongo_config_slave/mongod.conf;
    #登录第一个复制集
    /usr/bin/mongo --port 37017;
    #初始化复制集 
    rs.initiate({ _id:"config", members:[{ _id:0, host:"127.0.0.1:37017" },{ _id:1, host:"127.0.0.1:37018" }] });
    
    启动查询路由--mongos

    这里我们只配置一个mongos实例,不去做集群启动了,因此我们需要和前面一样,创建四个目录,分别存放log,db文件和pid目录以及config配置文件的目录

    cd /etc;
    #首先创建一下shard的log存放的目录
    mkdir -p /var/log/mongos_db;
    #接着创建mongos的数据库文件存放目录
    mkdir -p /var/lib/mongos;
    #创建mongos启动配置文件存放目录
    mkdir mongos/;
    #创建pidFilePath存放目录
    mkdir -p /var/run/mongos;
    #复制 配置文件到目录下
    cp -r mongod1.conf mongos/mongod.conf;
    
    #修改配置文件
    vim mongos/mongod.conf;
    #修改 path: /var/log/mongos_db/mongod1.log
    #修改 dbPath: /var/lib/mongos/mongo1
    #修改 pidFilePath: /var/run/mongos/mongod1.pid
    #修改  port: 27050
    #修改 replSetName: mongos
    #配置文件中添加如下配置,指定config集群的信息
    sharding:
      configDB: config/127.0.0.1:37017,127.0.0.1:37018
      
    #需要注意的是,使用mongos的话,是无法识别storage.dbPath配置的,因此要注释当前的配置
    #storage:
      #dbPath: /var/lib/mongos/mongo1  
      #journal:
      #  enabled: true
    #除此之外,还要删除replication相关的配置
    #replication:
    # replSetName: mongos
    #启动mongos,注意这里用的是mongos启动
    /usr/bin/mongos -f /etc/mongos/mongod.conf;
    #连接mongos
    mongo --port=27050;
    

    这个时候我们连接进去,可以看到,当前的角色已经变了,成为了mongos,需要注意的是我们要做分片操作,首先需要给需要分片的数据库启动分片,开启命令如下:

    sh.enableSharding("db_name");
    

    现在整个db的集合都可以进行分片了,不过需要注意的是,我们要对某个集合做分片,必须要选择一个片键,片键是集合文档内的一个键,Mongo会根据策略和这个片键进行拆分数据,我们要给集合启用分片之前,需要先在片键上创建索引:

    db.collection.ensureIndex({"key":1});
    

    然后我们就可以设置根据这个key来作为片键进行分片操作了:

    sh.shardCollection("db.collection",{id:"key"});
    

    配置完成后,我们来将shard信息添加进来,进行分片数据插入测试:

    use admin;
    #添加shard信息
    mongos> sh.addShard("shard/127.0.0.1:30017,127.0.0.1:30018");
    mongos> sh.addShard("shard2/127.0.0.1:30019,127.0.0.1:30020");
    #设置test库为允许sharding
    sh.enableSharding("test");
    #设置test中的tes集合的id按照hash的方式进行sharding
    sh.shardCollection("test.tes",{id:"hashed"});
    #插入几条数据测试一下
    for(i=1;i<=1000;i++){db.tes.insert({id:i,name:"Leo"})}
    

    这里我们插入数据完成以后,分别进入两个shard查看一下当前的数据,看是否生效

    #登录第一个shard
    /usr/bin/mongo --port 30017;
    use test;
    db.tes.find();
    #结果如下:
    shard:PRIMARY> db.tes.find()
    { "_id" : ObjectId("60a3a08cd9ea857697bcf0cd"), "id" : 3, "name" : "Leo3" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0d0"), "id" : 6, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0d2"), "id" : 8, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0d5"), "id" : 11, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0d6"), "id" : 12, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0de"), "id" : 20, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0df"), "id" : 21, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0e4"), "id" : 26, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0e5"), "id" : 27, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0e8"), "id" : 30, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0ea"), "id" : 32, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0eb"), "id" : 33, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0f0"), "id" : 38, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0f2"), "id" : 40, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0f3"), "id" : 41, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0f4"), "id" : 42, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0f6"), "id" : 44, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0fa"), "id" : 48, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0fc"), "id" : 50, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0fe"), "id" : 52, "name" : "Leo" }
    
    #登录第二个shard
    /usr/bin/mongo --port 30019;
    use test;
    db.tes.find();
    #结果如下:
    shard2:PRIMARY> db.tes.find()
    { "_id" : ObjectId("60a3a07bd9ea857697bcf0ca"), "id" : 0, "name" : "Leo0" }
    { "_id" : ObjectId("60a3a081d9ea857697bcf0cb"), "id" : 1, "name" : "Leo1" }
    { "_id" : ObjectId("60a3a086d9ea857697bcf0cc"), "id" : 2, "name" : "Leo2" }
    { "_id" : ObjectId("60a3a091d9ea857697bcf0ce"), "id" : 4, "name" : "Leo4" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0cf"), "id" : 5, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0d1"), "id" : 7, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0d3"), "id" : 9, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0d4"), "id" : 10, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0d7"), "id" : 13, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0d8"), "id" : 14, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0d9"), "id" : 15, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0da"), "id" : 16, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0db"), "id" : 17, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0dc"), "id" : 18, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0dd"), "id" : 19, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0e0"), "id" : 22, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0e1"), "id" : 23, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0e2"), "id" : 24, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0e3"), "id" : 25, "name" : "Leo" }
    { "_id" : ObjectId("60a3a0d3d9ea857697bcf0e6"), "id" : 28, "name" : "Leo" }
    

    可见当前我们的分片整个是已经搭建完成了,这个时候我们可以查看当前的分片集群的一个状态,通过如下命令:

    mongos> sh.status();
    --- Sharding Status --- 
      sharding version: {
            "_id" : 1,
            "minCompatibleVersion" : 5,
            "currentVersion" : 6,
            "clusterId" : ObjectId("60a39c69f5d7a342f9cdfb1d")
      }
      shards:
            {  "_id" : "shard",  "host" : "shard/127.0.0.1:30017,127.0.0.1:30018",  "state" : 1 }
            {  "_id" : "shard2",  "host" : "shard2/127.0.0.1:30019,127.0.0.1:30020",  "state" : 1 }
      active mongoses:
            "4.2.8" : 1
      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: 
                    512 : Success
      databases:
            {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                    config.system.sessions
                            shard key: { "_id" : 1 }
                            unique: false
                            balancing: true
                            chunks:
                                    shard   512
                                    shard2  512
                            too many chunks to print, use verbose if you want to force print
            {  "_id" : "test",  "primary" : "shard2",  "partitioned" : true,  "version" : {  "uuid" : UUID("72bb131e-1e88-4267-adc2-9f97e1e8d663"),  "lastMod" : 1 } }
                    test.tes
                            shard key: { "id" : "hashed" }
                            unique: false
                            balancing: true
                            chunks:
                                    shard   2
                                    shard2  2
                            { "id" : { "$minKey" : 1 } } -->> { "id" : NumberLong("-4611686018427387902") } on : shard Timestamp(1, 0) 
                            { "id" : NumberLong("-4611686018427387902") } -->> { "id" : NumberLong(0) } on : shard Timestamp(1, 1) 
                            { "id" : NumberLong(0) } -->> { "id" : NumberLong("4611686018427387902") } on : shard2 Timestamp(1, 2) 
                            { "id" : NumberLong("4611686018427387902") } -->> { "id" : { "$maxKey" : 1 } } on : shard2 Timestamp(1, 3) 
    

    sh命令和前面的rs命令很像,不过这里是用来代替分片集群管理的,而rs则是一个全局变量,除了可以管理以外,还内置了很多辅助函数,我们也可以选择使用sh.help();查看可以使用的辅助函数有哪些

    相关文章

      网友评论

        本文标题:mongoDB高级篇-mongo分片初体验

        本文链接:https://www.haomeiwen.com/subject/eddyjltx.html