Após atualizar uma instância de cluster sharded do ApsaraDB for MongoDB para o MongoDB 6,0 (versão secundária 7.0.1 ou posterior) ou para uma versão principal mais recente, a execução de sh.status() pode mostrar que as contagens de chunks estão visivelmente desiguais entre os shards, chegando a apresentar apenas um chunk por shard em alguns casos. Este tópico explica por que isso ocorre e como avaliar corretamente se os dados estão balanceados.
Sintoma
Alguns usuários relatam que, após atualizar uma instância de cluster sharded do ApsaraDB for MongoDB para o MongoDB 6,0 (versão secundária 7.0.1 ou posterior), o comando sh.status() indica que as contagens de chunks entre os shards não são mais aproximadamente iguais, diferentemente do comportamento anterior à atualização. As observações mais comuns incluem:
MongoDB 6,0 (versão secundária 7.0.1 e posteriores): As contagens de chunks variam significativamente entre os shards.
MongoDB 7.0 e posteriores: Cada shard pode conter apenas um chunk.
Você pode se perguntar:
Os dados não estão mais distribuídos uniformemente?
O balancer está com defeito?
A atualização apresentou algum erro?
Esse é o comportamento esperado após a atualização. Seus dados continuam distribuídos uniformemente e nenhuma ação é necessária. O novo balancer não utiliza mais a contagem de chunks como critério de balanceamento. Em vez disso, ele considera o tamanho real dos dados.
Por que isso acontece
Comportamento anterior ao MongoDB 6,0 versão secundária 7.0.1
Antes da versão secundária 7.0.1 do ApsaraDB for MongoDB 6,0, o cluster sharded balanceava os dados da seguinte forma:
O tamanho padrão do chunk era de 64 MB.
Quando um chunk ultrapassava 64 MB, ocorria uma divisão automática (AutoSplit) em chunks menores.
O balancer inspecionava periodicamente a contagem de chunks em cada shard e migrava chunks (
moveChunk) assim que a diferença excedia o limiar de migração.Com o tempo, cada shard passava a conter muitos chunks com contagens aproximadamente iguais.
Nesse modelo, o comando sh.status() exibia múltiplos chunks por shard, o que transmitia uma sensação intuitiva de que os dados estavam distribuídos de maneira uniforme.
Mudanças no MongoDB 6,0 a partir da versão secundária 7.0.1 (community 6.0.3)
A partir da **versão secundária 7.0.1 do ApsaraDB for MongoDB**, correspondente ao MongoDB community 6.0.3, o balancer passou a incorporar as seguintes mudanças:
Remoção do AutoSplit: Os chunks não são mais divididos automaticamente ao atingirem a capacidade máxima. A divisão ocorre apenas quando necessário, antes de uma migração.
Novo critério de balanceamento: Substituição da contagem de chunks pelo tamanho real dos dados.
Ajuste no limiar de migração: A migração é acionada quando o tamanho da mesma coleção difere em mais de três vezes o tamanho do chunk entre os shards. (O tamanho padrão do chunk no ApsaraDB for MongoDB 6,0 é de 128 MB, o que resulta em um limiar de 384 MB.)
Alteração na terminologia: O conceito de chunk perde ênfase em favor de "range". O comando
moveChunké substituído pormoveRange.Não é mais necessário executar
sh.enableSharding()antes de aplicar sharding a uma coleção.
Efeito: Como o AutoSplit foi removido e a contagem de chunks deixou de ser o critério de balanceamento, as quantidades de chunks entre os shards podem ficar desiguais, o que é normal. Para mais informações, consulte sh.enableAutoSplit().
Novidade no MongoDB 7.0: AutoMerger
O MongoDB 7.0 introduz o recurso AutoMerger:
O balancer mescla automaticamente chunks contíguos e mescláveis no mesmo shard.
O AutoMerger executa em segundo plano como parte das operações de balanceamento e vem ativado por padrão.
A execução ocorre a cada
autoMergerIntervalSecssegundos.Caso haja uma janela de balanceamento configurada, o AutoMerger opera exclusivamente dentro desse período.
Efeito: No MongoDB 7.0 e versões posteriores, o AutoMerger pode eventualmente consolidar os chunks de cada shard em um único chunk. Esse comportamento também é normal. Para mais detalhes, visualize AutoMerger.
Motivos dessas alterações
O balancer baseado em contagem de chunks nas versões anteriores apresentava várias desvantagens:
|
Problema |
Descrição |
|
Jumbo chunks |
Quando a chave de shard tem baixa cardinalidade, todos os documentos de um chunk compartilham o mesmo valor de chave, impedindo a divisão do chunk. Os shards podem terminar com a mesma contagem de chunks, mas com uso de disco muito diferente. |
|
Write skew |
Se a chave de shard do tipo range contiver um componente monotonicamente crescente, novas escritas concentram-se em um único shard. |
|
Consumo de recursos |
Operações frequentes de AutoSplit e moveChunk consomem recursos significativos de CPU e afetam o desempenho da carga de trabalho. |
Adotar o tamanho real dos dados como critério de balanceamento oferece uma visão mais precisa da distribuição de dados e reduz divisões e migrações desnecessárias de chunks.
Mapeamento de versões
|
Versão do ApsaraDB for MongoDB |
Versão Community |
Comportamento do balancer |
|
MongoDB 4.4 |
MongoDB 4.4 |
Legado: AutoSplit + balanceamento por contagem de chunks |
|
MongoDB 5.0 |
MongoDB 5.0 |
Legado: AutoSplit + balanceamento por contagem de chunks |
|
MongoDB 6,0 (versão secundária 7.0.0) |
MongoDB 6.0.0 |
Legado: AutoSplit + balanceamento por contagem de chunks |
|
MongoDB 6,0 (versão secundária 7.0.1 e posteriores) |
MongoDB 6.0.3 |
AutoSplit removido + balanceamento por tamanho (contagens de chunks podem ficar desiguais) |
|
MongoDB 7.0 e posteriores |
MongoDB 7.0+ |
AutoSplit removido + balanceamento por tamanho + AutoMerger consolida chunks |
Comparação entre versões
|
Item |
MongoDB 6,0 (antes da versão secundária 7.0.1) |
MongoDB 6,0 (versão secundária 7.0.1 e posteriores) |
MongoDB 7.0 e posteriores |
|
AutoSplit |
Ativado. Chunks divididos automaticamente ao atingirem a capacidade. |
Desativado |
Desativado |
|
AutoMerger |
Não disponível |
Não disponível |
Ativado. Chunks são mesclados automaticamente. |
|
Critério de balanceamento |
Contagem de chunks |
Tamanho real dos dados |
Tamanho real dos dados |
|
Contagem de chunks por shard |
Múltiplos, aproximadamente iguais |
Desigual, pode variar entre shards |
Pode convergir para um |
|
Limiar de migração |
Diferença na contagem de chunks ≥ 1 (MongoDB 4.2 e posteriores) |
Tamanho dos dados difere em mais de três vezes o tamanho do chunk |
Tamanho dos dados difere em mais de três vezes o tamanho do chunk |
|
|
Obrigatório antes do sharding |
Opcional no MongoDB 6,0 e posteriores |
Opcional |
|
Como avaliar o balanceamento |
Contagens de chunks via |
Tamanhos de dados via |
Tamanhos de dados via |
Dados de teste
Os resultados a seguir foram obtidos após a ferramenta YCSB inserir 50 milhões de registros em instâncias de cluster sharded do ApsaraDB for MongoDB executando MongoDB 4.4, MongoDB 6,0 e MongoDB 8.0.
MongoDB 4.4 (comportamento legado)
Execute sh.status(). Observe o campo chunkMetadata na saída. Cada shard possui 435 chunks, com contagens idênticas. Esse é o resultado do mecanismo legado de AutoSplit:
mongos> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('69fbfda6dec76b373f5eda81') }
---
shards
[
{
_id: 'd-uf6xxxx1',
host: 'mgset-1xxxxx0/192.168.XX.2:3005.192.168.XX.11:3002',
state: 1
},
{
_id: 'd-uf6xxxx2',
host: 'mgset-1xxxxx1/192.168.XX.4:3002.192.168.XX.5:3002',
state: 1
}
]
---
active mongoses
[ { '4.4.30': 2 } ]
---
autosplit
{ 'Currently enabled': 'yes' }
---
balancer
{
'Currently enabled': 'yes',
'Failed balancer rounds in last 5 attempts': 0,
'Currently running': 'no',
'Migration Results for the last 24 hours': { '947': 'Success' }
}
---
databases
[
{
database: {
_id: 'ycsb',
primary: 'd-uf6xxxx2',
partitioned: true
},
collections: {
'ycsb.test1': {
shardKey: { _id: 'hashed' },
unique: false,
balancing: true,
chunkMetadata: [
{ shard: 'd-uf6xxxx1', nChunks: 435 },
{ shard: 'd-uf6xxxx2', nChunks: 435 }
],
chunks: [
'too many chunks to print, use verbose if you want to force print'
],
tags: []
}
}
}
]
Execute db.test1.getShardDistribution(). Analise os campos data (tamanho dos dados) e chunks (contagem de chunks) de cada shard:
mongos> use ycsb
switched to db ycsb
mongos> db.test1.getShardDistribution()
Shard d-uf6xxxx1 at mgset-1xxxxx0/192.168.XX.2:3005,192.168.XX.11:3002
{
data: '27.2GiB',
docs: 25014674,
chunks: 435,
'estimated data per chunk': '64.04MiB',
'estimated docs per chunk': 57504
}
---
Shard d-uf6xxxx2 at mgset-1xxxxx1/192.168.XX.4:3002,192.168.XX.5:3002
{
data: '36.23GiB',
docs: 33313293,
chunks: 435,
'estimated data per chunk': '85.29MiB',
'estimated docs per chunk': 76582
}
---
Totals
{
data: '63.44GiB',
docs: 58327967,
chunks: 870,
'Shard d-uf6xxxx1': [
'42.88 % data',
'42.88 % docs in cluster',
'1KiB avg obj size on shard'
],
'Shard d-uf6xxxx2': [
'57.11 % data',
'57.11 % docs in cluster',
'1KiB avg obj size on shard'
]
}
MongoDB 6,0 (versão secundária 7.0.1 e posteriores)
Execute sh.status(). Verifique o campo chunkMetadata. As contagens de chunks apresentam-se visivelmente desiguais entre os shards (216 contra 1):
mongos> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('69fbfdc420578638757c1d06') }
---
shards
[
{
_id: 'd-uf6xxxx3',
host: 'mgset-1xxxxx2/192.168.XX.7:3002.192.168.XX.8:3002',
state: 1,
topologyTime: Timestamp({ t: 1778122310, i: 2 })
},
{
_id: 'd-uf6xxxx4',
host: 'mgset-1xxxxx3/192.168.XX.9:3002.192.168.XX.10:3002',
state: 1,
topologyTime: Timestamp({ t: 1778122310, i: 9 })
}
]
---
active mongoses
[ { '6.0.27': 2 } ]
---
autosplit
{ 'Currently enabled': 'yes' }
---
balancer
{
'Currently running': 'no',
'Currently enabled': 'yes',
'Failed balancer rounds in last 5 attempts': 0,
'Migration Results for the last 24 hours': { '216': 'Success' }
}
---
databases
[
{
database: {
_id: 'ycsb',
primary: 'd-uf6xxxx4',
partitioned: false,
version: {
uuid: UUID('4ee45231-9585-4dba-8f34-f624860e1a79'),
timestamp: Timestamp({ t: 1778122930, i: 1 }),
lastMod: 1
}
},
collections: {
'ycsb.test2': {
shardKey: { _id: 'hashed' },
unique: false,
balancing: true,
allowMigrations: true,
chunkMetadata: [
{ shard: 'd-uf6xxxx3', nChunks: 216 },
{ shard: 'd-uf6xxxx4', nChunks: 1 }
],
chunks: [
'too many chunks to print, use verbose if you want to force print'
],
tags: []
}
}
}
]
Execute db.test2.getShardDistribution(). Observe a porcentagem de data em cada shard. Apesar da grande diferença nas contagens de chunks (216 contra 1), os dados continuam distribuídos uniformemente (50,31% contra 49,68%):
mongos> use ycsb
switched to db ycsb
mongos> db.test2.getShardDistribution()
Shard d-uf6xxxx4 at mgset-1xxxxx3/192.168.XX.9:3002,192.168.XX.10:3002
{
data: '27.36GiB',
docs: 32285618,
chunks: 1,
'estimated data per chunk': '27.36GiB',
'estimated docs per chunk': 32285618
}
---
Shard d-uf6xxxx3 at mgset-1xxxxx2/192.168.XX.7:3002,192.168.XX.8:3002
{
data: '27.01GiB',
docs: 24841944,
chunks: 216,
'estimated data per chunk': '128.09MiB',
'estimated docs per chunk': 115009
}
---
Totals
{
data: '54.38GiB',
docs: 57127562,
chunks: 217,
'Shard d-uf6xxxx4': [
'50.31 % data',
'56.51 % docs in cluster',
'1KiB avg obj size on shard'
],
'Shard d-uf6xxxx3': [
'49.68 % data',
'43.48 % docs in cluster',
'1KiB avg obj size on shard'
]
}
MongoDB 8.0 (com AutoMerger)
Logo após a conclusão da migração, execute sh.status(). Verifique o campo chunkMetadata. Cada shard ainda apresenta múltiplos chunks (55 contra 1):
mongos> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('69fbfdbdd7b0e3d9551dd833') }
---
shards
[
{
_id: 'd-uf6xxxx5',
host: 'mgset-1xxxxx4/192.168.XX.1:3000.192.168.XX.3:3002',
state: 1,
topologyTime: Timestamp({ t: 1778122320, i: 8 }),
replSetConfigVersion: Long('-1')
},
{
_id: 'd-uf6xxxx6',
host: 'mgset-1xxxxx5/192.168.XX.5:3003.192.168.XX.6:3003',
state: 1,
topologyTime: Timestamp({ t: 1778122319, i: 10 }),
replSetConfigVersion: Long('-1')
}
]
---
active mongoses
[ { '8.0.18': 2 } ]
---
autosplit
{ 'Currently enabled': 'yes' }
---
balancer
{
'Currently enabled': 'yes',
'Failed balancer rounds in last 5 attempts': 0,
'Currently running': 'no',
'Migration Results for the last 24 hours': { '216': 'Success' }
}
---
databases
[
{
database: {
_id: 'ycsb',
primary: 'd-uf6xxxx6',
version: {
uuid: UUID('98799357-048e-45bc-a472-387165e0fe74'),
timestamp: Timestamp({ t: 1778122931, i: 2 }),
lastMod: 1
}
},
collections: {
'ycsb.test2': {
shardKey: { _id: 'hashed' },
unique: false,
balancing: true,
allowMigrations: true,
chunkMetadata: [
{ shard: 'd-uf6xxxx5', nChunks: 55 },
{ shard: 'd-uf6xxxx6', nChunks: 1 }
],
chunks: [
'too many chunks to print, use verbose if you want to force print'
],
tags: []
}
}
}
]
Após a conclusão do AutoMerger, execute sh.status() novamente. Observe o campo chunkMetadata. Agora, cada shard possui apenas um chunk:
mongos> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('69fbfdbdd7b0e3d9551dd833') }
---
shards
[
{
_id: 'd-uf6xxxx5',
host: 'mgset-1xxxxx4/192.168.XX.1:3000.192.168.XX.3:3002',
state: 1,
topologyTime: Timestamp({ t: 1778122320, i: 8 }),
replSetConfigVersion: Long('-1')
},
{
_id: 'd-uf6xxxx6',
host: 'mgset-1xxxxx5/192.168.XX.5:3003.192.168.XX.6:3003',
state: 1,
topologyTime: Timestamp({ t: 1778122319, i: 10 }),
replSetConfigVersion: Long('-1')
}
]
---
active mongoses
[ { '8.0.18': 2 } ]
---
autosplit
{ 'Currently enabled': 'yes' }
---
balancer
{
'Currently enabled': 'yes',
'Failed balancer rounds in last 5 attempts': 0,
'Currently running': 'no',
'Migration Results for the last 24 hours': { '216': 'Success' }
}
---
databases
[
{
database: {
_id: 'ycsb',
primary: 'd-uf6xxxx6',
version: {
uuid: UUID('98799357-048e-45bc-a472-387165e0fe74'),
timestamp: Timestamp({ t: 1778122931, i: 2 }),
lastMod: 1
}
},
collections: {
'ycsb.test2': {
shardKey: { _id: 'hashed' },
unique: false,
balancing: true,
allowMigrations: true,
chunkMetadata: [
{ shard: 'd-uf6xxxx5', nChunks: 1 },
{ shard: 'd-uf6xxxx6', nChunks: 1 }
],
chunks: [
{ min: { _id: MinKey() }, max: { _id: Long('-58615400192952365') }, 'on shard': 'd-uf6xxxx5', 'last modified': Timestamp({ t: 217, i: 2 }) },
{ min: { _id: Long('-58615400192952365') }, max: { _id: MaxKey() }, 'on shard': 'd-uf6xxxx6', 'last modified': Timestamp({ t: 217, i: 1 }) }
],
tags: []
}
}
}
]
Execute db.test2.getShardDistribution(). Analise a porcentagem de data. Mesmo com cada shard contendo apenas um chunk, os dados permanecem distribuídos uniformemente (49,67% contra 50,32%):
mongos> use ycsb
switched to db ycsb
mongos> db.test2.getShardDistribution()
Shard d-uf6xxxx5 at mgset-1xxxxx4/192.168.XX.1:3000,192.168.XX.3:3002
{
data: '27.01GiB',
docs: 24841944,
chunks: 1,
'estimated data per chunk': '27.01GiB',
'estimated docs per chunk': 24841944
}
---
Shard d-uf6xxxx6 at mgset-1xxxxx5/192.168.XX.5:3003,192.168.XX.6:3003
{
data: '27.37GiB',
docs: 35898246,
chunks: 1,
'estimated data per chunk': '27.37GiB',
'estimated docs per chunk': 35898246
}
---
Totals
{
data: '54.39GiB',
docs: 60740190,
chunks: 2,
'Shard d-uf6xxxx5': [
'49.67 % data',
'40.89 % docs in cluster',
'1KiB avg obj size on shard'
],
'Shard d-uf6xxxx6': [
'50.32 % data',
'59.1 % docs in cluster',
'1KiB avg obj size on shard'
]
}
Conclusão: Os dados de teste nas três versões demonstram que, independentemente das variações na contagem de chunks (870 → 217 → 2), os dados permanecem distribuídos uniformemente entre os shards. A diferença nas contagens de chunks deve-se exclusivamente a mudanças na gestão interna e não afeta a distribuição real dos dados nem sua carga de trabalho.
Como avaliar corretamente o balanceamento de dados
Após atualizar para o MongoDB 6,0 (versão secundária 7.0.1) ou posterior, utilize os métodos abaixo para avaliar o balanceamento:
Recomendado: getShardDistribution()
Conecte-se ao mongos e execute:
use <your_database>
db.<your_collection>.getShardDistribution()
Esse comando exibe o tamanho dos dados, a contagem de documentos e a porcentagem da coleção em cada shard, oferecendo uma visão precisa da distribuição.
Auxiliar: db.stats()
use <your_database>
db.stats()
Retorna o uso geral de armazenamento do banco de dados entre os shards.
Não recomendado: contagens de chunks via sh.status()
O comando sh.status() continua funcional, porém as contagens de chunks não refletem mais o balanceamento dos dados. Contagens desiguais ou um único chunk por shard são comportamentos normais e não indicam problemas na distribuição de dados.
Perguntas frequentes
P: Perderei dados se as contagens de chunks ficarem desiguais ou caírem para um após a atualização?
R: Não. Chunks são apenas uma unidade lógica interna usada pelo MongoDB para gerenciar dados. Alterações nas contagens de chunks não afetam os dados reais, que permanecem intactos em cada shard.
P: Preciso executar comandos de divisão manualmente para dividir chunks?
R: Não. O novo balancer divide os dados conforme necessário antes das migrações. Nenhuma intervenção manual é necessária.
P: O balancer continua funcionando após a atualização?
R: Sim. O balancer continua operando, mas utiliza o tamanho dos dados em vez da contagem de chunks como critério. Quando a diferença no tamanho dos dados entre os shards excede o limiar, o balancer migra os dados automaticamente.
P: Qual a diferença no comportamento de chunks entre o MongoDB 6,0 e o MongoDB 7.0 após a atualização?
R: O MongoDB 6,0 (versão secundária 7.0.1 e posteriores) remove o AutoSplit e adota o balanceamento por tamanho, de modo que as contagens de chunks entre shards podem ficar desiguais. O MongoDB 7.0 adiciona o AutoMerger, que consolida os chunks. Eventualmente, cada shard pode passar a ter um único chunk. Em ambos os casos, os dados permanecem distribuídos uniformemente.
P: É normal haver múltiplos chunks durante a migração?
R: Sim. O balancer realiza divisões necessárias durante a migração, portanto múltiplos chunks podem aparecer temporariamente. No MongoDB 7.0 e posteriores, o AutoMerger os consolida após o término da migração. No MongoDB 6,0, os chunks podem persistir, mas o balanceamento dos dados não é afetado.
P: Essa mudança afeta minha carga de trabalho?
R: Não. A alteração é transparente para as aplicações. Na prática, o novo comportamento reduz divisões e migrações desnecessárias, o que frequentemente melhora o desempenho.