MongoDB~分片数据存储Chunk;其迁移原理、影响,以及避免手段

分片数据存储:Chunk存储

Chunk(块) 是 MongoDB 分片集群的一个核心概念,其本质上就是由一组 Document 组成的逻辑数据单元。每个 Chunk 包含一定范围片键的数据,互不相交且并集为全部数据。

分片集群不会记录每条数据在哪个分片上,而是记录 Chunk 在哪个分片上,以及这个 Chunk 包含哪些分片键数据。

在这里插入图片描述
如上图,假设集合的shardKey x(以范围分片为例,哈希分片类似),写入该集合的文档根据其x的取值范围,会被分散到chunk1到chunk4中,每个chunk只包含特定范围的数据(比如chunk2就只包含x的取值在[-75, 25)范围内的文档),同一份chunk的文档只会存储在一个shard上,一个shard可能包含多个chunk,chunk会触发迁移,但具体存储在哪个shard,由记录在config server中的路由信息决定。

Chunk分裂

默认情况下,一个 Chunk 的最大值默认为 64MB(可调整,取值范围为 1~1024 MB。如无特殊需求,建议保持默认值),进行数据插入、更新、删除时,如果此时 Mongos 感知到了目标 Chunk 的大小或者其中的数据量超过上限,则会触发 Chunk 分裂
在这里插入图片描述

Chunk迁移

数据的增长会让 Chunk 分裂得越来越多。这个时候,各个分片上的 Chunk 数量可能会不平衡。Mongos 中的 均衡器(Balancer) 组件就会执行自动平衡,尝试使各个 Shard 上 Chunk 的数量保持均衡,这个过程就是 再平衡(Rebalance)。默认情况下,数据库和集合的 Rebalance 是开启的。

如下图所示,随着数据插入,导致 Chunk 分裂,让 AB 两个分片有 3 个 Chunk,C 分片只有一个,这个时候就会把 B 分配的迁移一个到 C 分片实现集群数据均衡。
在这里插入图片描述

Balancer 是 MongoDB 的一个运行在 Config Server 的 Primary 节点上(自 MongoDB 3.4 版本起)的后台进程,它监控每个分片上 Chunk 数量,并在某个分片上 Chunk 数量达到阈值进行迁移。

balancer通过特定规则来筛选出来需要进行迁移的chunk,这些规则具体是什么呢?当前,mongoDB会对以下三种类型的chunk进行迁移(优先级由高到底):

  1. chunk属于正在进行排水(即draining,一般出现在shard删除,move primary等情况下,表示该chunk需要尽快被删除)的shard

  2. chunk是否违反了zones的约束

  3. 如果不属于以上两种情况,则通过计算各个shard之间的chunks数量进行负载均衡,原则上balancer会让各个shard在满足zones约束的条件下尽可能均衡

选定了需要迁移的chunk后,balancer会选择当前shards中chunks数最少的一个作为迁移的目标。

Chunk 只会分裂,不会合并,即使 chunkSize 的值变大。

Rebalance 操作是比较耗费系统资源的,我们可以通过在业务低峰期执行:预分片或者设置 Rebalance 时间窗等方式来减少其对 MongoDB 正常使用所带来的影响。

Chunk迁移原理

chunk迁移操作通过moveChunk命令发起,moveChunk命令即可以被balancer自动调用(balancer每隔10s扫描哪些chunk需要被迁移),也支持用户主动发起

迁移chunk的整个过程实际上就是一次两个shard进行数据交换的过程,发送chunk的一方称为发送方(donorShard),接收chunk的一方称为接收方(recipientShard)。发送方和接收方通过一系列精心设计的步骤来实现chunk的迁移。

完成一次chunk迁移需要进行以下8个步骤:

  1. 发送方发起迁移: configsvr向发送方请求进行指定chunk的迁移任务(同一时刻只能执行一个chunk迁移)。如果此时发现已有一个相同的chunk的迁移任务,跳过此次迁移,否则会新发起一个迁移任务。
  2. 接收方发起chunk拷贝: 发送方进行迁移参数的校验,校验通过后,向接收方发送recvChunkStart命令,接收方进行一些传送文档数据的初始化工作后,会不断重复地向发送方发送migrateClone命令批量拉取chunk中的文档并将拉取的文档进行批量插入,即进行文档的全量拷贝。
  3. 接收方同时拉取增量修改: 文档全量拷贝完成后,接收方通过不断重复发送transferMods命令拉取chunk的增量修改(包括插入、更新、删除),并将其应用到自身。
  4. 发送方等待接收方chunk拷贝完成: 发送方不断向接收方发送 recvChunkStatus命令查询文档存量数据,以及增量同步是否完成或超时,当增量同步完成时,表示此时接受方已进入“steady”状态,可以进行接下来的流程。
  5. 发送方进入临界区: 一旦当接收方的文档数据同步完成,发送方就会进入临界区(critical section),此时发送方接下来的操作不可被打断,并且所有发送方的写操作将被挂起,直到发送方退出临界区。
  6. 接收方执行commit: 发送方进入临界区后,接下来会同步地调用recvChunkCommit命令给接收方,接收方再一次进行chunk文档的增量同步,同步完成后,向接收方返回同步完成的结果,接收方退出临界区,将挂起的写请求进行重定向。
  7. configsvr执行commit: 接收方收到同步完成的结果后,向configsvr发送configsvrCommitChunkMigration命令,表示迁移完成。(configsvrCommitChunkMigration命令返回前,发送方的读操作会被挂起)
  8. 当chunk迁移完成后,发送方还需要清理残留的chunk,这种chunk称之为孤儿chunk,孤儿chunk中的文档称为孤儿文档。一般情况孤儿chunk的删除是异步执行的(迁移完成后15分钟),每次删除128个文档,每次间隔20ms;但也可以指定waitForDelete在迁移流程中同步对孤儿chunk进行删除。 实际删除孤儿chunk前,需要判断该chunk是否能被删除

Chunk迁移的影响

性能影响

chunk迁移操作其实和普通的读写操作并无差别,虽然在迁移过程中MongoDB通过读写操作批量化一定程度上减轻了迁移的开销,但由于迁移操作是chunk级别的并发,且存在大量密集的写入和删除操作,如果恰好遇到业务高峰或累积了大量chunk需要迁移,对于性能还是有不小的影响。

MongoDB执行完一次chunk迁移,如果在之后不久刚好触发孤儿chunk的延迟删除,删除操作导致了多个次要节点的cache升高,由于节点规格较小,cache很快就超过20%,此时WT引擎会优先进行cahce evict操作进行内存释放,频繁的内存释放操作阻塞了读写,最终导致该secondary节点出现了大量慢查询。

孤儿文档的影响

一般情况下,发送方的孤儿文档会在chunk迁移后立即或延迟删除(根据waitForDelete参数来决决定),但如果chunk迁移发生了异常,以及异步删除孤儿文档有延迟,则有可能在发送方和接收方产生孤儿文档。如果用户一直是通过mongos进行分片集合的读写,那孤儿文档并不会对读写造成实际的影响。但如果用户通过直连分片集群*(当然了,这样的行为并不推荐)的shard进行读写,就会有可能发现同一个文档存在于多个shard上,出现读写不一致的现象**。

如何避免迁移

如下几点措施可以在一定程度上规避chunk自动迁移对业务的影响:

  1. 指定只在特定时间点可以进行chunk迁移(或者关闭balancer),避开业务高峰期

  2. 设置合理的分片建,保证chunk分布均匀,减少chunk迁移操作

  3. 预分片,减少chunk的迁移

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值