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.csdn.net/joy0921/article/details/80131276