MongoDB sharding chunk 分裂与迁移详解

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS SQL Server,基础系列 2核4GB
简介:
MongoDB

MongoDB Sharding

关于 MongoDB sharding 的原理,如果不了解请先参考

注:本文的内容基于 mongoDB 3.2 版本。

Primary shard

使用 MongoDB sharding 后,数据会以 chunk 为单位(默认64MB)根据 shardKey 分散到后端1或多个 shard 上。

每个 database 会有一个 primary shard,在数据库创建时分配

  • database 下启用分片(即调用 shardCollection 命令)的集合,刚开始会生成一个[minKey, maxKey] 的 chunk,该 chunk 初始会存储在 primary shard 上,然后随着数据的写入,不断的发生 chunk 分裂及迁移,整个过程如下图所示。
  • database 下没有启用分片的集合,其所有数据都会存储到 primary shard

_2017_05_30_7_11_09

何时触发 chunk 分裂?

mongos 上有个 sharding.autoSplit 的配置项,可用于控制是否自动触发 chunk 分裂,默认是开启的。如无专业人士指导,强烈建议不要关闭 autoSplit,更好的方式是使用「预分片」的方式来提前分裂,后面会详细介绍。

mongoDB 的自动 chunk 分裂只会发生在 mongos 写入数据时,当写入的数据超过一定量时,就会触发 chunk 的分裂,具体规则如下。

int ChunkManager::getCurrentDesiredChunkSize() const {
    // split faster in early chunks helps spread out an initial load better
    const int minChunkSize = 1 << 20;  // 1 MBytes

    int splitThreshold = Chunk::MaxChunkSize;  // default 64MB

    int nc = numChunks();

    if (nc <= 1) {
        return 1024;
    } else if (nc < 3) {
        return minChunkSize / 2;
    } else if (nc < 10) {
        splitThreshold = max(splitThreshold / 4, minChunkSize);
    } else if (nc < 20) {
        splitThreshold = max(splitThreshold / 2, minChunkSize);
    }

    return splitThreshold;
} 

bool Chunk::splitIfShould(OperationContext* txn, long dataWritten) const {
    dassert(ShouldAutoSplit);
    LastError::Disabled d(&LastError::get(cc()));

    try {
        _dataWritten += dataWritten;
        int splitThreshold = getManager()->getCurrentDesiredChunkSize();
        if (_minIsInf() || _maxIsInf()) {
            splitThreshold = (int)((double)splitThreshold * .9);
        }

        if (_dataWritten < splitThreshold / ChunkManager::SplitHeuristics::splitTestFactor)
            return false;

        if (!getManager()->_splitHeuristics._splitTickets.tryAcquire()) {
            LOG(1) << "won't auto split because not enough tickets: " << getManager()->getns();
            return false;
        }
        ......
}

chunkSize 为默认64MB是,分裂阈值如下

集合 chunk 数量 分裂阈值
1 1024B
[1, 3) 0.5MB
[3, 10) 16MB
[10, 20) 32MB
[20, max) 64MB

写入数据时,当 chunk 上写入的数据量,超过分裂阈值时,就会触发 chunk 的分裂,chunk 分裂后,当出现各个 shard 上 chunk 分布不均衡时,就会触发 chunk 迁移。

何时触发 chunk 迁移?

默认情况下,MongoDB 会开启 balancer,在各个 shard 间迁移 chunk 来让各个 shard 间负载均衡。用户也可以手动的调用 moveChunk 命令在 shard 之间迁移数据。

Balancer 在工作时,会根据shard tag集合的 chunk 数量shard 间 chunk 数量差值 来决定是否需要迁移。

(1)根据 shard tag 迁移

MongoBD sharding 支持 shard tag 特性,用户可以给 shard 打上标签,然后给集合的某个range 打上标签,mongoDB 会通过 balancer 的数据迁移来保证「拥有 tag 的 range 会分配到具有相同 tag 的 shard 上」。

(2)根据 shard 间 chunk 数量迁移

int threshold = 8;
if (balancedLastTime || distribution.totalChunks() < 20)
    threshold = 2;
else if (distribution.totalChunks() < 80)
    threshold = 4;
集合 chunk 数量 迁移阈值
[1, 20) 2
[20, 80) 4
[80, max) 8

针对所有启用分片的集合,如果 「拥有最多数量 chunk 的 shard」 与 「拥有最少数量 chunk 的 shard」 的差值超过某个阈值,就会触发 chunk 迁移; 有了这个机制,当用户调用 addShard 添加新的 shard,或者各个 shard 上数据写入不均衡时,balancer 就会自动来均衡数据。

(3)removeShard 触发迁移

还有一种情况会触发迁移,当用户调用 removeShard 命令从集群里移除shard时,Balancer 也会自动将这个 shard 负责的 chunk 迁移到其他节点,因 removeShard 过程比较复杂,这里先不做介绍,后续专门分析下 removeShard 的实现。

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 大小会随着写入不断增长,直到达到目标大小。

如何减小分裂及迁移的影响?

mongoDB sharding 运行过程中,自动的 chunk 分裂及迁移如果对服务产生了影响,可以考虑一下如下措施。

(1)预分片提前分裂

在使用 shardCollection 对集合进行分片时,如果使用 hash 分片,可以对集合进行「预分片」,直接创建出指定数量的 chunk,并打散分布到后端的各个 shard。

指定 numInitialChunks 参数在 shardCollection 指定初始化的分片数量,该值不能超过 8192。

Optional. Specifies the number of chunks to create initially when sharding an empty collection with a hashed shard key. MongoDB will then create and balance chunks across the cluster. The numInitialChunks must be less than 8192 per shard. If the collection is not empty, numInitialChunks has no effect.

如果使用 range 分片,因为 shardKey 的取值不确定,预分片意义不大,很容易出现部分 chunk 为空的情况,所以 range 分片只支持 hash 分片。

(2)合理配置 balancer

monogDB 的 balancer 能支持非常灵活的配置策略)来适应各种需求

  • Balancer 能动态的开启、关闭
  • Blancer 能针对指定的集合来开启、关闭
  • Balancer 支持配置时间窗口,只在制定的时间段内进行迁移

参考资料

MongoDB
相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
6月前
|
SQL DataWorks NoSQL
DataWorks报错问题之datax mongodb全量迁移报错如何解决
DataWorks是阿里云提供的一站式大数据开发与管理平台,支持数据集成、数据开发、数据治理等功能;在本汇总中,我们梳理了DataWorks产品在使用过程中经常遇到的问题及解答,以助用户在数据处理和分析工作中提高效率,降低难度。
|
存储 域名解析 监控
『MongoDB』MongoDB高可用部署架构——分片集群篇(Sharding)
📣读完这篇文章里你能收获到 - 为什么要使用分片 - Mongodb分片集群有哪些特点 - Mongodb分片集群的完整架构 - Mongodb分片集群数据分布方式 - Mongodb分片集群的设计思路 - Mongodb分片集群搭建及扩容 - 这篇文章强烈建议收藏!!!免得下次找不到
3629 2
『MongoDB』MongoDB高可用部署架构——分片集群篇(Sharding)
|
1月前
|
NoSQL MongoDB 数据库
使用NimoShake将数据从AWS DynamoDB迁移至阿里云MongoDB
使用NimoShake将数据从AWS DynamoDB迁移至阿里云MongoDB
|
3月前
|
JSON NoSQL Ubuntu
在Ubuntu 14.04上如何备份、恢复和迁移MongoDB数据库
在Ubuntu 14.04上如何备份、恢复和迁移MongoDB数据库
93 1
|
3月前
|
NoSQL MongoDB 数据库
DTS 的惊天挑战:迁移海量 MongoDB 数据时,捍卫数据准确完整的生死之战!
【8月更文挑战第7天】在数字化时代,大数据量的MongoDB迁移至关重要。DTS(数据传输服务)通过全面的数据评估、可靠的传输机制(如事务保证一致性)、异常处理(如回滚或重试),以及迁移后的数据校验来确保数据准确无损。DTS还处理数据转换与映射,即使面对不同数据库结构也能保持数据完整性,为企业提供可靠的数据迁移解决方案。
66 2
|
4月前
|
DataWorks NoSQL fastjson
DataWorks操作报错合集之DataX进行MongoDB全量迁移的过程中,DataX的MongoDB Reader插件在初始化阶段找不到Fastjson 2.x版本的类库,该怎么办
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
5月前
|
存储 数据采集 NoSQL
DTS在迁移大数据量的MongoDB数据库时如何保证数据的准确性和完整性?
【6月更文挑战第4天】DTS在迁移大数据量的MongoDB数据库时如何保证数据的准确性和完整性?
144 1
|
存储 NoSQL 分布式数据库
MongoDB性能系列最佳实践-Sharding
MongoDB将会推出一系列介绍MongoDB性能最佳实践的文章,旨在帮助用户在多个关键方面实现规模化性能优化。
MongoDB性能系列最佳实践-Sharding
|
数据采集 NoSQL 容灾
如何实现MongoDB数据的快速迁移?
为解决用户面临的 MongoDB 迁移问题,玖章算术旗下的云原生智能数据管理平台 NineData 推出了 MongoDB 业务不停服数据迁移能力。NineData 实现了完全自动化的全量数据迁移,以及增量数据的采集复制能力。
|
存储 NoSQL Oracle
「数据库选型」卫报从MongoDB迁移到Amazon RDS上的PostgreSQL
「数据库选型」卫报从MongoDB迁移到Amazon RDS上的PostgreSQL