MongoDB分片集群
  CXvnc1NhAWTQ 2023年11月13日 27 0

一、分片介绍

1.1 分片简介

分片(sharding)是MongoDB用来将海量数据分割到集群内不同服务器上所采用的方法。它与Redis Cluster的实现原理类似,也是将数据分成若干份,每个节点(通常为主节点,配一个或多个从节点)存一份数据即可,减轻了服务器的存储和访问压力,从而提升性能。

MongoDB分片集群_mongodb

1.2 分片的目的

复制集虽然解决了高可用的问题,但是也只是分担了主节点读操作的压力,写操作仍然在主节点完成。如此一来,高数据量和吞吐量的数据库应用会对单机的性能造成较大压力。
      为了解决这些问题,有两个基本的方法:垂直扩展和水平扩展。

  • 垂直扩展:增加更多的CPU和存储资源来扩展容量。
  • 水平扩展:将数据集分布在多个服务器上。水平扩展即分片。

1.3 分片的优缺点

1.3.1 优点

  • 保证集群总是可读写MongoDB通过多种途径来确保集群的可用性和可靠性。将MongoDB的分片和复制功能结合使用,在确保数据分片到多台服务器的同时,也确保了每分数据都有相应的备份,这样就可以确保有服务器坏掉时,其他的从库可以立即接替坏掉的部分继续工作。
  • 使集群易于扩展当系统需要更多的空间和资源的时候,MongoDB使我们可以按需方便的扩充系统容量。
  • 对集群进行抽象,让集群“不可见” MongoDB自带了一个叫做Mongos的专有路由进程。Mongos就是掌握统一路口的路由器,其会将客户端发来的请求准确无误的路由到集群中的一个或者一组服务器上,同时会把接收到的响应拼装起来发回到客户端。

1.3.2 缺点

分片额外消耗较多,约相当于单机性能的70%左右;管理复杂,尽量不要分片

1.4 分片集群架构

组件 (角色)

说明

Mongos

提供集群统一的对外应用访问入口,转发应用请求,选择合适的数据节点进行读写,合并多个数据节点的返回数据,应用的所有操作均通过Mongos执行。数据路由,和客户端打交道的模块。Mongos本身没有任何数据,它也不知道该怎么处理数据,用于寻找Config Server是无状态节点(不存数据),一般至少有2个Mongos节点。

Config Server

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

Shard

真正的数据存储位置。以复制集为单位,横向扩展,最大1024个分片,分片之间数据不重复,所有分片在一起才能可以完整的工作以Chunk为单位存数据。

Mongos本身并不持久化数据,Sharded Cluster所有的元数据都会存储到 Config Server,而用户的数据分散存储到各个Shard。Mongos启动后,会从配置服务器加载元数据,开始提供服务,将用户的请求正确路由到对应的Shard。

举个例子,有10条记录(ID为1~10)分别存放在2个分片,第一个分片存放ID为1~5的记录,第二个分片存放ID为6~10的记录。现在有用户想访问ID为8的记录,虽然Mongos收到了访问请求,但这个ID为8的记录到底在哪个分片,Mongos是不清楚的。因为它就是个代理,类似于Nginx代理。此时就需要Config Server了,可以把它理解为就是个索引数据库,它记录了哪个数据在哪个分片上。于是Mongos收到访问请求后发请求去问Config Server:这个ID为8的记录到底在哪个分片?Config Server经过查询发现ID为8的记录在第二个分片,遂告知Mongos是在第二个分片。之后Mongos就将访问请求转给第二个分片。第二个分片将ID为8的记录给Mongos,由Mongos返回给用户。

Mongos与Config Server通常消耗很少的资源,可以选择低规格虚拟机,Shard服务器消耗资源多。Shard服务器需要考虑如下问题:需要足以容纳热数据索引的内存;正确创建索引后CPU通常不会成为瓶颈。最后,建议监控各项资源使用情况,无论哪一项达到60%以上,基于以下原因则开始考虑扩展。

  • 扩展需要新的资源,申请新资源需要时间,数据量大的话,可能会长达几天时间。
  • 扩展后数据需要均衡,均衡需要时间。应保证新数据入库速度慢于均衡速度。
  • 均衡需要资源,如果资源即将或已经耗尽,均衡也是会很低效的。

1.5 分片集群的相关概念

      以下各种概念由小到大

  • 片键Shard Key:文档中的一个字段。
  • 文档Doc:包含shard key的一行数据。
  • 块Chunk:包含n个文档,默认64M。
  • 分片Shard:包含n个Chunk,一个分片对应一个复制集。
  • 集群Cluster:包含n个分片。

1.6 集群中数据分布

1.6.1 Chunk介绍

在一个Shard服务器内部,MongoDB还是会把数据分为Chunks,每个Chunk代表这个Shard 服务器内部一部分数据。Chunk的产生,会有以下两个用途:

  • 切分:当一个Chunk的大小超过配置中的Chunk Size时,MongoDB的后台进程会把这个Chunk切分成更小的Chunk,从而避免Chunk过大的情况。
  • 均衡:在MongoDB中,balancer是一个后台进程,负责Chunk的迁移,从而均衡各个Shard服务器的负载,系统初始1个Chunk,Chunk Size默认值64M,生产库上选择适合业务的Chunk Size是最好的。当存储需求超过64M时,Chunk会进行分裂,如果单位时间存储需求很大,可设置更大的Chunk。

1.6.2 Chunk分裂和迁移

随着数据的增长,其中的数据大小超过了配置的 Chunk Size,默认是64M,则这个Chunk就会分裂成两个。数据的增长会让Chunk分裂得越来越多。

MongoDB分片集群_分片集群_02

此时,各个Shard 上的Chunk数量就会不平衡。Mongos中的一个组件Balancer 就会执行自动平衡,把Chunk从Chunk数量最多的Shard节点挪动到数量最少的节点。

MongoDB分片集群_分片集群_03

ChunkSize 对分裂及迁移有啥影响?

MongoDB 默认的Chunksize为64MB,如无特殊需求,建议保持默认值;

Chunksize会直接影响到Chunk分裂、迁移的行为。 Chunksize 越小,Chunk分裂及迁移越多,数据分布越均衡;反之,Chunksize越大,Chunk分裂及迁移会更少,但可能导致数据分布不均。

Chunksize太小,容易出现 jumbo Chunk(即ShardKey的某个取值出现频率很高,这些文档只能放到一个Chunk 里,无法再分裂)而无法迁移。

ChunkSize越大,则可能出现Chunk内文档数太多(Chunk内文档数不能超过 250000)而无法迁移。

Chunk 自动分裂只会在数据写入时触发,所以如果将ChunkSize 改小,系统需要一定的时间来将Chunk分裂到指定的大小。

Chunk只会分裂,不会合并,所以即使将ChunkSize改大,现有的Chunk数量不会减少,但Chunk大小会随着写入不断增长,直到达到目标大小。

1.7 数据分片

1.7.1 分片键(Shard Key)

MongoDB中数据的分片是以集合为基本单位的,集合中的数据通过片键(Shard key)被分成多部分。其实片键就是在集合中选一个键,用该键的值作为数据拆分的依据。
      所以一个好的片键对分片至关重要。片键必须是一个索引,通过sh.shardCollection加会自动创建索引(前提是此集合不存在的情况下)。一个自增的片键对写入和数据均匀分布就不是很好,因为自增的片键总会在一个分片上写入,后续达到某个阀值可能会写到别的分片。但是按照片键查询会非常高效。
      随机片键对数据的均匀分布效果很好。注意尽量避免在多个分片上进行查询。在所有分片上查询,Mongos会对结果进行归并排序。
      对集合进行分片时,需要选择一个片键,片键是每条记录都必须包含的,且建立了索引的单个字段或复合字段,MongoDB按照片键将数据划分到不同的数据块中,并将数据块均衡地分布到所有分片中。
      为了按照片键划分数据块,MongoDB使用基于范围的分片方式或者基于哈希的分片方式。
      注意:

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

1.7.2 以范围为基础的分片(Sharded Cluster)

Sharded Cluster支持将单个集合的数据分散存储在多Shard上,用户可以指定根据集合内文档的某个字段即Shard Key来进行范围分片(Range Sharding)。优点是依据片键范围查询性能好;缺点是可能会导致数据访问不均匀,热点访问数据有可能都集中在一个或特定几个分片上。

MongoDB分片集群_mongodb_04

1.7.3 基于哈希的分片

分片过程中利用哈希索引作为分片的单个键,且哈希分片的片键只能使用一个字段,而基于哈希片键最大的好处就是保证数据在各个节点分布基本均匀。

MongoDB分片集群_mongodb_05

对于基于哈希的分片,MongoDB计算一个字段的哈希值,并用这个哈希值来创建数据块。在使用基于哈希分片的系统中,拥有”相近”片键的文档很可能不会存储在同一个数据块中,因此数据的分离性更好一些。其优点是数据分布均匀,写效率较高,适用于日志等高并发场景;缺点是范围查询效率低。

1.7.4 关于分片和分片键的选择

针对主要查询字段使用分片键作为条件查询。可以直接定位具体分片,而非所有分片响应,提高效率。

分片的基本标准:

  • 关于数据:数据量不超过3TB,尽可能保持在2TB一个片。
  • 关于索引:常用索引必须容纳进内存。

按照以上标准初步确定分片后,还需要考虑业务压力,随着压力增大,CPU、RAM、磁盘中的任何一项出现瓶颈时,都可以通过添加更多分片来解决。

二、部署分片集群

参考https://docs.mongodb.com/manual/tutorial/deploy-shard-cluster/

2.1 分片集群环境规划

以下案例准备10个实例,使用端口号:28017~28026

①Mongos节点:28017

②Config Server节点:28018~28020,3台构成的复制集(1主两从,不支持arbiter),复制集名字configsvr

③Shard节点:shard1:28021~28023 (1主两从,复制集名字shard1);shard2:28024~28026 (1主两从,复制集名字shard2)

IP

角色

192.168.131.12

Mongos--28017

Configs Server--28018~28020

192.168.131.13

Shard--shard1:28021~28023;shard2:28024~28026

2.2 配置Shard节点

2.2.1 在Shard节点创建对应的目录

mkdir -p /mongodb/{28021..28026}/{conf,data,log}

2.2.2 Shard节点的配置文件

2.2.2.1 第一个复制集shard1的搭建
vim /mongodb/28021/conf/mongodb.conf
systemLog:
 destination: file
 path: /mongodb/28021/log/mongodb.log
 logAppend: true
storage:
 dbPath: /mongodb/28021/data
net:
 bindIp: 0.0.0.0
 port: 28021
replication :
 replSetName: shard1
sharding:
 clusterRole: shardsvr
processManagement:
 fork: true
sed 's#28021#28022#g' /mongodb/28021/conf/mongodb.conf > /mongodb/28022/conf/mongodb.conf
sed 's#28021#28023#g' /mongodb/28021/conf/mongodb.conf > /mongodb/28023/conf/mongodb.conf
2.2.2.2 第二个复制集Shard2的搭建
vim /mongodb/28024/conf/mongodb.conf
systemLog:
 destination: file
 path: /mongodb/28024/log/mongodb.log
 logAppend: true
storage:
 dbPath: /mongodb/28024/data
net:
 bindIp : 0.0.0.0
 port: 28024
replication:
 replSetName: shard2
sharding:
 clusterRole: shardsvr
processManagement:
 fork: true
sed 's#28024#28025#g' /mongodb/28024/conf/mongodb.conf > /mongodb/28025/conf/mongodb.conf
sed 's#28024#28026#g' /mongodb/28024/conf/mongodb.conf > /mongodb/28026/conf/mongodb.conf

      之后启动所有Shard节点

for i in {28021..28026};do mongod -f /mongodb/$i/conf/mongodb.conf;done

搭建Shard复制集

#shard1
mongosh --port 28021
use admin
config = { _id: 'shard1', members: [{_id: 0, host: '192.168.131.13:28021'},{_id: 1, host: '192.168.131.13:28022'},{_id: 2, host: '192.168.131.13:28023' }]}
rs.initiate (config)
#shard2
mongosh --port 28024
use admin
config = { _id: 'shard2', members: [{_id: 0, host: '192.168.131.13:28024'},{_id: 1, host: '192.168.131.13:28025'},{_id: 2, host: '192.168.131.13:28026' }]}
rs.initiate (config)

2.3 配置Config Server节点

2.3.1 在Config Server节点创建对应的目录

mkdir -p /mongodb/{28018..28020}/{conf,data,log}

2.3.2 创建Config节点的配置文件

vim /mongodb/28018/conf/mongodb.conf
systemLog:
 destination: file
 path: /mongodb/28018/log/mongodb.conf
 logAppend: true
storage:
 dbPath: /mongodb/28018/data
net:
 bindIp: 0.0.0.0
 port: 28018
replication:
 replSetName: config
sharding:
 clusterRole: configsvr  #指定角色
processManagement:
 fork: true
sed 's#28018#28019#g' /mongodb/28018/conf/mongodb.conf > /mongodb/28019/conf/mongodb.conf
sed 's#28018#28020#g' /mongodb/28018/conf/mongodb.conf > /mongodb/28020/conf/mongodb.conf

之后启动所有Config Server节点

for i in {28018..28020};do mongod -f /mongodb/$i/conf/mongodb.conf;done

搭建Config Server复制集

mongosh --port 28018
use admin
config = { _id: 'config', members: [{_id: 0, host: '192.168.131.12:28018'},{_id: 1, host: '192.168.131.12:28019'},{_id: 2, host: '192.168.131.12:28020'}]}
rs.initiate (config)

注意:mongodb 3.4之后,要求config server 必须为replica set,但是不支持arbiter

2.4 配置Mongos节点

2.4.1 创建Mongos节点的目录

#注意无数据目录
mkdir -p /mongodb/28017/{conf,log}

2.4.2 Mongos的配置文件

vim /mongodb/28017/conf/mongos.conf
systemLog:
 destination: file
 path: /mongodb/28017/log/mongos.log
 logAppend: true
net:
 bindIp: 0.0.0.0
 port: 28017 #不加此行,默认监听27017
sharding:
 #这是Config Server的地址,因为要从Config Server获取元数据
 configDB: config/192.168.131.12:28018,192.168.131.12:28019,192.168.131.12:28020
processManagement:
 fork: true

2.4.3 启动Mongos程序

启动Mongos程序,需使用专门的mongos程序,而非mongod程序。

mongos -f /mongodb/28017/conf/mongos.conf

2.4.4 分片集群添加节点

#进入Mongos服务,并添加分片
mongosh --port 28017 admin
#添加分片方法一
db.runCommand({ addshard: "shard1/192.168.131.13:28021,192.168.131.13:28022,192.168.131.13:28023", name: "shard1" })
db.runCommand({ addshard: "shard2/192.168.131.13:28024,192.168.131.13:28025,192.168.131.13:28026", name: "shard2" })
#添加分片方法二
sh.addShard("shard1/192.168.131.13:28021,192.168.131.13:28022,192.168.131.13:28023")
sh.addShard("shard1/192.168.131.13:28024,192.168.131.13:28025,192.168.131.13:28026")
#列出分片
db.adminCommand({listShards: 1})

MongoDB分片集群_mongodb_06

MongoDB分片集群_mongodb_07

MongoDB分片集群_mongodb_08

2.5 配置分片规则

2.5.1 Range分片配置&测试

这里就针对test数据库设置分片规则

##连接到mongos的admin数据库激活数据库分片功能
mongosh --port 28017 admin
sh.enableSharding("test")
#或者
db.runCommand ({enablesharding: "test" })
##创建索引
use test
db.vast.createIndex({id: 1}) #针对vast表的id字段从小到大创建索引
##开启range分片
use admin
sh.shardCollection("test.vast", {id: 1})
#或者
db.runCommand({shardcollection: "test.vast",key: {id: 1}})
#插入大量数据
use test
for (i=0;i<1000000 ;i++){ db.vast.insert ( { "id" :i, "name " : "wang" , "age" : 20,"date" : new Date()})}
#分片结果测试
mongosh --port 28024
db.vast.count()

2.5.2 Hash分片的配置&测试

这里针对wxd库下的vast大表进行hash创建哈希索引

##连接到mongos的admin数据库对于wxd数据库开启分片功能
mongosh --port 28017 admin
sh.enableSharding("wxd")
##对于wxd库下的vast表建立hash索引
use wxd
db.vast.createIndex( { id: "hashed"} )
##在wxd库的vast表的id列开启hash分片
use admin
sh.shardCollection ( "wxd.vast", { id:"hashed"})
#或者
db.runCommand({shardcollection: "wxd.vast",key: {id: "hashed"}})
##插入大量数据
use wxd
for (i=0;i<1000000 ;i++){ db.vast.insert ( { "id" :i, "name " : "wang" , "age" : 20,"date" : new Date()})}
#分片结果测试。注意需要找Shard上的Primary节点
mongosh --port 28024
db.vast.count()

MongoDB分片集群_分片集群_09

三、Balance操作

Mongos的一个重要功能balancer,自动巡查所有Shard节点上的chunk的情况,自动做chunk迁移,即实现balance功能。

balance的工作时机:

  • 自动运行,当检测系统不繁忙的时候做迁移
  • 在做节点删除的时候,立即开始迁移工作
  • balancer可以指定只在预设定的时间窗口内运行

有时候需要关闭和开启balancer。比如:备份的时候进行balance会导致数据不一致,所以需要错开备份时间段。

#停止&开启 balancer
mongos> sh.stopBalancer()
mongos> sh.startBalancer()
#查询Balancer的状态
mongos>sh.getBalancerState()

还可以自定义自动平衡进行的时间段。参考https://docs.mongodb.com/manual/tutorial/manage-sharded-clusterbalancer/#schedule-the-balancing-window

#connect to mongos
mongo --port 28017 admin
use config
sh.setBalancerState(true)
sh.getBalancerState()
#设置3:00到5:00进行balance
db.settings.update({id: "balancer"},{$set: {activeWindow:{start: "3:00",stop : "5:00"}}}, true)
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月13日 0

暂无评论

推荐阅读
  CXvnc1NhAWTQ   2023年11月13日   28   0   0 mongodb分片集群
  9teav380C5it   2023年11月02日   52   0   0 DockermongodbIP
  yx99X8RMvAE0   2023年11月02日   66   0   0 mongodb数据库
  X9zksgdgaPkc   2023年11月02日   60   0   0 Docker端口号mongodb
  9JCEeX0Eg8g4   2023年11月27日   30   0   0 DatabaseSystemmongodb