zoukankan      html  css  js  c++  java
  • mongoDB研究笔记:分片集群的工作机制

    上面的(http://www.cnblogs.com/guoyuanwei/p/3565088.html)介绍了部署了一个默认的分片集群,对mongoDB的分片集群有了大概的认识,到目前为止我们还没有在集群上建立其它数据库,mongoDB的分片是基于集合(表)来进行的,因此要对一个集合分片,必须先使其所在的数据库支持分片。如何使一个集合分片?如何选择分片用到的片键?平衡器如何使chunks块在片中迁移?分片的读写情况怎么样?接下来将探讨这些问题。

    使集合分片

    (1)连接到上面所配置集群中的mongos实例

    > mongo --port 40009

    (2)在集群中创建数据库eshop和集合users

          mongos> use eshop

                switched to db eshop

          mongos> db.users.insert({userid:1,username:"lili",city:"beijing"})

         此时在集合users中只有一条记录:

         { "_id" : ObjectId("521dcce715ce3967f964c00b"), "userid" : 1, "username" : "lili", "city" :    "beijing" }

    观察集群的状态信息,字段databases会增加一条记录,其它字段与初始化的集群信息相同:

    mongos> sh.status()

            databases:

            {  "_id" : "eshop",  "partitioned" : false,  "primary" : "rs0" }

    可以看到此时数据库eshop还没支持分片,且数据库中所有未分片的集合将保存在片rs0中;通过查看磁盘上的数据文件,此时会产生eshop.0、eshop.1、eshop.ns三个文件且位于rs0所对应的数据目录中,集群中chunks集合为空,因为现在还没有对集合users分片。

    (3)分片

          mongoDB的分片是基于范围的,也就是说任何一个文档一定位于指定片键的某个范围内,一旦片键选择好后,chunks就会按照片键来将一部分documents从逻辑上组合在一起。这里对users集合选择"city"字段作为片键来分片,假如现在"city"字段值有"beijing"、"guangzhou"、"changsha",初始的时候随机的向集群中插入包含以上字段值的文档,此时由于chunks的大小未达到默认的阈值64MB或100000个文档,集群中应该只有一个chunk,随着继续插入文档,超过阈值的chunk会被分割成两个chunks,最终的chunks和片键分布可能如下表格所示。表格只是大体上描述了分片的情况,实际可能有所变化,其中-表示所有键值小于"beijing"的文档,表示所有键值大于"guangzhou"的文档。这里还要强调一点就是chunks所包含的文档,并不是物理上的包含,它是一种逻辑包含,它只表示带有片键的文档会落在哪个范围内,而这个范围的文档对应的chunk位于哪个片是可以查询到的,后续的读写操作就定位到这个片上的具体集合中进行。

    开始键值

    结束键值

    所在分片

    -

    beijing

    rs0

    beijing

    changsha

    rs1

    changsha

    guangzhou

    rs0

    guangzhou

    rs1

    下面继续通过命令使集合users分片,使集合分片必须先使其所在的数据库支持分片,如下:

    mongos> sh.enableSharding("eshop")  //使数据库支持分片

    对已有数据的集合进行分片,必须先在所选择的片键上创建一个索引,如果集合初始时没有任何数据,则mongoDB会自动在所选择的的片键上创建一个索引。

    mongos> db.users.ensureIndex({city:1})  //创建基于片键的索引

    mongos> sh.shardCollection("eshop.users",{city:1})  //使集合分片

    成功执行上面命令后,再次查看集群状态信息:

    mongos> sh.status()

    --- Sharding Status ---

      sharding version: {

            "_id" : 1,

            "version" : 3,

            "minCompatibleVersion" : 3,

            "currentVersion" : 4,

            "clusterId" : ObjectId("521b11e0a663075416070c04")

    }

      shards:

            {  "_id" : "rs0",  "host" : "rs0/GUO:40000,GUO:40001" }

            {  "_id" : "rs1",  "host" : "rs1/GUO:40003,GUO:40004" }

      databases:

            {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }

            {  "_id" : "eshop",  "partitioned" : true,  "primary" : "rs0" } //数据库已支持分片

                    eshop.users //分片的集合

                            shard key: { "city" : 1 } //片键

                            chunks:   //所有块信息

                                    rs0     1 //当前只有1个块在片rs0上

                            { "city" : { "$minKey" : 1 } } -->> { "city" : { "$maxKe

    y" : 1 } } on : rs0 { "t" : 1, "i" : 0 } //此块的包含键值范围是-,且在片rs0上,因为此时集合中只有一条记录,还未进行块的分割、迁移

    (4)继续插入数据使集合自动分片

         为了观察到集合被分成多个chunk,并分布在多个片上,继续插入一些数据进行分析。

    > for(var i = 1; i<10000;i++) db.users.insert({userid:i,username:"lili"+i,city:"beijing"})

    > for(var i = 0; i<10000;i++) db.users.insert({userid:i,username:"xiaoming"+i,city:"changsha"})

    > for(var i = 0; i<10000;i++) db.users.insert({userid:i,username:"xiaoqiang"+i,city:"guangzhou"})

    通过以上三次循环插入文档后,第一个chunk的大小会超过64MB时,出现chunk分割与迁移的过程。再次观察集群的状态信息,字段databases值变为:

      databases:

            {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }

            {  "_id" : "eshop",  "partitioned" : true,  "primary" : "rs0" }

                    eshop.users

                            shard key: { "city" : 1 }

                            chunks:

                                    rs1     1

                                    rs0     2

                            { "city" : { "$minKey" : 1 } } -->> { "city" : "beijing"

    } on : rs1 { "t" : 2, "i" : 0 } //块区间

                            { "city" : "beijing" } -->> { "city" : "guangzhou" } on

    : rs0 { "t" : 2, "i" : 1 } //块区间

                            { "city" : "guangzhou" } -->> { "city" : { "$maxKey" : 1

    } } on : rs0 { "t" : 1, "i" : 4 } //块区间

    说明此时集群中有三个块,其中在片rs0上有两个块,在片rs1上有一个块,每个块包含一定区间范围的文档。为了更加清楚的知道这些块是如何分割和迁移的,可以查看changelog集合中的记录信息进行分析。

    从命令db.changelog.find()输出内容中可以看到有以下几步:

    第一步:分割大于64MB的块,原来此块的片键的区间范围是-,分割后区间变为-到"beijing"、"beijing"到两个区间。

    第二步:随着继续插入文档,区间"beijing"到所包含的块的大小超过64MB,此时这个区间又被分割为"beijing"到"guangzhou"、"guangzhou"到这两个区间。

    第三步:经过上面的分割,现在相当于有三个区间块了,这一步做的就是将区间-到"beijing"对应的chunk从片rs0迁移到片rs1,最终结果是分片rs0上包含"beijing"到"guangzhou"、"guangzhou"到两个区间的块,分片rs1上包含区间-到"beijing"的块。

    上面循环插入文档时还插入了片键值为"changsha"的记录,这个片键的记录应该都位于区间"beijing"到"guangzhou"所对应的chunk上,只不过由于chunk的大小还未达到64MB,所以还未进行分割,如果继续插入此片键的文档,区间可能会被分割为"beijing"到"changsha"、"changsha"到"guangzhou"这两个区间块。依次类推,mongoDB就是这样来实现海量数据的分布式存储的,同时由于每个片又是由复制集组成,保证了数据的可靠性。

  • 相关阅读:
    公用表表达式(CTE)的递归调用
    c# 如何让tooltip显示文字换行
    实战 SQL Server 2008 数据库误删除数据的恢复
    SQL SERVER数据库中 是否可以对视图进行修改删除
    asp.net中实现文件批量上传
    sql server 2008学习2 文件和文件组
    sql server 2008学习3 表组织和索引组织
    sql server 2008学习4 设计索引的建议
    sql server 2008学习10 存储过程
    .net 调用 sql server 自定义函数,并输出返回值
  • 原文地址:https://www.cnblogs.com/guoyuanwei/p/3763027.html
Copyright © 2011-2022 走看看