• 结合MongoDB分片实践谈谈自己的看法


    0、集群部署

    Deploy Sharded Cluster using Hashed Sharding
    Deploy Sharded Cluster using Ranged Sharding

    我使用了三台服务器系统:

    角色 replicaSetName 10.96.180.204 10.98.200.197 10.98.200.198 端口
    Config Server config PRIMARY SECONDARY SECONDARY 21000
    Shard Server 1 shard1 SECONDARY PRIMARY SECONDARY 27001
    Shard Server 2 shard2 PRIMARY SECONDARY SECONDARY 27002
    Shard Server 3 shard3 SECONDARY SECONDARY PRIMARY 27003

    另外,每台服务器上都启动了一个 mongos,端口号为 20000;
    因此,每台服务器上都启动了 4 个 mongod 进程和 1 个 mongos 进程;

    下表是我列出的操作命令和结果检查命令,一一对应;

    登入 执行命令 检查命令 描述
    ./bin/mongo 127.0.0.1:27001/admin
    ./bin/mongo 127.0.0.1:27002/admin
    ./bin/mongo 127.0.0.1:27003/admin
    ./bin/mongo 127.0.0.1:21000/admin
    rs.initiate() rs.status(),members数组其中一个成员的stateStr是PRIMARY 初始化副本集
    ./bin/mongo 127.0.0.1:20000/admin sh.addShard() sh.status(),关注 shards: 变化 添加分片到集群
    ./bin/mongo 127.0.0.1:20000/admin sh.enableSharding() sh.status(),关注 databases: 变化 为数据库启用分片
    ./bin/mongo 127.0.0.1:20000/<collection_name> sh.shardCollection() db.<collection_name>.getShardDistribution(),可以看到每个分片所包含的数据量 使用哈希/范围切分对集合进行分片

    1、初始化副本集

    比如,用 MONGODB_HOME 下的 ./bin/mongo 登入分片服务器 shard1 并连接到 admin 库:

    ./bin/mongo 127.0.0.1:27001/admin
    

    接着,用 rs.initiate() 初始化 shard1 副本集:

    rs.initiate(
      {
        _id : shard1,
        members: [
          { _id : 0, host : "10.98.200.198:27001" },
          { _id : 1, host : "10.98.200.197:27001" },
          { _id : 2, host : "10.96.180.204:27001" }
        ]
      }
    )
    

    类似地,初始化 shard2 集群的副本集:

    1. ./bin/mongo 127.0.0.1:27001/admin 中的端口替换为 27002
    2. 把 rs.initiate 括号中的 _idhost 中的 27001 端口替换为 shard2 和 27001;

    初始化 shard3 集群的副本集也是同理:

    1. ./bin/mongo 127.0.0.1:27001/admin 中的端口 27001 替换为 27003
    2. 把 rs.initiate 括号中的 _idhost 中的 27001 端口替换为 shard3 和 27003;

    初始化 config 集群的副本集操作也类似:

    1. ./bin/mongo 127.0.0.1:21000/admin 中的端口 27001 替换为 21000
    2. 把 rs.initiate 括号中的 _idhost 中的 27001 端口替换为 config 和 21000;

    查看副本集状态 members

    经过选举,会从三台中选出一台 PRIMARY,另外两台没选上的则是 SECONDARY,可以通过 rs.status() 命令查看谁才是“主”;

    经测试发现,如果你在哪台服务器上执行“初始化副本集”操作,大概率就是这台被选为“主”;

    2、添加分片到集群

    首先确保你已经启动了路由层(mongos进程),接着仍然是用 ./bin/mongo 登录路由层:

    ./bin/mongo 127.0.0.1:20000/admin
    

    20000 是在启动 mongos 指定的端口

    登陆后执行 sh.addShard() 命令来为集群添加分片

    sh.addShard( "<replSetName>/10.96.180.204:<port>,10.98.200.197:<port>,10.98.200.198:<port>")
    

    可以替换的 replSetName 和 port 的组合如下三个:

    replSetName port
    shard1 27001
    shard2 27002
    shard3 27003

    查看副本集状态 shards:

    可以使用 sh.status() 或者 db.printShardingStatus() 命令打印出的 shards: 查看所有分片的情况:

    3、为数据库启用分片

    sh.enableSharding 是在 ./bin/mongo 登入路由层后操作的:

    ./bin/mongo 127.0.0.1:20000/admin
    

    接着就是通过 sh.enableSharding("<database>") 为数据库开启分片,执行之后,副本集状态 databases: 会新增一条记录:

    {  "_id" : "<database>",  "primary" : "<replicaSetName>",  "partitioned" : true }
    

    自然是 shards: 所列的分片中一个分片的 _id,partitioned 表示已分区或者已分片的意思。

    4、使用哈希/范围切分对集合进行分片

    https://www.mongodb.com/docs/v3.4/tutorial/deploy-sharded-cluster-hashed-sharding/#shard-a-collection-using-hashed-sharding
    https://www.mongodb.com/docs/v3.4/tutorial/deploy-sharded-cluster-ranged-sharding/#shard-a-collection-using-ranged-sharding
    如果你仔细读 MongoDB Sharding 中以上两小节,不难发现 sh.shardCollection("<database>.<collection>", { <key> : <direction> } ) 是需要先有索引的!

    具体操作是:

    sh.shardCollection("<database>.<collection>", { <key> : <direction> } )
    

    如果集合还没有数据

    在集合设计之初,就考虑分片的话,可以直接执行 sh.shardCollection

    sh.shardCollection("<database>.<collection>", { <key> : <direction> } )
    

    例如,以下是我的一次执行结果:

    mongos> sh.shardCollection("ott_shms_prd.temp_user_scale_data", {"custNum":"hashed"})
    { "collectionsharded" : "ott_shms_prd.temp_user_scale_data", "ok" : 1 }
    

    使用 db.<collection_name>.getIndexes() 查询该集合上的索引,系统自动为我们创建了索引 custNum_hashed:

    mongos> db.temp_user_scale_data.getIndexes()
    [
            {
                    "v" : 2,
                    "key" : {
                            "_id" : 1
                    },
                    "name" : "_id_",
                    "ns" : "ott_shms_prd.temp_user_scale_data"
            },
            {
                    "v" : 2,
                    "key" : {
                            "custNum" : "hashed"
                    },
                    "name" : "custNum_hashed",
                    "ns" : "ott_shms_prd.temp_user_scale_data"
            }
    ]
    

    如果集合为空,MongoDB 会在执行 sh.shardCollection() 时创建索引。

    使用 db.<collection_name>.getShardDistribution() 看一下分片的数据情况:

    mongos> db.temp_user_scale_data.getShardDistribution()
    
    Shard shard1 at shard1/10.96.180.204:27001,10.98.200.197:27001,10.98.200.198:27001
     data : 0B docs : 0 chunks : 2
     estimated data per chunk : 0B
     estimated docs per chunk : 0
    
    Shard shard2 at shard2/10.96.180.204:27002,10.98.200.197:27002,10.98.200.198:27002
     data : 0B docs : 0 chunks : 2
     estimated data per chunk : 0B
     estimated docs per chunk : 0
    
    Shard shard3 at shard3/10.96.180.204:27003,10.98.200.197:27003,10.98.200.198:27003
     data : 0B docs : 0 chunks : 2
     estimated data per chunk : 0B
     estimated docs per chunk : 0
    
    Totals
     data : 0B docs : 0 chunks : 6
     Shard shard1 contains NaN% data, NaN% docs in cluster, avg obj size on shard : NaNGiB
     Shard shard2 contains NaN% data, NaN% docs in cluster, avg obj size on shard : NaNGiB
     Shard shard3 contains NaN% data, NaN% docs in cluster, avg obj size on shard : NaNGiB
    

    如果集合中已经有数据了

    那么,你直接调用 sh.shardCollection 会报错,因为你需要先创建索引 db.collection.createIndex()

    1. 创建一个与你要进行分片的 key 相同的索引,即 db.<collection_name>.createIndex( { <key> : <direction> } ), key 和 direction 都相同;
    2. 另一种方式,就是你创建的索引,需以你要分片的 key 为前缀,即 db.<collection_name>.createIndex( { <key> : <direction>, <other_key> : <other_direction> } )

    先创建索引,再对集合执行分片,操作结果如下:

    mongos> db.user_scale_data.createIndex({"custNum" : 1,"uuid" : 1})
    {
            "raw" : {
                    "shard1/10.96.180.204:27001,10.98.200.197:27001,10.98.200.198:27001" : {
                            "createdCollectionAutomatically" : false,
                            "numIndexesBefore" : 2,
                            "numIndexesAfter" : 3,
                            "ok" : 1,
                            "$gleStats" : {
                                    "lastOpTime" : {
                                            "ts" : Timestamp(1655282005, 1),
                                            "t" : NumberLong(1)
                                    },
                                    "electionId" : ObjectId("7fffffff0000000000000001")
                            }
                    }
            },
            "ok" : 1
    }
    mongos> sh.shardCollection("ott_shms_prd.user_scale_data",{"custNum" : 1})
    { "collectionsharded" : "ott_shms_prd.user_scale_data", "ok" : 1 }
    

    执行完分片命令后,第一次查看分片情况:

    mongos> db.user_scale_data.getShardDistribution()
    
    Shard shard1 at shard1/10.96.180.204:27001,10.98.200.197:27001,10.98.200.198:27001
     data : 923.18MiB docs : 89322 chunks : 29
     estimated data per chunk : 31.83MiB
     estimated docs per chunk : 3080
    
    Shard shard2 at shard2/10.96.180.204:27002,10.98.200.197:27002,10.98.200.198:27002
     data : 131.88MiB docs : 12301 chunks : 4
     estimated data per chunk : 32.97MiB
     estimated docs per chunk : 3075
    
    Shard shard3 at shard3/10.96.180.204:27003,10.98.200.197:27003,10.98.200.198:27003
     data : 129.74MiB docs : 12283 chunks : 4
     estimated data per chunk : 32.43MiB
     estimated docs per chunk : 3070
    
    Totals
     data : 1.15GiB docs : 113906 chunks : 37
     Shard shard1 contains 77.91% data, 78.41% docs in cluster, avg obj size on shard : 10KiB
     Shard shard2 contains 11.13% data, 10.79% docs in cluster, avg obj size on shard : 10KiB
     Shard shard3 contains 10.95% data, 10.78% docs in cluster, avg obj size on shard : 10KiB
    

    第二次查看分片情况:

    mongos> db.temp_user_scale_data.getShardDistribution()
    
    Shard shard1 at shard1/10.96.180.204:27001,10.98.200.197:27001,10.98.200.198:27001
     data : 399.14MiB docs : 38596 chunks : 13
     estimated data per chunk : 30.7MiB
     estimated docs per chunk : 2968
    
    Shard shard2 at shard2/10.96.180.204:27002,10.98.200.197:27002,10.98.200.198:27002
     data : 385.91MiB docs : 36909 chunks : 12
     estimated data per chunk : 32.15MiB
     estimated docs per chunk : 3075
    
    Shard shard3 at shard3/10.96.180.204:27003,10.98.200.197:27003,10.98.200.198:27003
     data : 384.55MiB docs : 36913 chunks : 12
     estimated data per chunk : 32.04MiB
     estimated docs per chunk : 3076
    
    Totals
     data : 1.14GiB docs : 112418 chunks : 37
     Shard shard1 contains 34.12% data, 34.33% docs in cluster, avg obj size on shard : 10KiB
     Shard shard2 contains 32.99% data, 32.83% docs in cluster, avg obj size on shard : 10KiB
     Shard shard3 contains 32.87% data, 32.83% docs in cluster, avg obj size on shard : 10KiB
    

    观察结论一:为有数据的集合创建分片后,MongoDB 会“渐进式”地把单个分片上的数据转移到其他分片上,并且最终,各个分片上的数据量和文档数都趋于平均值;
    观察结论二:如果多个有数据的集合,都执行了 sh.shardCollection,不会同时发生迁移,会按照“先后顺序”依次进行数据迁移。

  • 相关阅读:
    利用条件信号量设计读写锁
    高效编程之互斥锁和自旋锁的一些知识
    高效编程之指针跳转的影响
    高效编程之cache命中对于程序性能的影响
    SQL Server中使用自定义指定顺序排序
    Vue使用,异步获取日期时间后格式成"/Date(1333245600000+0800)/" 转换成正常格式
    技术胖-胜洪宇关注web前端技术
    百度editor编辑器添加新字体
    mvc4中的 webapi 的使用方式
    js特效不错的网站
  • 原文地址:https://www.cnblogs.com/kendoziyu/p/16378007.html
Copyright © 2020-2023  润新知