(1.4)mongodb sh,mongodb分片集群

【1】mongodb 分片集群介绍

转自官网:https://www.mongodb.com/docs/manual/sharding/

MongoDB通过sharding支持水平扩展

一个 MongoDB分片集群由以下组件组成:

  • shard:每个分片包含分片数据的一个子集。每个分片都可以部署为副本集
  • mongosmongos充当查询路由器,在客户端应用程序和分片集群之间提供接口。从 MongoDB 4.4 开始,mongos可以支持 对冲读取以最小化延迟。
  • config servers:配置服务器存储集群的元数据和配置设置。

下图描述了分片集群中组件的交互:

用于生产目的的示例分片集群图。 恰好包含 3 个配置服务器、2 个或更多“mongos”查询路由器,以及至少 2 个分片。 分片是副本集。

MongoDB 在集合级别对数据进行分片,将集合数据分布在集群中的各个分片上。

MongoDB 使用分片将集合的文档分布在分片之间。分片键由文档中的一个或多个字段组成。

  • 从版本 4.4 开始,分片集合中的文档可能会缺少分片键字段。在跨分片分布文档时,缺失的分片键字段被视为具有空值,但在路由查询时则不会。有关更多信息,请参阅 缺少分片键字段
  • 在 4.2 及更早的版本中,分片集合的每个文档中都必须存在分片键字段。

您在对集合进行分片时选择分片键。

  • 从 MongoDB 5.0 开始,您可以通过更改集合的分片键来重新分片集合。
  • 从 MongoDB 4.4 开始,您可以通过向现有分片添加一个或多个后缀字段来优化分片键。
  • 在 MongoDB 4.2 及更早版本中,分片后无法更改分片键的选择。

文档的分片键值决定了它在分片中的分布。

  • 从 MongoDB 4.2 开始,您可以更新文档的 shard key 值,除非您的 shard key 字段是不可变_id字段。有关详细信息,请参阅 更改文档的分片键值
  • 在 MongoDB 4.0 及更早版本中,文档的分片键字段值是不可变的。

(1.3)分片键索引、分片密钥策略

  要对填充的集合进行分片,该集合必须具有 以分片键开头的索引。对空集合进行分片时,如果集合还没有指定分片键的适当索引,则 MongoDB 会创建支持索引。请参阅 分片键索引

  分片键的选择会影响分片集群的性能、效率和可扩展性。具有最佳硬件和基础设施的集群可能会因选择分片键而受到瓶颈。分片键及其后备索引的选择也会影响集群可以使用的分片策略。

提示

也可以看看:

选择一个分片键

MongoDB 将分片数据分成(64M)每个块都有一个基于 shard key的包含下限和互斥上限。

为了在集群中的所有分片上实现块的均匀分布,平衡器在后台运行以跨分迁移

也就是说,一波数据写入,这部分所有数据一开始只放入到一个分片,完成后自动平衡器在后台运行,慢慢的根据判断平衡一部分数据到其他分片节点

提示
也可以看看:

使用块进行数据分区

  自动分片:4.2 之前,所有数据都在主节点,然后在后台自动分片迁移到对应的分片节点

  

 

MongoDB在分集群中的分片之间分配读写工作负载 ,允许每个分片处理集群操作的子集。通过添加更多分片,读写工作负载都可以在集群中水平扩展。

对于包含分片键或复合分片键前缀的查询,mongos可以将查询定位到特定分片或分片集。这些有针对性的操作通常比 广播到集群中的每个分片更有效。

从 MongoDB 4.4 开始,mongos可以支持对冲读取以最小化延迟。

 

片将数据分布在集群中的分片上,允许每个分片包含整个集群数据的一个子集。随着数据集的增长,额外的分片会增加集群的存储容量。

 

将配置服务器和分片部署为副本集提供了更高的可用性。

即使一个或多个分片副本集完全不可用,分片集群也可以继续执行部分读写。也就是说,虽然无法访问不可用分片上的数据,但针对可用分片的读取或写入仍然可以成功。

分片集群基础设施要求和复杂性需要仔细规划、执行和维护。

一旦一个集合被分片,MongoDB 就不会提供对一个分片集合进行分片的方法。

虽然您可以稍后重新分片您的集合 ,但请务必仔细考虑您的分片键选择以避免可伸缩性和性能问题。

详细参考:选择一个分片键

 

要了解对集合进行分片的操作要求和限制,请参阅分片集群中的操作限制

如果查询不包括分片键或复合分片键的前缀 ,则mongos执行广播操作,查询 分片集群中的所有分片。这些分散/收集查询可能是长时间运行的操作。

(1.7)分片和非分片集合

数据库可以混合有分片和非分片集合。分片集合被分区并分布在 集群中的分片上。未分片的集合存储在 分片上。每个数据库都有自己的主分片。

  

 

(1.8)连接到分片集群

  您必须连接到mongos路由器才能与分片集群中的任何集合进行交互。这包括分片非分片集合。客户端不应连接到单个分片以执行读取或写入操作。

  

 

 您可以使用或 MongoDB驱动程序mongos连接到相同的方式 mongodmongosh

【分片策略】

MongoDB 支持两种分片策略,用于跨分片集群分布数据。

Hashed Sharding)

哈希散列分片涉及计算分片键字段值的散列。然后根据哈希散列的分片键值为每个块分配一个范围。

MongoDB 在使用哈希散列索引解析查询时会自动计算散列值。应用程序不需要计算哈希。

  

 

 

虽然一系列分片键可能“接近”,但它们的散列值不太可能在同一个上。基于散列值的数据分布有助于更均匀的数据分布,尤其是在分片键单调变化的数据集中。

但是,散列分布意味着对分片键的基于范围的查询不太可能针对单个分片,从而导致更多集群范围的 广播操作

有关详细信息,请参阅散列分片

(Ranged Sharding)

范围分片涉及根据分片键值将数据划分为范围。然后根据分片键值为每个块分配一个范围。

  

 

  值“接近”的一系列分片键更有可能驻留在同一个上。这允许有针对性的操作,因为mongos可以将操作路由到仅包含所需数据的分片。

  远程分片的效率取决于选择的分片键。考虑不周的分片键会导致数据分布不均匀,这可能会抵消分片的一些好处或导致性能瓶颈。有关基于范围的分片,请参阅 分片键选择

  有关详细信息,请参阅远程分片

(Zones in Sharded Clusters)

区域可以帮助改善跨多个数据中心的分片集群的数据局部性。

  在分片集群中,您可以根据shard key创建分片数据区域您可以将每个区域与集群中的一个或多个分片相关联。一个分片可以与任意数量的区域相关联。平衡集群中,MongoDB仅将区域覆盖的迁移到与该区域关联的分片。

  每个区域涵盖一个或多个分片键值范围。区域覆盖的每个范围始终包括其下边界,但不包括其上边界。

可以应用区域的一些常见部署模式如下:

  • 隔离特定分片集上的特定数据子集。
  • 确保最相关的数据驻留在地理上距离应用程序服务器最近的分片上。
  • 根据分片硬件的硬件/性能将数据路由到分片。

下图说明了具有三个分片和两个区域的分片集群。

  该A区域表示一个范围,其下限为1,上限为10

  该B区域表示一个范围,其下边界为10,上边界为20

  分片AlphaBeta拥有A区域。ShardBeta也有该B区域。

  ShardCharlie 没有与之关联的区域。集群处于稳定状态,没有任何块违反任何区域。

  

 

  在定义要覆盖的区域的新范围时,您必须使用分片键中包含的字段。

  如果使用复合分片键,范围必须包含分片键的前缀。有关更多信息,请参阅区域中的分片键。

【2】搭建 mongodb sh 分片集群

(2.0)架构规划

10个实例:38017-38026

(0)mongos:38017

(1)configserver:38018-38020

  3台构成复制集(1主2从,不支持 arbiter)38018-38020(复制集名字 configserver)

(2)shard 节点:

sh1: 38021-23 (1主2从,其中一个节点为 arbiter,复制集名字为 sh1 )

sh2: 38024-26 (1主2从,其中一个节点为 arbiter,复制集名字为 sh2 )

 

(2.1)Shard 节点的搭建

可以支持 PSS(1主2从)、PSA(1主1从+纯投票节点 ARBITER)

<1> 6个节点的文件和配置信息:

# 构造实例目录

mkdir -p /data/mongodb/{38017,38018,38019,38020,38021,38022,38023,38024,38025,38026}/{data,log}
useradd mongodb -s /sbin/false

# 构造配置文件

cat <<eof >/data/mongodb/38021/mongod.conf
systemLog:
  destination: file
  path: /data/mongodb/38021/log/mongodb.log
  logAppend: true
storage:
  journal:
    enabled: true
  dbPath: /data/mongodb/38021/data
  directoryPerDB: true
  #engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
processManagement:
  fork: true
net:
  bindIp: 0.0.0.0
  port: 38021
replication:
  oplogSizeMB: 2048
  replSetName: sh1
sharding:
clusterRole: shardsvr eof # 构造不同实例的配置文件 cp
/data/mongodb/38021/mongod.conf /data/mongodb/38022/mongod.conf cp /data/mongodb/38021/mongod.conf /data/mongodb/38023/mongod.conf cp /data/mongodb/38021/mongod.conf /data/mongodb/38024/mongod.conf cp /data/mongodb/38021/mongod.conf /data/mongodb/38025/mongod.conf cp /data/mongodb/38021/mongod.conf /data/mongodb/38026/mongod.conf sed -i 's#38021#38022#g' /data/mongodb/38022/mongod.conf sed -i 's#38021#38023#g' /data/mongodb/38023/mongod.conf sed -i 's#38021#38024#g' /data/mongodb/38024/mongod.conf sed -i 's#38021#38025#g' /data/mongodb/38025/mongod.conf sed -i 's#38021#38026#g' /data/mongodb/38026/mongod.conf sed -i 's#: sh1#: sh2#g' /data/mongodb/38024/mongod.conf sed -i 's#: sh1#: sh2#g' /data/mongodb/38025/mongod.conf sed -i 's#: sh1#: sh2#g' /data/mongodb/38026/mongod.conf # 启动多个实例 chown -R mongodb:mongodb /data/mongodb chmod -R 775 /data/mongodb su - mongodb -c "/usr/local/mongodb/bin/mongod --config /data/mongodb/38021/mongod.conf &" su - mongodb -c "/usr/local/mongodb/bin/mongod --config /data/mongodb/38022/mongod.conf &" su - mongodb -c "/usr/local/mongodb/bin/mongod --config /data/mongodb/38023/mongod.conf &" su - mongodb -c "/usr/local/mongodb/bin/mongod --config /data/mongodb/38024/mongod.conf &" su - mongodb -c "/usr/local/mongodb/bin/mongod --config /data/mongodb/38025/mongod.conf &" su - mongodb -c "/usr/local/mongodb/bin/mongod --config /data/mongodb/38026/mongod.conf &"

# 查阅
ps -ef|grep mongod
netstat -nltp|grep 3802

# 快速清理
rm -rf /data/mongodb/{38021,38022,38023,38024,38025,38026}/{data,log}/*

<2> 初始化 sh1 sh2 2个复制集

# 构造 sh1

mongo --port 38021 admin

config = { _id: 'sh1', members: [
  {_id: 0, host: '192.168.191.25:38021'},
  {_id: 1, host: '192.168.191.25:38022'},
  {_id: 2, host: '192.168.191.25:38023', "arbiterOnly": true}]
}


rs.initiate(config) // 初始化后,登录上会显示是主还是从 ,如:my_repl:PRIMARY> 
rs.status() // 查看集群所有描述
rs.isMaster()  // 查看集群成员,以及当前节点是否是
rs.conf() // 查看一下集群的配置信息,比如成员的权重、是否是投票节点等等
quit()

# 构造 sh2

mongo --port 38024 admin

config = { _id: 'sh2', members: [
  {_id: 0, host: '192.168.191.25:38024'},
  {_id: 1, host: '192.168.191.25:38025'},
  {_id: 2, host: '192.168.191.25:38026', "arbiterOnly": true}]
}


rs.initiate(config) // 初始化后,登录上会显示是主还是从 ,如:my_repl:PRIMARY> 
rs.status() // 查看集群所有描述
rs.isMaster()  // 查看集群成员,以及当前节点是否是
rs.conf() // 查看一下集群的配置信息,比如成员的权重、是否是投票节点等等
quit()

 

(2.2)configserver 节点配置

可以支持 PSS(1主2从)、不支持 PSA(1主1从+纯投票节点 ARBITER)

<1> 配置文件与信息

# 构造实例目录

mkdir -p /data/mongodb/{38017,38018,38019,38020,38021,38022,38023,38024,38025,38026}/{data,log}
useradd mongodb -s /sbin/false

# 构造配置文件

cat <<eof >/data/mongodb/38018/mongod.conf
systemLog:
  destination: file
  path: /data/mongodb/38018/log/mongodb.log
  logAppend: true
storage:
  journal:
    enabled: true
  dbPath: /data/mongodb/38018/data
  directoryPerDB: true
  #engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
processManagement:
  fork: true
net:
  bindIp: 0.0.0.0
  port: 38018
replication:
  oplogSizeMB: 2048
  replSetName: configReplSet
sharding:
  clusterRole: configsvr
eof

#  构造不同实例的配置文件

cp /data/mongodb/38018/mongod.conf /data/mongodb/38019/mongod.conf
cp /data/mongodb/38018/mongod.conf /data/mongodb/38020/mongod.confsed -i 's#38018#38019#g' /data/mongodb/38019/mongod.conf
sed -i 's#38018#38020#g' /data/mongodb/38020/mongod.conf

# 启动多个实例
chown -R mongodb:mongodb /data/mongodb
chmod -R 775 /data/mongodb
su - mongodb -c "/usr/local/mongodb/bin/mongod --config /data/mongodb/38018/mongod.conf &"
su - mongodb -c "/usr/local/mongodb/bin/mongod --config /data/mongodb/38019/mongod.conf &"
su - mongodb -c "/usr/local/mongodb/bin/mongod --config /data/mongodb/38020/mongod.conf &"

# 查阅
ps -ef|grep mongod
netstat -nltp|grep 380

# 快速清理
rm -rf /data/mongodb/{38018,38019,38020}/{data,log}/*

<2> 初始化复制集

# 构造 configReplSet

mongo --port 38018 admin

config = { _id: 'configReplSet', members: [
  {_id: 0, host: '192.168.191.25:38018'},
  {_id: 1, host: '192.168.191.25:38019'},
  {_id: 2, host: '192.168.191.25:38020'}]
}


rs.initiate(config) // 初始化后,登录上会显示是主还是从 ,如:my_repl:PRIMARY> 
rs.status() // 查看集群所有描述
rs.isMaster()  // 查看集群成员,以及当前节点是否是
rs.conf() // 查看一下集群的配置信息,比如成员的权重、是否是投票节点等等
quit()

(2.3)mongos 节点配置(必须最后做)

用 38017 做该路由节点

cat <<eof >/data/mongodb/38017/mongod.conf
systemLog:
  destination: file
  path: /data/mongodb/38017/log/mongodb.log
  logAppend: true
processManagement:
  fork: true
net:
  bindIp: 0.0.0.0
  port: 38017
sharding:
  configDB: configReplSet/192.168.191.25:38018,192.168.191.25:38019,192.168.191.25:38020
eof

chown -R mongodb:mongodb /data/mongodb
chmod -R 775 /data/mongodb
su - mongodb -c "/usr/local/mongodb/bin/mongos --config /data/mongodb/38017/mongod.conf &"

(2.4)分片集群添加节点

连接到一个 mongos ( 192.168.191.25:38017 ) 做如下操作配置:

mongo 192.168.191.25:38017/admin

// (1)添加分片
db.runCommand({ addshard: "sh1/192.168.191.25:38021,192.168.191.25:38022,192.168.191.25:38023"})
db.runCommand({ addshard: "sh2/192.168.191.25:38024,192.168.191.25:38025,192.168.191.25:38026"})

// (2)列出所有分片信息
db.runCommand({ listshards: 1 })

// (3)整体状况查看
sh.status()

  

【3】实际分片的配置使用

分片策略见前文

(3.0)运维查阅使用命令

# (1)构建 库、表分片
// (1.1)打开 test 库的分片功能
use admin
db.runCommand(  { enablesharding: "autoshard" })

// (1.2)给该集合的 id 列 加个索引(btree)
use autoshard
db.autotable.ensureIndex({ id: 1 })

// (1.3)配置分片集合,以及分片 Key
use admin
db.runCommand({ shardcollection: "autoshard.autotable",key: {id: 1} })
sh.shardCollection( "zonedb.zonetab",{order_id: 1}) // 与上面等同

// (1.4)查看数据信息
db.autotable.getShardDistribution()   // 表数据在分片节点的分布情况
sh.status() // 所有 分片集群相关情况

// (1.5)删除分片节点(谨慎,严重影响业务)
sh.getBalancerState() // 确认 balance 是否在工作
db.runCommand({removeShard: "sh2"}) // 删除操作一定会立即出发 balance,把数据迁移到其他分片节点


#(2)查看分片集群相关信息
// 查看分片集群、分片节点信息
use admin
db.runCommand({ isdbgrid: 1}) // 判断是否是 shard 集群
db.runCommand({ listshards: 1}) // 列出所有分片信息

// 列出开启分配的数据库
use config
db.databases.find({"partitioned": true}) 
db.databases.find() // 列出所有数据库分片情况

// 查看分片的 分片键
db.collections.find().pretty()

// 上面所有信息都可以
sh.status() // 列出所有分配信息
 

 

(3.1)range 自动分片配置及测试

登录 mongos

mongo --port 38017 admin

  原理:所有数据都在主节点,然后在后台自动平衡器会把数据迁移到对应的分片节点;

  注意,如果是 range 分区,那么相同的 分区键值会存放到同一个分片节点上去

那么当 range 分区键列如果重复率很高,会导致数据存放非常不均匀;

// (1)打开 test 库的分片功能
use admin
db.runCommand(  { enablesharding: "autoshard" })

// (2)给该集合的 id 列 加个索引(btree)
use autoshard
db.autotable.ensureIndex({ id: 1 })

// (3)配置分片集合,以及分片 Key
use admin
db.runCommand({ shardcollection: "autoshard.autotable",key: {id: 1} })

// (4)构建测试数据
use autoshard
for(i=1;i<10000;i++){ db.autotable.insert({"id": i,"name": "zhangsan","age": 70,"date": new Date()})}
db.autotable.getShardDistribution()
// 如下图,我们可以发现,所有数据都在分区2中,但因为只有一个 chunks 所以没有迁移到到其他节点,又因为一个chunks 64MB大小
  

 

 

(3.2)Zones 方式进行 range 手动定制分片

登录 mongos

mongo --port 38017 admin

// (1)打开 test 库的分片功能
use admin
db.runCommand(  { enablesharding: "zonedb" })

// (2)给该集合的 id 列 加个索引(btree)
use zonedb
db.zonetab.ensureIndex({ order_id: 1 })

// (3)配置分片集合,以及分片 Key
use admin
sh.shardCollection( "zonedb.zonetab",{order_id: 1})

// (4)每个分片,添加一个 tag
sh.addShardTag("sh1","zonedb_zonetable_min_500")
sh.addShardTag("sh2","zonedb_zonetable_501_max")
sh.status() // 可以查看到
  
// (5)把 tag 对应其范围
sh.addTagRange(
"zonedb.zonetab",
{"order_id": MinKey },
{"order_id": 500 },"zonedb_zonetable_min_500"
)
sh.addTagRange(
"zonedb.zonetab",
{"order_id": 501 },
{"order_id": MaxKey},"zonedb_zonetable_501_max"
)
// (6)构建测试数据
use zonedb
for(i=1;i<1000;i++){ db.zonetab.insert({"order_id": i,"name": "zhangsan","age": 70,"date": new Date()})}

// (7)查看分片分布
use zonedb db.zonetab.stats()
db.zonetab.getShardDistribution()
  

(3.3)hash 分片 案例

先登录 mongos,然后操作

mongo --port 38017 admin

 

// (1)打开 test 库的分片功能
use admin
db.runCommand(  { enablesharding: "hashdb" })

// (2)给该集合的 id 列 加个索引(btree)
use hashdb
db.hashtab.ensureIndex({ id: "hashed" })

// (3)配置分片集合,以及分片 Key
use admin
sh.shardCollection("hashdb.hashtab",{id: "hashed"})

// (4)构建测试数据
use hashdb
for(i=1;i<600;i++){ db.hashtab.insert({"id": i,"name": "zhangsan","age": 70,"date": new Date()})}

db.hashtab.getShardDistribution()
// 如下图,插入了600行数据进去,hash分区基本是均匀的
  

【4】Balancer 自动平衡器介绍

(4.1)Balancer  的触发情况

mongs 的一个重要功能,自动巡查所有 shard 节点上的 chunk 的情况,自动做 chunk迁移;

什么时候工作、触发?

  1、自动运行,会检测系统不繁忙的时候做迁移

  2、在做节点删除的时候,立即开始迁移工作

  3、balancer 可以设置在预定的时间窗口内运行

有时候需要可以关闭和开启 blancer(备份的时候)

sh.stopBalancer()

sh.startBalancer()

(4.2)自定义 Balancer 自动平衡的时间段

# 关于整体的 balancer 策略

use config
sh.getBalancerState()
sh.setBalancerState( true )

sh.getBalancerWindow()  // 操作前,查看 balancer 计划
db.settings.update({_id: "balancer"},{$set:{activeWindow:{start: "3:00" , stop: "5:00"}}},true) // 建议避开高峰期和备份时间
sh.getBalancerWindow()  // 操作后,查看 balancer 计划
sh.status() // 这个在 balancer 模块也可以看到


# 关于集合级别的 balancer
sh.disableBalancing("students.grades") // 关闭某个库下集合的 balancer
sh.enableBalancing("students.grades") // 打开某个库下集合的 balancer
db.getSiblingDB("config").collections.findOne({_id: "students.grades"}).noBalance;

 

posted @ 2022-05-01 18:29  郭大侠1  阅读(204)  评论(0编辑  收藏  举报