mongodb分片后怎么取数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mongodb分片后怎么取数据相关的知识,希望对你有一定的参考价值。

参考技术A 分片是MongoDB提供的一种机制,其可以将大型的集合分割保存到不同的服务器上。与其他的分区方案相比,MongoDB几乎能自动为我们完成所有事情。只要我们进行简单的配置,并告诉MongoDB要分配的数据,它就可以自动维护数据在不同服务器之间的平衡。同时根据需要增减服务器,MongoDB也会自动移动平移已有数据。
分片机制提供了如下三种优势
1. 对集群进行抽象,让集群“不可见”。
MongoDB自带了一个叫做mongos的专有路由进程。mongos就是掌握统一路口的路由器,其会将客户端发来的请求准确无误的路由到集群中的一个或者一组服务器上,同时会把接收到的响应拼装起来发回到客户端。
2.保证集群总是可读写。
MongoDB通过多种途径来确保集群的可用性和可靠性。将MongoDB的分片和复制功能结合使用,在确保数据分片到多台服务器的同时,也确保了每分数据都有相应的备份,这样就可以确保有服务器换掉时,其他的副本可以立即接替坏掉的部分继续工作。
3.使集群易于扩展。
当系统需要更多的空间和资源的时候,MongoDB使我们可以按需方便的扩充系统容量。
实现数据分割
分片(shard)是集群中存储集合数据子集的一台或者多台服务器。在生产环境中一个分片通常是一个副本集(replica set)。

片键(key),MongoDB以其作为依据来确定需要在不同分片服务器之间移动的数据。例如我们可以选择用户名(username)字段作为分片键,现有一用户名区间[“p”,”z”],那么wufengtinghai是属于这一区间的,那么数据最终会保存到与此区间对应的分片服务器上。
分配数据到分片服务器
分配数据到分片服务器可以使用不同的方式,了解不同的方式可以加深我们对MongoDB使用方式的理解。
一分片一区间
分配数据到分片最简单的方式莫过于一个区间一个分片。假设我们有四个分片存储用户的相关信息,则我们可能会得到如下的分片和区间的对应关系。

这种分片方式非常简单易懂,但是在一个大型繁忙的系统中却会带来许多的不便。假如大量的用户使用首字母在【“a”,”f”)中的名字来注册,这将会导致分片1比较大,因此需要将其一部分文档移动到分片2上,我们可以调整分片1对应区间【”a”,”c”),使分片2的区间变成【”c”,”n”)。

如果移动数据后,分片2因此过载怎么办?假设分片1和分片2各有500G数据,而分片3和分片4各自有300G数据。那么按照这个方案,最终需要一连串的复制,总共算下来需要移动400G数据,考虑到需要在集群的服务器之间移动这些数据,可见移动数据量之大。

如果需要新加分片服务器进行水平扩展呢?假设此时每个分片上都有了500G数据,那么我们现在需要将分片4上的400G数据移动到分片5,将分片3的300G数据移动到分片4,将分片2的200G数据移动到分片3,将分片1的100G数据移动到分片2,整整移动了1T的数据!

随着分片数量和数据量的增长,这种噩梦将会持续下去,因此MongoDB不会采用这种方式。
一分片多区间
如果我们采用一分片多区间的方式,我们可以将分片1上的数据划分为两个区间,【”a”,”d”)包含400G数据,【”d”,”f”)包含100G数据,同样我们也可以对分片2做类似的处理,得到区间【”f”,”j”)和【“j”,”n”)。现在我们只需要将分片1上的【”d”,”f”)数据移动到分片4,将分片2的【“j”,”n”)的数据移动到分片3。这样我们仅仅只需要移动200G数据。

如果要添加新分片,可以从每个分片顶端取100G数据并将其移动到新的分片上,这样仅仅只需要移动400G数据即可。

MongoDB就是利用这种方式,当一个分片的数据越来越大时,其会自动分割片键区间,并将分片的数据进行分割并移动到其他分片。本回答被提问者和网友采纳

mongodb分片

在系统早期,数据量还小的时候不会引起太大的问题,但是随着数据量持续增多,后续迟早会出现一台机器硬件瓶颈问题的。而mongodb主打的就是海量数据架构,他不能解决海量数据怎么行!不行!“分片”就用这个来解决这个问题。

传统数据库怎么做海量数据读写?其实一句话概括:分而治之。上图看看就清楚了,如下 taobao岳旭强在infoq中提到的 架构图:

技术分享

上图中有个TDDL,是taobao的一个数据访问层组件,他主要的作用是SQL解析、路由处理。根据应用的请求的功能解析当前访问的sql判断是在哪个业务数据库、哪个表访问查询并返回数据结果。具体如图:

技术分享

说了这么多传统数据库的架构,那Nosql怎么去做到了这些呢?mysql要做到自动扩展需要加一个数据访问层用程序去扩展,数据库的增加、删除、备份还需要程序去控制。一但数据库的节点一多,要维护起来也是非常头疼的。不过mongodb所有的这一切通过他自己的内部机制就可以搞定!顿时石化了,这么牛X!还是上图看看mongodb通过哪些机制实现路由、分片:

技术分享

从图中可以看到有四个组件:mongos、config server、shard、replica set。

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

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

shard,这就是传说中的分片了。上面提到一个机器就算能力再大也有天花板,就像军队打仗一样,一个人再厉害喝血瓶也拼不过对方的一个师。俗话说三个臭皮匠顶个诸葛亮,这个时候团队的力量就凸显出来了。在互联网也是这样,一台普通的机器做不了的多台机器来做,如下图:

技术分享

一台机器的一个数据表 Collection1 存储了 1T 数据,压力太大了!在分给4个机器后,每个机器都是256G,则分摊了集中在一台机器的压力。也许有人问一台机器硬盘加大一点不就可以了,为什么要分给四台机器呢?不要光想到存储空间,实际运行的数据库还有硬盘的读写、网络的IO、CPU和内存的瓶颈。在mongodb集群只要设置好了分片规则,通过mongos操作数据库就能自动把对应的数据操作请求转发到对应的分片机器上。在生产环境中分片的片键可要好好设置,这个影响到了怎么把数据均匀分到多个分片机器上,不要出现其中一台机器分了1T,其他机器没有分到的情况,这样还不如不分片!

replica set,上两节已经详细讲过了这个东东,怎么这里又来凑热闹!其实上图4个分片如果没有 replica set 是个不完整架构,假设其中的一个分片挂掉那四分之一的数据就丢失了,所以在高可用性的分片架构还需要对于每一个分片构建 replica set 副本集保证分片的可靠性。生产环境通常是 2个副本 + 1个仲裁。

说了这么多,还是来实战一下如何搭建高可用的mongodb集群:

首先确定各个组件的数量,mongos 3个, config server 3个,数据分3片 shard server 3个,每个shard 有一个副本一个仲裁也就是 3 * 2 = 6 个,总共需要部署15个实例。这些实例可以部署在独立机器也可以部署在一台机器,我们这里测试资源有限,只准备了 3台机器,在同一台机器只要端口不同就可以,看一下物理部署图:

技术分享

架构搭好了,安装软件!

  • 1、准备机器,IP分别设置为: 192.168.0.136、192.168.0.137、192.168.0.138。
  • 2、分别在每台机器上建立mongodb分片对应测试文件夹。
    1
    2
    #存放mongodb数据文件
    mkdir -p /data/mongodbtest
    1
    2
    #进入mongodb文件夹
    cd  /data/mongodbtest
  • 3、下载mongodb的安装程序包
    1
    wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.8.tgz
    1
    2
    #解压下载的压缩包
    tar xvzf mongodb-linux-x86_64-2.4.8.tgz
  • 4、分别在每台机器建立mongos 、config 、 shard1 、shard2、shard3 五个目录。
    因为mongos不存储数据,只需要建立日志文件目录即可。

     

    1
    2
    #建立mongos目录
    mkdir -p /data/mongodbtest/mongos/log
    1
    2
    #建立config server 数据文件存放目录
    mkdir -p /data/mongodbtest/config/data
    1
    2
    #建立config server 日志文件存放目录
    mkdir -p /data/mongodbtest/config/log
    1
    2
    #建立config server 日志文件存放目录
    mkdir -p /data/mongodbtest/mongos/log
    1
    2
    #建立shard1 数据文件存放目录
    mkdir -p /data/mongodbtest/shard1/data
    1
    2
    #建立shard1 日志文件存放目录
    mkdir -p /data/mongodbtest/shard1/log
    1
    2
    #建立shard2 数据文件存放目录
    mkdir -p /data/mongodbtest/shard2/data
    1
    2
    #建立shard2 日志文件存放目录
    mkdir -p /data/mongodbtest/shard2/log
    1
    2
    #建立shard3 数据文件存放目录
    mkdir -p /data/mongodbtest/shard3/data
    1
    2
    #建立shard3 日志文件存放目录
    mkdir -p /data/mongodbtest/shard3/log
  • 5、规划5个组件对应的端口号,由于一个机器需要同时部署 mongos、config server 、shard1、shard2、shard3,所以需要用端口进行区分。
    这个端口可以自由定义,在本文 mongos为 20000, config server 为 21000, shard1为 22001 , shard2为22002, shard3为22003.
  • 6、在每一台服务器分别启动配置服务器。
    1
    /data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongod --configsvr --dbpath /data/mongodbtest/config/data --port 21000 --logpath /data/mongodbtest/config/log/config.log --fork
  • 7、在每一台服务器分别启动mongos服务器。
    1
    /data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongos  --configdb 192.168.0.136:21000,192.168.0.137:21000,192.168.0.138:21000  --port 20000   --logpath  /data/mongodbtest/mongos/log/mongos.log --fork
  • 8、配置各个分片的副本集。
    1
    2
    #在每个机器里分别设置分片1服务器及副本集shard1
    /data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongod --shardsvr --replSet shard1 --port 22001 --dbpath /data/mongodbtest/shard1/data  --logpath /data/mongodbtest/shard1/log/shard1.log --fork --nojournal  --oplogSize 10

    为了快速启动并节约测试环境存储空间,这里加上 nojournal 是为了关闭日志信息,在我们的测试环境不需要初始化这么大的redo日志。同样设置 oplogsize是为了降低 local 文件的大小,oplog是一个固定长度的 capped collection,它存在于”local”数据库中,用于记录Replica Sets操作日志。注意,这里的设置是为了测试!

    1
    2
    #在每个机器里分别设置分片2服务器及副本集shard2
    /data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongod --shardsvr --replSet shard2 --port 22002 --dbpath /data/mongodbtest/shard2/data  --logpath /data/mongodbtest/shard2/log/shard2.log --fork --nojournal  --oplogSize 10
    1
    2
    #在每个机器里分别设置分片3服务器及副本集shard3
    /data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongod --shardsvr --replSet shard3 --port 22003 --dbpath /data/mongodbtest/shard3/data  --logpath /data/mongodbtest/shard3/log/shard3.log --fork --nojournal  --oplogSize 10

    分别对每个分片配置副本集,深入了解副本集参考本系列前几篇文章。

    任意登陆一个机器,比如登陆192.168.0.136,连接mongodb

    1
    2
    #设置第一个分片副本集
    /data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo  127.0.0.1:22001
    1
    2
    #使用admin数据库
    use admin
    1
    2
    3
    4
    5
    6
    7
    #定义副本集配置
    config = { _id:"shard1", members:[
                         {_id:0,host:"192.168.0.136:22001"},
                         {_id:1,host:"192.168.0.137:22001"},
                         {_id:2,host:"192.168.0.138:22001",arbiterOnly:true}
                    ]
             }
    1
    2
    #初始化副本集配置
    rs.initiate(config);
    1
    2
    #设置第二个分片副本集
    /data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo  127.0.0.1:22002
    1
    2
    #使用admin数据库
    use admin
    1
    2
    3
    4
    5
    6
    7
    #定义副本集配置
    config = { _id:"shard2", members:[
                         {_id:0,host:"192.168.0.136:22002"},
                         {_id:1,host:"192.168.0.137:22002"},
                         {_id:2,host:"192.168.0.138:22002",arbiterOnly:true}
                    ]
             }
    1
    2
    #初始化副本集配置
    rs.initiate(config);
    1
    2
    #设置第三个分片副本集
    /data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo    127.0.0.1:22003
    1
    2
    #使用admin数据库
    use admin
    1
    2
    3
    4
    5
    6
    7
    #定义副本集配置
    config = { _id:"shard3", members:[
                         {_id:0,host:"192.168.0.136:22003"},
                         {_id:1,host:"192.168.0.137:22003"},
                         {_id:2,host:"192.168.0.138:22003",arbiterOnly:true}
                    ]
             }
    1
    2
    #初始化副本集配置
    rs.initiate(config);
  • 9、目前搭建了mongodb配置服务器、路由服务器,各个分片服务器,不过应用程序连接到 mongos 路由服务器并不能使用分片机制,还需要在程序里设置分片配置,让分片生效。
    1
    2
    #连接到mongos
    /data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo  127.0.0.1:20000
    1
    2
    #使用admin数据库
    user  admin
    1
    2
    #串联路由服务器与分配副本集1
    db.runCommand( { addshard : "shard1/192.168.0.136:22001,192.168.0.137:22001,192.168.0.138:22001"});

    如里shard是单台服务器,用 db.runCommand( { addshard : “[: ]” } )这样的命令加入,如果shard是副本集,用db.runCommand( { addshard : “replicaSetName/[:port][,serverhostname2[:port],…]” });这样的格式表示 。

    1
    2
    #串联路由服务器与分配副本集2
    db.runCommand( { addshard : "shard2/192.168.0.136:22002,192.168.0.137:22002,192.168.0.138:22002"});
    1
    2
    #串联路由服务器与分配副本集3
    db.runCommand( { addshard : "shard3/192.168.0.136:22003,192.168.0.137:22003,192.168.0.138:22003"});
    1
    2
    #查看分片服务器的配置
    db.runCommand( { listshards : 1 } );

    #内容输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    {
             "shards" : [
                    {
                            "_id" : "shard1",
                            "host" : "shard1/192.168.0.136:22001,192.168.0.137:22001"
                    },
                    {
                            "_id" : "shard2",
                            "host" : "shard2/192.168.0.136:22002,192.168.0.137:22002"
                    },
                    {
                            "_id" : "shard3",
                            "host" : "shard3/192.168.0.136:22003,192.168.0.137:22003"
                    }
            ],
            "ok" : 1
    }

    因为192.168.0.138是每个分片副本集的仲裁节点,所以在上面结果没有列出来。

  • 10、目前配置服务、路由服务、分片服务、副本集服务都已经串联起来了,但我们的目的是希望插入数据,数据能够自动分片,就差那么一点点,一点点。。。

    连接在mongos上,准备让指定的数据库、指定的集合分片生效。

    1
    2
    #指定testdb分片生效
    db.runCommand( { enablesharding :"testdb"});
    1
    2
    #指定数据库里需要分片的集合和片键
    db.runCommand( { shardcollection : "testdb.table1",key : {id: 1} } )

    我们设置testdb的 table1 表需要分片,根据 id 自动分片到 shard1 ,shard2,shard3 上面去。要这样设置是因为不是所有mongodb 的数据库和表 都需要分片!

  • 11、测试分片配置结果。
    1
    2
    #连接mongos服务器
    /data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo  127.0.0.1:20000
    1
    2
    #使用testdb
    use  testdb;
    1
    2
    3
    #插入测试数据
    for (var i = 1; i <= 100000; i++)
    db.table1.save({id:i,"test1":"testval1"});
    1
    2
    #查看分片情况如下,部分无关信息省掉了
    db.table1.stats();
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    {
            "sharded" true,
            "ns" "testdb.table1",
            "count" 100000,
            "numExtents" 13,
            "size" 5600000,
            "storageSize" 22372352,
            "totalIndexSize" 6213760,
            "indexSizes" : {
                    "_id_" 3335808,
                    "id_1" 2877952
            },
            "avgObjSize" 56,
            "nindexes" 2,
            "nchunks" 3,
            "shards" : {
                    "shard1" : {
                            "ns" "testdb.table1",
                            "count" 42183,
                            "size" 0,
                            ...
                            "ok" 1
                    },
                    "shard2" : {
                            "ns" "testdb.table1",
                            "count" 38937,
                            "size" 2180472,
                            ...
                            "ok" 1
                    },
                    "shard3" : {
                            "ns" "testdb.table1",
                            "count" :18880,
                            "size" 3419528,
                            ...
                            "ok" 1
                    }
            },
            "ok" 1
    }

    可以看到数据分到3个分片,各自分片数量为: shard1 “count” : 42183,shard2 “count” : 38937,shard3 “count” : 18880。已经成功了!不过分的好像不是很均匀,所以这个分片还是很有讲究的,后续再深入讨论。

  • 12、java程序调用分片集群,因为我们配置了三个mongos作为入口,就算其中哪个入口挂掉了都没关系,使用集群客户端程序如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public class TestMongoDBShards {
     
           public static void main(String[] args) {
     
                 try {
                      List<ServerAddress> addresses = new ArrayList<ServerAddress>();
                      ServerAddress address1 = new ServerAddress("192.168.0.136" 20000);
                      ServerAddress address2 = new ServerAddress("192.168.0.137" 20000);
                      

以上是关于mongodb分片后怎么取数据的主要内容,如果未能解决你的问题,请参考以下文章

mongodb带密码的副本集加入分片后怎么访问

mongoDB分片集群

mongodb分片

走进MongoDB---- 分片

Mongodb 分片

[转]搭建高可用mongodb集群—— 分片