MongoDB进阶(二)—分片(Sharding)技术

第1章 MongoDB分片(Sharding)技术简介

1.1 分布式系统设计理念

1.1.1 分布式存储

  • 能够将大数据,按照一定的算法,均匀的分布到不同的节点上
  • 能够按照原有设计的存储策略,提取数据

1.1.2 分布式的业务系统

  • 除了实现分布式存储,还要考虑数据热点问题

1.2 Mongodb分片集群

  • 原生态的分布式集群
  • 分布式存储系统,并自带了自动分片和均衡的特性
  • 将来能不能成为一个分布式的业务系统,取决于使用者

1.2.1 分片的目的

高数据量和吞吐量的数据库应用会对单机的性能造成较大压力,大的查询量会将单机的CPU耗尽,大的数据量对单机的存储压力较大,最终会耗尽系统的内存而将压力转移到磁盘IO上。为了解决这些问题,有两个基本的方法: 垂直扩展和水平扩展。

垂直扩展:增加更多的CPU和存储资源来扩展容量。

水平扩展:将数据集分布在多个服务器上。水平扩展即分片。

图片[1]|MongoDB进阶(二)—分片(Sharding)技术|leon的博客

1.2.2 分片集群架构

图片[2]|MongoDB进阶(二)—分片(Sharding)技术|leon的博客

1.2.2.1 Config Server

存储集群所有节点、分片数据路由信息、所有存/取数据的方式、所有shard节点的信息、分片功能的一些配置信息等,可以理解为真实数据的元数据。默认需要配置3个Config Server节点。

1.2.2.2 Mongos

Mongos是数据路由,和客户端打交道的模块,提供对外应用访问,所有操作均通过mongos执行,mongos本身没有任何数据,他也不知道该怎么处理这些数据,需要去找config server处理。一般有多个mongos节点。

1.2.2.3 Mongod(shard)

存储应用数据记录,是真正的数据存储位置,以chunk为单位村粗数据。一般有多个Mongod节点以达到数据分片的目的。

1.2.3 分片集群的数据分布(shard节点)

  • 使用chunk来存储数据
  • 集群搭建完成之后,默认开启一个chunk,大小是64M,
  • 存储需求超过64M,chunk会进行分裂,如果单位时间存储需求很大,可以设置更大的chunk
  • chunk会被自动均衡迁移

图片[3]|MongoDB进阶(二)—分片(Sharding)技术|leon的博客

1.2.3.1 chunksize的选择的原则

  • 适合业务的chunksize是最好的
  • chunk的分裂和迁移:非常消耗IO资源
  • chunk分裂的时机:插入和更新时,读数据不会分裂

1.2.3.2 chunksize的选择

  • 小的chunksize:数据均衡是迁移速度快,数据分布更均匀。数据分裂频繁,路由节点消耗更多资源
  • 大的chunksize:数据分裂少。数据块移动集中消耗IO资源
  • 通常100-200M

1.3 分片策略

为了防止出现大量的chunk均衡迁移,可能造成的IO压力,我们需要设置合理分片使用策略(片键的选择、分片算法(range、hash))

1.3.1 路由和平衡

  • 当数据写入时,MongoDBCluster根据分片键设计写入数据
  • 当外部语句发起数据查询时,MongoDB根据数据分布自动路由至指定节点返回数据

1.3.2 平衡(数据分布策略)

Sharded Cluster支持将单个集合的数据分散存储在多shard上,用户可以指定根据集合内文档的某个字段即shard key来分布数据。

范围分片:

图片[4]|MongoDB进阶(二)—分片(Sharding)技术|leon的博客

1.3.2.1 Mongos均衡特性

图片[5]|MongoDB进阶(二)—分片(Sharding)技术|leon的博客

如图,第一个chunk的范围就是uid从-∞到12000范围内的数据。第二个就是12000到58000 。以此类推。对于一个刚配置为Sharding的collection ,最开始只有一个chunk,范围是从-∞到+∞。

图片[6]|MongoDB进阶(二)—分片(Sharding)技术|leon的博客

随着数据的增长,其中的数据大小超过了配置的chunk size,默认是64M,则这个chunk就会分裂成两个。数据的增长会让chunk分裂得越来越多。这时候,各个shard 上的chunk数量就会不平衡。这时候, mongos中的一个组件balancer就会执行自动平衡。把chunk从chunk数量最多的shard节点挪动到数量最少的节点。

1.3.3 Hash分片

Hash分片与范围分片互补,能将文档随机的分散到各个chunk,充分的扩展写能力,弥补了范围分片的不足,但不能高效的服务范围查询,所有的范围查询要分发到后端所有的Shard才能找出满足条件的文档。

图片[7]|MongoDB进阶(二)—分片(Sharding)技术|leon的博客

1.3.4 分片注意事项

  • 分片键是不可变
  • 分片键必须有索引
  • 分片键大小限制512bytes
  • 分片键用于路由查询
  • MongoDB不接受已进行collection级分片的collection上插入无分片键的文档(也不支持空值插入)

1.4 分片键

1.4.1 分片键介绍

  • 必须为分片collection 定义分片键
  • 基于一个或多个列(类似一个索引)
  • 分片键定义数据空间
  • 想象key space 类似一条线上一个点数据
  • 一个key range 是一条线上一段数据

图片[8]|MongoDB进阶(二)—分片(Sharding)技术|leon的博客

1.4.2 分片键选择的建议

  • 递增的sharding key
  • 数据文件挪动小。(优势)
  • 因为数据文件递增,所以会把insert的写IO永久放在最后一片上,造成最后一片的写热点。
  • 同时,随着最后一片的数据量增大,将不断的发生迁移至之前的片上。
  • 随机的sharding key
  • 数据分布均匀,insert的写IO均匀分布在多个片上。(优势)
  • 大量的随机IO,磁盘不堪重荷。
  • 混合型key
  • 大方向随机递增。
  • 小范围随机分布。

第2章 搭建及管理分片集群

提示:此分片集群是在已经安装好mongodb的基础上进行配置的,详情请参考《MongoDB基础(二)—搭建》。

2.1 搭建分片集群

2.1.1 创建实例目录及授权

[root@db01 ~]# mkdir -p /usr/local/mongodb/290{17..27}/{conf,data,log}
[root@db01 ~]# chown -R mongod.mongod /usr/local/mongodb/

2.1.2 配置shared节点

提示:开启分片集群时要先开启config server才可以开启mongos,否则会开启失败,建议开启顺序:shared—>config server—>mongos

2.1.2.1 编写配置文件

  • sh1复制集:
[root@db01 ~]# vim /usr/local/mongodb/29021/conf/mongod.yml
[root@db01 ~]# vim /usr/local/mongodb/29022/conf/mongod.yml
[root@db01 ~]# vim /usr/local/mongodb/29023/conf/mongod.yml
systemLog:
  destination: file
  path: "/usr/local/mongodb/29021/log/mongod.log"
  #path: "/usr/local/mongodb/29022/log/mongod.log"
  #path: "/usr/local/mongodb/29023/log/mongod.log"
  logAppend: true
processManagement:
  fork: true           
storage:                                                               
  journal:
     enabled: true 
  dbPath: "/usr/local/mongodb/29021/data"
  #dbPath: "/usr/local/mongodb/29022/data"
  #dbPath: "/usr/local/mongodb/29023/data"
  directoryPerDB: true
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
net:
  bindIp: 10.0.0.41
  port: 29021
  #port: 29022
  #port: 29023
replication:
  oplogSizeMB: 2048
  replSetName: sh1
sharding:
  clusterRole: shardsvr
  • sh2复制集:
[root@db01 ~]# vim /usr/local/mongodb/29024/conf/mongod.yml
[root@db01 ~]# vim /usr/local/mongodb/29025/conf/mongod.yml
[root@db01 ~]# vim /usr/local/mongodb/29026/conf/mongod.yml
systemLog:
  destination: file
  path: "/usr/local/mongodb/29024/log/mongod.log"
  #path: "/usr/local/mongodb/29025/log/mongod.log"
  #path: "/usr/local/mongodb/29026/log/mongod.log"
  logAppend: true
processManagement:
  fork: true           
storage:                                                             
  journal:
     enabled: true 
  dbPath: "/usr/local/mongodb/29024/data"
  #dbPath: "/usr/local/mongodb/29025/data"
  #dbPath: "/usr/local/mongodb/29026/data"
  directoryPerDB: true
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
net:
  bindIp: 10.0.0.41
  port: 29024
  #port: 29025
  #port: 29026
replication:
  oplogSizeMB: 2048
  replSetName: sh2
sharding:
  clusterRole: shardsvr

2.1.2.2 开启服务

[mongod@db01 ~]$ mongod -f /usr/local/mongodb/29021/conf/mongod.yml
[mongod@db01 ~]$ mongod -f /usr/local/mongodb/29022/conf/mongod.yml
[mongod@db01 ~]$ mongod -f /usr/local/mongodb/29023/conf/mongod.yml
[mongod@db01 ~]$ mongod -f /usr/local/mongodb/29024/conf/mongod.yml
[mongod@db01 ~]$ mongod -f /usr/local/mongodb/29025/conf/mongod.yml
[mongod@db01 ~]$ mongod -f /usr/local/mongodb/29026/conf/mongod.yml

2.1.2.3 配置复制集

  • 配置sh1复制集:
[mongod@db01 ~]$ mongo --host=10.0.0.41 --port=29021
config = {_id: 'sh1', members: [
                          {_id: 0, host: '10.0.0.41:29021'},
                          {_id: 1, host: '10.0.0.41:29022'},
                          {_id: 2, host: '10.0.0.41:29023',"arbiterOnly":true}]
           }
rs.initiate(config)
  • 配置sh2复制集:
[mongod@db01 ~]$ mongo --host=10.0.0.41 --port=29024
config = {_id: 'sh2', members: [
                          {_id: 0, host: '10.0.0.41:29024'},
                          {_id: 1, host: '10.0.0.41:29025'},
                          {_id: 2, host: '10.0.0.41:29026',"arbiterOnly":true}]
           }
rs.initiate(config)

2.1.3 配置config server节点

2.1.3.1 编辑配置文件

[root@db01 ~]# vim /usr/local/mongodb/29018/conf/mongod.yml

[root@db01 ~]# vim /usr/local/mongodb/29019/conf/mongod.yml
[root@db01 ~]# vim /usr/local/mongodb/29020/conf/mongod.yml
systemLog:
  destination: file
  path: "/usr/local/mongodb/29018/log/mongod.log"
  #path: "/usr/local/mongodb/29019/log/mongod.log"
  #path: "/usr/local/mongodb/29020/log/mongod.log"
  logAppend: true
processManagement:
  fork: true
storage:
  journal:
     enabled: true
  dbPath: "/usr/local/mongodb/29018/data"
  #dbPath: "/usr/local/mongodb/29019/data"
  #dbPath: "/usr/local/mongodb/29020/data"
  directoryPerDB: true
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
net:
  bindIp: 10.0.0.41
  port: 29018
  #port: 29019
  #port: 29020
replication:
  oplogSizeMB: 2048
  replSetName: configReplSet
sharding:
  clusterRole: configsvr

2.1.3.2 开启服务

[mongod@db01 ~]$ mongod -f /usr/local/mongodb/29018/conf/mongod.yml
[mongod@db01 ~]$ mongod -f /usr/local/mongodb/29019/conf/mongod.yml
[mongod@db01 ~]$ mongod -f /usr/local/mongodb/29020/conf/mongod.yml

2.1.3.3 配置configReplSet复制集

注意:mongodb 3.4之后,虽然要求config server为replica set,但是不支持arbiter。
[mongod@db01 ~]$ mongo --host=10.0.0.41 --port=29018
config = {_id: 'configReplSet', members: [
                          {_id: 0, host: '10.0.0.41:29018'},
                          {_id: 1, host: '10.0.0.41:29019'},
                          {_id: 2, host: '10.0.0.41:29020'}]
           }
rs.initiate(config)

2.1.4 配置mongos节点

2.1.4.1 编写配置文件

[root@db01 ~]# vim /usr/local/mongodb/29017/conf/mongod.yml
systemLog:
  destination: file
  path: "/usr/local/mongodb/29017/log/mongod.log"
  logAppend: true
processManagement:
  fork: true
net:
  bindIp: 10.0.0.41
  port: 29017
sharding:
  configDB: configReplSet/10.0.0.41:29018,10.0.0.41:29019,10.0.0.41:29020

2.1.4.2 开启服务

[mongod@db01 ~]$ mongos -f /usr/local/mongodb/29017/conf/mongod.yml

2.1.5 连接到mongs并添加分片信息

[mongod@db01 ~]$ mongo 10.0.0.41:29017/admin
mongos> db.runCommand( { addshard : "sh1/10.0.0.41:29021,10.0.0.41:29022,10.0.0.41:29023",name:"shard1"} )
{ "shardAdded" : "shard1", "ok" : 1 }
mongos> db.runCommand( { addshard : "sh2/10.0.0.41:29024,10.0.0.41:29025,10.0.0.41:29026",name:"shard2"} )
{ "shardAdded" : "shard2", "ok" : 1 }

2.1.6 查看分片集群配置情况

2.1.6.1 列出分片

[mongod@db01 ~]$ mongo 10.0.0.41:29017/admin
mongos> db.runCommand( { listshards : 1 } )
{
    "shards" : [
        {
            "_id" : "shard1",
            "host" : "sh1/10.0.0.41:29021,10.0.0.41:29022"
        },
        {
            "_id" : "shard2",
            "host" : "sh2/10.0.0.41:29024,10.0.0.41:29025"
        }
    ],
    "ok" : 1
}

2.1.6.2 查看整体状态

[mongod@db01 ~]$ mongo 10.0.0.41:29017/admin
mongos> sh.status()
--- Sharding Status ---
  sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("5a20ad3bf228506f1dc38231")
}
  shards:
    {  "_id" : "shard1",  "host" : "sh1/10.0.0.41:29021,10.0.0.41:29022" }
    {  "_id" : "shard2",  "host" : "sh2/10.0.0.41:29024,10.0.0.41:29025" }
  active mongoses:
    "3.2.8" : 1
  balancer:
    Currently enabled:  yes
    Currently running:  no
    Failed balancer rounds in last 5 attempts:  0
    Migration Results for the last 24 hours:
        No recent migrations
  databases:

2.2 分片集群管理操作

2.2.1 模拟业务数据

[mongod@db01 ~]$ mongo 10.0.0.41:29017/test
mongos> for(i=0;i<2000000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }         # 等待时间较长
WriteResult({ "nInserted" : 1 })

2.2.2 激活数据库分片功能

【语法】:

admin>  ( { enablesharding : "数据库名称" } )

【操作】:

[mongod@db01 ~]$ mongo 10.0.0.41:29017/admin
mongos> db.runCommand( { enablesharding : "test" } )
{ "ok" : 1 }
# 或
( { enablesharding : "数据库名称" } )

2.2.3 创建索引

从插入的数据发现业务只有id和date列,唯一值比较多的,适合做索引以及分片键,这里选择id列做索引和分片键:

[mongod@db01 ~]$ mongo 10.0.0.41:29017/admin
mongos> db.vast.ensureIndex( { id: 1 } )
{
    "raw" : {
      "configReplSet/10.0.0.41:29018,10.0.0.41:29019,10.0.0.41:29020" : {
            "createdCollectionAutomatically" : false,
            "numIndexesBefore" : 2,
            "numIndexesAfter" : 2,
            "note" : "all indexes already exist",
            "ok" : 1,
            "$gleStats" : {
                "lastOpTime" : Timestamp(1512091603, 4),
                "electionId" : ObjectId("7fffffff0000000000000001")
            }
        }
    },
    "ok" : 1
}
# 或
db.runCommand( { shardcollection : "test.vast",key : {id: 1} } )

2.2.4 创建分片键

【语法】:

admin> sh.shardCollection("数据库名称.集合名称",key : {分片键: 1}  )
或
admin> db.runCommand( { shardcollection : "数据库名称.集合名称",key : {分片键: 1} } )

【操作】:

[mongod@db01 ~]$ mongo 10.0.0.41:29017/admin
mongos> db.runCommand( { shardcollection : "test.vast",key : {id: 1} } )
{ "collectionsharded" : "test.vast", "ok" : 1 }
# 或
sh.shardCollection("test.vast",key : {id: 1}  )

2.2.5 创建哈希索引(扩展)

【语法】:

admin > sh.shardCollection( "数据库名.集合名", { 片键: "hashed" } )

【操作】:

admin> db.vast.ensureIndex( { a: "hashed" } )
admin > sh.shardCollection( "test.vast", { a: "hashed" } )

2.2.6 判断是否Shard集群

[mongod@db01 ~]$ mongo 10.0.0.41:29017/admin
mongos> db.runCommand({ isdbgrid : 1})
{ "isdbgrid" : 1, "hostname" : "db01", "ok" : 1 }

2.2.7 列出所有分片信息

[mongod@db01 ~]$ mongo 10.0.0.41:29017/admin
mongos> db.runCommand({ listshards : 1})
{
    "shards" : [
        {
            "_id" : "shard1",
            "host" : "sh1/10.0.0.41:29021,10.0.0.41:29022"
        },
        {
            "_id" : "shard2",
            "host" : "sh2/10.0.0.41:29024,10.0.0.41:29025"
        }
    ],
    "ok" : 1
}

2.2.8 列出开启分片的数据库

[mongod@db01 ~]$ mongo 10.0.0.41:29017/config
mongos> db.databases.find( { "partitioned": true } )
{ "_id" : "test", "primary" : "shard2", "partitioned" : true }

2.2.9 列出所有数据库分片情况

[mongod@db01 ~]$ mongo 10.0.0.41:29017/config
mongos> db.databases.find()
{ "_id" : "test", "primary" : "shard2", "partitioned" : true }

2.2.10 查看分片的片键

[mongod@db01 ~]$ mongo 10.0.0.41:29017/config
mongos> db.collections.find().pretty()
{
    "_id" : "test.vast",
    "lastmodEpoch" : ObjectId("5a20afdaf228506f1dc3827b"),
    "lastmod" : ISODate("1970-02-19T17:02:47.296Z"),
    "dropped" : false,
    "key" : {
        "id" : 1
    },
    "unique" : false
}

2.2.11 查看分片的详细信息

mongos> db.printShardingStatus()
或
mongos> sh.status()
--- Sharding Status ---
  sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("5a20ad3bf228506f1dc38231")
}
  shards:
    {  "_id" : "shard1",  "host" : "sh1/10.0.0.41:29021,10.0.0.41:29022" }
    {  "_id" : "shard2",  "host" : "sh2/10.0.0.41:29024,10.0.0.41:29025" }
  active mongoses:
    "3.2.8" : 1
  balancer:
    Currently enabled:  yes
    Currently running:  no
    Failed balancer rounds in last 5 attempts:  0
    Migration Results for the last 24 hours:
        7 : Success
        1 : Failed with error 'aborted', from shard2 to shard1
  databases:
    {  "_id" : "test",  "primary" : "shard2",  "partitioned" : true }
        test.vast
            shard key: { "id" : 1 }
            unique: false
            balancing: true
            chunks:
                shard1  7
                shard2  8
            { "id" : { "$minKey" : 1 } } -->> { "id" : 1 } on : shard1 Timestamp(8, 1)
            { "id" : 1 } -->> { "id" : 13 } on : shard2 Timestamp(7, 1)
            { "id" : 13 } -->> { "id" : 103576 } on : shard2 Timestamp(2, 2)
            { "id" : 103576 } -->> { "id" : 223714 } on : shard2 Timestamp(2, 3)
            { "id" : 223714 } -->> { "id" : 327277 } on : shard1 Timestamp(3, 2)
            { "id" : 327277 } -->> { "id" : 447413 } on : shard1 Timestamp(3, 3)
            { "id" : 447413 } -->> { "id" : 550976 } on : shard2 Timestamp(4, 2)
            { "id" : 550976 } -->> { "id" : 671112 } on : shard2 Timestamp(4, 3)
            { "id" : 671112 } -->> { "id" : 774675 } on : shard1 Timestamp(5, 2)
            { "id" : 774675 } -->> { "id" : 895972 } on : shard1 Timestamp(5, 3)
            { "id" : 895972 } -->> { "id" : 1103098 } on : shard2 Timestamp(6, 2)
            { "id" : 1103098 } -->> { "id" : 1373512 } on : shard2 Timestamp(6, 3)
            { "id" : 1373512 } -->> { "id" : 1580638 } on : shard1 Timestamp(7, 2)
            { "id" : 1580638 } -->> { "id" : 1861821 } on : shard1 Timestamp(7, 3)
            { "id" : 1861821 } -->> { "id" : { "$maxKey" : 1 } } on : shard2 Timestamp(8, 0)

2.3 节点管理操作

2.3.1 添加节点(分片)

[mongod@db01 ~]$ mongo 10.0.0.41:29017/admin
mongos> db.runCommand( { addshard : "sh1/10.0.0.41:29021,10.0.0.41:29022,10.0.0.41:29023",name:"shard1"} )
{ "shardAdded" : "shard1", "ok" : 1 }

2.3.2 删除节点(分片)

注意:由于删除节点会产生chunk迁移,所以删除节点时间视数据量大小而定,并且删除节点的时候不要再做其他操作,防止数据库发生未知错误。
[mongod@db01 ~]$ mongo 10.0.0.41:29017/admin
mongos> db.runCommand( { removeShard: "shard2" } )
{
    "msg" : "draining started successfully",
    "state" : "started",        # 删除开始
    "shard" : "shard2",
    "note" : "you need to drop or movePrimary these databases",
    "dbsToMove" : [
        "test"
    ],
    "ok" : 1
}
mongos> db.runCommand( { removeShard: "shard2" } )
{
    "msg" : "draining ongoing",
    "state" : "ongoing",        # 删除进行中
    "remaining" : {
        "chunks" : NumberLong(8),
        "dbs" : NumberLong(1)
    },
    "note" : "you need to drop or movePrimary these databases",
    "dbsToMove" : [
        "test"
    ],
    "ok" : 1
}
mongos> db.runCommand( { removeShard: "shard2" } )
{
    "msg" : "removeshard completed successfully",
    "state" : "completed",      # 删除完成
    "shard" : "shard2",
    "ok" : 1
}

2.4 balance管理操作

2.4.1 查看balance状态

[mongod@db01 ~]$ mongo 10.0.0.41:29017/admin
mongos> sh.getBalancerState()
true

2.4.2 关闭和启动balance(不要随意操作)

mongo 10.0.0.41:29017/admin
mongos> sh.stopBalancer()
Waiting for active hosts...
Waiting for the balancer lock...
Waiting again for active hosts after balancer is off...
mongos> sh.getBalancerState()
false
mongos> sh.startBalancer()
mongos> sh.getBalancerState()
true

2.4.3 定义balancer的工作窗口(很重要)

mongo 10.0.0.41:29017/admin
mongos>db.settings.update({ _id : "balancer" }, { $set : { activeWindow : { start : "00:00", stop : "5:00" } } }, true )
提示:设置时间窗口的原则:1、避开业务繁忙期;2、避开备份时间窗口

2.4.4 关于集合的balance(很少用到)

2.4.4.1 关闭某个集合的balance

sh.disableBalancing("students.grades")

2.4.4.2 打开某个集合的balance

sh.enableBalancing("students.grades")

2.4.4.3 确定某个集合的balance是开启或者关闭

db.getSiblingDB("config").collections.findOne({_id : "students.grades"}).noBalance;
温馨提示:本文最后更新于2022-12-20 20:57:50,已超过523天没有更新。某些文章具有时效性,若文章内容或图片资源有错误或已失效,请联系站长。谢谢!
转载请注明本文链接:https://blog.leonshadow.cn/763482/852.html
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享