MongoDB--chunk的分裂和迁移

本文深入探讨MongoDB中chunk的分裂与迁移机制,解析chunk如何根据片键均匀分布于shard,阐述chunk分裂逻辑与大小调整,以及chunk迁移策略,包括基于shardtag、chunk数量、removeShard和手动移动的迁移方式。

MongoDB–chunk的分裂和迁移

一:关于chunk的分裂和分块简介

启用分片之后,数据会以chunk为单位(默认64MB,大小是1~1024MB之间)根据片键(shardKey,按照自己指定的字段作为片键)均匀的分散到后端1或多个shard上。

每个database会有一个主分片(primary shard),在数据库创建时分配。database下启用分片(即调用shardCollection命令)的集合,刚开始会生成一个[minKey, maxKey]的chunk,该chunk初始会存储在primary shard上,然后随着数据的写入,不断的发生chunk分裂及迁移。初始的minkey和maxkey是无穷大和无穷小。

在这里插入图片描述

二:chunk的分裂

1. chunk分裂的逻辑

chunk的默认大小是64MB,达到这个阈值就会发生分裂。

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;
        }
        ......
}
2. 修改chunk的大小

1.连接mongos

2.use config

3.db.settings.save({_id:“chunksize”,value:64}) //单位是MB

注意:

  • 自动分裂只在插入的时候生效
  • 如果降低了块的大小,那么可能需要一段时间才能将所有块分割为新的大小
  • 分裂不能被取消
  • chunk只会分裂,不会合并,所以即使将chunkSize改大,现有的chunk数量不会减少,但chunk大小会随着写入不断增长,直到达到目标大小。
  • 块大小的允许范围是1到1024 mb(包括1024 mb)

修改chunk大小的影响:
在这里插入图片描述

三:chunk的迁移

balancer(均衡器)负责数据的迁移,它会周期性的检查分片间是否存在不均衡,如果存在就会开始迁移。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就会自动来均衡数据。

mongos> db.chunks.find().count()
7

我这里chunk的个数是7,如果两个shard的chunk差值超过2就会发生迁移
3. removeShard触发迁移

还有一种情况会触发迁移,当用户调用removeShard命令从集群里移除shard时,Balancer也会自动将这个shard负责的chunk迁移到其他节点

4. 手动移动块
>use config

//Sh.moveChunk({“test.collecton”,{query},”shard_1”}),参数1:集合,参数2:查询条件,参数3:移动到那个分片
>sh.moveChunk("test.user",{"user_id":NumberLog("28179147024124")},shard2)

如果出现某个块的大小超出了系统指定了最大值,mongos则会拒绝移动这个块。可以使用splitAt命令对块拆分

>sh.splitAt({"user_id":NumberLog("28179147024124")})

四:对分裂和迁移的管理

1.建议chunkSize大小保持默认值

2.chunkSize太大会导致迁移变少,数据不均匀;chunksize太小会造成jumbo chunnk(shardKey 的某个取值出现频率很高,这些文档只能放到一个chunk里,无法再分裂)

3.在使用shardCollection对集合进行分片时,如果使用hash分片,可以对集合进行「预分片」,直接创建出指定数量的chunk,并打散分布到后端的各个shard,指定numInitialChunks参数在shardCollection指定初始化的分片数量,该值不能超过8192。

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

原文参考:https://blog.youkuaiyun.com/joy0921/article/details/80131276

<think>嗯,用户这次问的是"chunk块大小的定义",看起来是对不同系统中chunk概念的统一性产生了好奇。结合之前的对话历史,用户可能是在学习分布式存储或内存管理时遇到了这个术语的多义性。 用户引用了四段材料,但只有引用[3]的MongoDB部分当前问题直接相关。其他引用涉及的是完全不同的领域:引用[1][2]讲堆内存管理中的chunk,引用[4]则是音视频传输的chunk格式。需要特别注意区分这些概念。 从技术角度看,chunk大小的定义确实高度依赖上下文: 1. 在内存管理(如ptmalloc)中,chunk大小由内存分配请求决定,通常包含头部元数据用户数据区,且必须对齐到2*SIZE_SZ(64位系统常为16字节)[^1][^2] 2. 分布式文件系统(如MongoDB)的chunk是逻辑分片单元,其大小通过配置参数决定(如默认64MB),且支持动态分裂[^3] 3. 流媒体协议(如RTMP)的chunk大小是网络传输单元,通过握手协议协商确定(如默认128字节到65536字节)[^4] 用户可能真正想知道的是:为什么不同系统都叫chunk但实现差异这么大?这需要从设计目的解释:内存管理的chunk侧重减少碎片,分布式系统的chunk关注负载均衡,流媒体的chunk优化网络传输。 回答时要突出三个关键差异点:定义依据(手动配置/自动计算/协议协商)、调整机制(静态/动态)核心目标。表格对比会特别清晰,但需注意避免直接复制之前MooseFS的表格结构。 值得补充的是,虽然实现不同,但所有chunk设计都遵循两个共性:1) 作为基础操作单元 2) 包含元数据描述。这可能是用户潜在的认知连接点。</think>在不同技术领域中,“chunk块大小”的定义存在显著差异,其确定方式取决于具体应用场景系统设计目标: --- ### 一、内存管理中的chunk大小(如ptmalloc堆分配器) 1. **动态计算** chunk大小由用户请求的内存空间 $S$ 系统对齐要求决定: ```c chunk_size = ALIGN(S + sizeof(chunk_metadata), MALLOC_ALIGNMENT) ``` - `chunk_metadata`:包含前/后继块指针、大小标志等(通常占$2 \times \text{SIZE\_SZ}$字节)[^1] - `MALLOC_ALIGNMENT`:系统对齐系数(64位系统通常为16字节) 2. **最小分配单位** 实际分配的最小chunk需满足: $$ \text{chunk\_size} \geq \text{MINSIZE} = 4 \times \text{SIZE\_SZ} $$ 例如在64位Linux中:$ \text{SIZE\_SZ} = 8 \text{ bytes} \rightarrow \text{MINSIZE} = 32 \text{ bytes} $[^1] 3. **类型影响大小** | Chunk类型 | 大小特征 | |------------------|----------------------------------| | Allocated chunk | 用户数据区 + 元数据头 | | Free chunk | 额外包含前驱/后继指针(双向链表) | | Top chunk | 动态扩展的堆顶剩余空间 | --- ### 二、分布式存储中的chunk大小(如MongoDB分片) 1. **预设阈值** MongoDB默认chunk大小为 **64MB**,可通过命令调整: ```javascript db.adminCommand({ setShardSize: 128 }) // 设置为128MB ``` 2. **动态分裂机制** 当chunk内数据增长超过阈值时: ```mermaid graph LR A[Chunk数据增长] --> B{Size > 阈值?} B -->|Yes| C[自动分裂为两个新Chunk] B -->|No| D[保持原状态] ``` 3. **范围划分依据** 基于分片键(Shard Key)的值域范围划分,例如: - Chunk1: `{ _id: { $minKey: 1 } }` 到 `{ _id: 1000 }` - Chunk2: `{ _id: 1001 }` 到 `{ _id: 2000 }`[^3] --- ### 三、流媒体协议中的chunk大小(如RTMP) 1. **协商确定** 客户端与服务端通过握手协议动态协商: ```go type SetChunkSize struct { ChunkSize uint32 // 4字节字段 } ``` - 默认值:**128字节** - 可调范围:1 ~ 65535字节[^4] 2. **头部结构影响** 实际传输单元大小由Basic HeaderMessage Header共同决定: | Chunk类型 | 头部长度 | 有效载荷比例 | |----------|---------|------------| | Type 0 | 11字节 | ≈ 90% | | Type 3 | 1字节 | ≈ 99% | --- ### 关键差异总结 | 领域 | 大小定义依据 | 是否可调 | 典型值 | |--------------|---------------------------|---------------|-------------| | 内存管理 | 用户请求+对齐约束 | 隐式确定 | 32B ~ 2MB | | 分布式存储 | 系统预设+动态分裂 | 管理员配置 | 64MB~256MB | | 流媒体传输 | 协议协商+头部开销 | 会话级动态调整 | 128B~64KB | > **示例场景**:在MongoDB中,若将chunk大小从64MB改为32MB,系统会: > 1. 立即触发现存大chunk分裂 > 2. 提升数据迁移频率以实现更细粒度负载均衡[^3] ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值