MongoDB: Sharding: Escalonamento horizontal
Última atualização: 2026-08-26
Os clusters fragmentados são a solução definitiva para o escalonamento horizontal no MongoDB — dominá-los permite que você lide com dados na escala de petabytes.
1. O que você vai aprender
- Conceito de sharding (escalonamento horizontal)
- Estratégias de seleção de chaves de fragmentos
- Divisão e migração de blocos
- Segmentação por intervalo versus segmentação por hash
- Servidor de configuração + Mongos + arquitetura de fragmentação
- Configurando um cluster fragmentado do Docker
2. Arquitetura fragmentada
Explicação do conceito: O sharding é a solução de escalonamento horizontal do MongoDB — ele distribui os dados por vários shards, sendo que cada um deles é um conjunto de réplicas independente. As aplicações acessam os dados de forma transparente por meio do roteamento do Mongos, sem precisar saber como os dados estão distribuídos. Quando um único servidor atinge sua capacidade máxima ou o limite de taxa de transferência de gravação, o sharding é a única maneira de escalar.
Como funciona: O Mongos atua como um roteador de consultas. Após receber uma solicitação do aplicativo, ele recupera os metadados dos shards (quais chunks estão em quais shards) do Config Server, encaminha a solicitação ao shard de destino para execução e mescla os resultados antes de retorná-los. O código do aplicativo é idêntico ao de um MongoDB de nó único — o particionamento é transparente para o aplicativo.
Três componentes principais:
graph TB
App[Applications] --> M[Mongos<br/>Query Route<br/>Stateless]
M --> CS[Config Server<br/>Configuration Information<br/>3Node Replica Set]
M --> S1[Shard 1<br/>Shard Node 1<br/>Dungeon Collection]
M --> S2[Shard 2<br/>Shard Node 2<br/>Dungeon Collection]
M --> S3[Shard 3<br/>Shard Node 3<br/>Dungeon Collection]
subgraph "Data Flow"
Q[Query Request] --> M
M -->|Metadata Query| CS
M -->|Data Query| S1
M -->|Data Query| S2
M -->|Data Query| S3
end
style M fill:#cce5ff
style CS fill:#fff3cd
style S1 fill:#d4edda
style S2 fill:#d4edda
style S3 fill:#d4edda
| Componente | Responsabilidades | Requisitos de implantação |
|---|---|---|
| Mongos | Roteamento de consultas, transparência da aplicação | Sem estado, suporta múltiplas instâncias |
| Servidor de configuração | Armazena metadados do shard (configuração do cluster) | Deve ser um conjunto de réplicas (3 nós) |
| Shard | Armazena os dados propriamente ditos (cada shard é um conjunto de réplicas) | Conjunto de réplicas com pelo menos 3 nós |
Shards x Conjuntos de réplicas:
| Dimensão | Conjunto de réplicas | Cluster de fragmentos |
|---|---|---|
| Objetivo | Alta disponibilidade (HA) | Escalonamento horizontal + HA |
| Dados | Cada nó armazena o conjunto de dados completo | Os dados são distribuídos por vários fragmentos |
| Escalabilidade de gravação | Nenhuma (todas as gravações são direcionadas ao primário) | ✅ Gravações distribuídas entre vários shards |
| Escalabilidade de leitura | Balanceamento de carga de leitura secundária | ✅ Consultas paralelas em múltiplos fragmentos |
| Complexidade operacional | Média | Alta |
| Escala adequada | < 1 TB | > 1 TB / > 10 mil operações/s |
3. Estratégias de seleção de chaves de particionamento
Explicação do conceito: Uma chave de fragmentação é o campo que determina como os dados são distribuídos entre os fragmentos — ela afeta diretamente o desempenho das consultas, o equilíbrio dos dados e a escalabilidade. Uma vez definida, uma chave de fragmentação não pode ser modificada; escolher a chave de fragmentação errada é um dos erros arquitetônicos mais graves.
Como funciona: O MongoDB divide os dados em blocos (64 MB por padrão) com base na chave de fragmentação, sendo que cada bloco é atribuído a um fragmento específico. A fragmentação por intervalo divide os dados com base em intervalos de valores da chave de fragmentação, enquanto a fragmentação por hash divide os dados com base nos valores de hash da chave de fragmentação. Durante uma consulta, o Mongos usa a chave de fragmentação para localizar o fragmento que contém o bloco alvo, evitando assim consultas de difusão.
Regras do ESRT para a seleção da chave de particionamento:
| Ordem | Tipo | Descrição | Exemplo |
|---|---|---|---|
| Equalidade | Filtragem por igualdade de valores | Priorizar userId, _id | find({userId: 'u001'}) |
| Ordenação | Campo de ordenação | createdAt, etc. | sort({createdAt: -1}) |
| Range | Consulta de intervalo | Selecionar intervalos frequentes | {price: {$gte: 100}} |
| Tempo | Tendência temporal | Dados da série temporal | {createdAt: 1} |
Quatro características de uma boa chave de partição:
| Recurso | Descrição | Causa |
|---|---|---|
| Linha de base elevada | Grande número de valores únicos | Os dados podem ser divididos em partes mais detalhadas |
| Atualizações pouco frequentes | Os valores raramente mudam | Alterar a chave de fragmentação exige a migração de blocos, o que consome muitos recursos |
| Resultado da consulta | As condições da consulta incluem a chave de fragmento | O Mongos oferece suporte ao roteamento direcionado para evitar a transmissão em massa |
| Distribuição uniforme | Os valores estão distribuídos uniformemente | Evite fragmentos com picos de carga |
(1) Segmentação por intervalo (particionamento por intervalo)
Explicação do conceito: O particionamento por intervalo divide os blocos com base na ordem natural dos valores da chave de particionamento — intervalos de valores consecutivos são colocados no mesmo bloco. Isso é adequado para consultas por intervalo e ordenação, mas pode facilmente levar à concentração de dados (hotspots).
Princípio: O particionamento por intervalo divide o intervalo de valores da chave de fragmento em intervalos contíguos [min, splitPoint1), [splitPoint1, splitPoint2), ..., sendo que cada intervalo corresponde a um bloco. Documentos com valores adjacentes são colocados no mesmo bloco → no mesmo fragmento.
// === Enable Sharding ===
sh.enableSharding('shopdb');
// === Selecting a Sharding Key:User ID Scope ===
sh.shardCollection('shopdb.orders', { userId: 1 });
// userId 1-1000 → Shard 1
// userId 1001-2000 → Shard 2
| Dimensão | Fragmentos de Alcance | Descrição |
|---|---|---|
| Consulta de intervalo | ✅ Eficiente | Dados consecutivos no mesmo fragmento |
| Classificação | ✅ Eficiente | Os índices são ordenados naturalmente |
| Distribuição de dados | ⚠️ Possível distorção | Teclas de atalho concentradas em um único fragmento |
| Cenários adequados | Séries temporais, intervalo de IDs | createdAt, userId |
(2) Fragmentos com hash
Explicação do conceito: O sharding com hash calcula um hash para a chave de shard e divide os blocos com base em intervalos de valores de hash. Os dados são distribuídos uniformemente, sem pontos de concentração, mas as consultas por intervalo exigem uma transmissão para todos os shards.
// === Hash Sharding ===
sh.shardCollection('shopdb.products', { sku: 'hashed' });
// sku Hash values are evenly distributed across the shards
| Dimensão | Fragmento com hash | Descrição |
|---|---|---|
| Distribuição de dados | ✅ Uniforme | Espalhados naturalmente pela função hash |
| Distribuição de gravação | ✅ Uniforme | Sem pontos de concentração |
| Consulta de intervalo | ❌ Requer transmissão | Valores adjacentes estão em shards diferentes |
| Cenários adequados | Principalmente consultas de igualdade | SKU, e-mail, ID do usuário |
(3) Comparação por intervalo versus comparação por hash
| Dimensão | Intervalo | Hash |
|---|---|---|
| Distribuição de dados | Possível assimetria | Uniforme |
| Consulta de intervalo | ✅ Rota de destino | ❌ Transmissão para todos os shards |
| Consulta de equivalência | ✅ | ✅ |
| Classificação | ✅ Indexado em ordem | ❌ |
| Pontos de aquecimento | ⚠️ Pontos de aquecimento em um único local | ✅ Uniforme |
| Chaves fragmentadas compostas | ✅ Compatível | ❌ Apenas campo único |
(4) Como escolher a melhor chave de particionamento
// ✅ Good Sharding Key:High base figure、Infrequent Updates、Query hits
sh.shardCollection('shopdb.orders', { userId: 1, createdAt: -1 });
// Composite Segmented Key,userId Scope + Sort by Time
// ❌ Invalid Shard Key:Low base
sh.shardCollection('shopdb.products', { category: 1 });
// category Only 5 a value,It will tilt severely
Anti-padrão de chave de partição:
| Anti-padrão | Consequências | Melhores práticas |
|---|---|---|
| Campo de valor baixo (por exemplo, categoria) | Asimetria grave nos dados | Selecionar campo de valor alto (userId) |
| Campo que aumenta monotonamente (como ObjectId) | Todos os novos dados são gravados no mesmo fragmento | Use uma chave de fragmentação com hash ou composta |
| Campos com atualizações frequentes | Migração frequente de blocos | Selecionar campos com atualizações pouco frequentes |
| Não está nos critérios de consulta | Todas as transmissões de consulta | Selecionar campos de consulta de alta frequência |
4. Divisão e migração de blocos
Explicação do conceito: Um chunk é a menor unidade de gerenciamento de dados fragmentados — 64 MB por padrão — e contém todos os documentos cujas chaves de fragmento se enquadram em um intervalo específico. Os chunks são divididos automaticamente quando excedem um limite e são migrados automaticamente quando o número de chunks não é igual entre os fragmentos. Esse é o mecanismo central por trás do balanceamento automático de carga do MongoDB.
Como funciona:
- Divisão: Quando um chunk ultrapassa 64 MB (ou o número de documentos ultrapassa o limite configurado), o Mongos identifica a mediana da chave de fragmentação e divide o chunk em dois.
- Migração: O Balancer verifica periodicamente o número de blocos em cada fragmento e migra blocos dos fragmentos com mais blocos para aqueles com menos, até que a carga esteja equilibrada.
Como funciona um equalizador:
graph TB
subgraph "Equalizer Workflow"
A[Check eachShard<br/>ChunkQuantity] --> B{Gap>8?}
B -->|Yes| C[Select Migration Source Shard<br/>(Chunk with the most)]
C --> D[Select a Migration DestinationShard<br/>(ChunkThe fewest)]
D --> E[MigrationChunk]
E --> F[UpdateConfig Server<br/>Metadata]
F --> A
B -->|No| G[Wait for the next check<br/>Default 10 seconds]
end
style E fill:#cce5ff
style F fill:#d4edda
graph LR
A[Chunk 1<br/>1-1000] -->|Split| B[Chunk 1a<br/>1-500]
A -->|Split| C[Chunk 1b<br/>501-1000]
C -->|Migration| D[Shard 2]
style B fill:#d4edda
style D fill:#fff3cd
Comandos de bloco:
| Operação | Comando | Descrição |
|---|---|---|
| Dividir manualmente | sh.splitAt(ns, key) |
Dividir no par chave-valor especificado |
| Visualizar distribuição | db.col.getShardDistribution() |
Volume de dados por fragmento |
| Status do cluster | sh.status() |
Detalhes da distribuição de blocos |
| Status do equalizador | sh.isBalancerRunning() |
A equalização está em andamento? |
| Equalizador Start-Stop | sh.startBalancer() / sh.stopBalancer() |
Pode ser pausado durante os intervalos de manutenção |
| Alterar tamanho do bloco | db.settings.save({_id:'chunksize', value: 128}) |
Unidade: MB |
// === Manual Split Chunk ===
sh.splitAt('shopdb.orders', { userId: 5000 });
// === View Chunk Distribution ===
db.orders.getShardDistribution();
// === Balancer Status ===
sh.status();
sh.isBalancerRunning();
Análise dos pontos-chave:
- A divisão de blocos é uma operação lógica (modifica apenas os metadados) e não move os dados; a migração de blocos é uma operação física (copia efetivamente os dados).
- O equalizador é executado em segundo plano e não afeta as operações de leitura/gravação durante a migração (utilizando gravações duplas para garantir a consistência).
- Durante os períodos de manutenção (como importações em lote), recomenda-se pausar o equalizador para evitar que a migração afete o desempenho da importação.
▶ Exemplo 1: Gerenciamento do equalizador e divisão manual de blocos
// ShopHub:Pause the equalizer before importing a large batch,Restore After Import
// 1. Pause Equalizer
sh.stopBalancer();
// 2. Bulk Import Data
for (let i = 0; i < 1000000; i++) {
db.orders.insertOne({ userId: 'user_' + (i % 500), total: Math.random() * 1000, createdAt: new Date() });
}
// 3. Manually Split Hotspots Chunk
sh.splitAt('shopdb.orders', { userId: 'user_100' });
sh.splitAt('shopdb.orders', { userId: 'user_200' });
sh.splitAt('shopdb.orders', { userId: 'user_300' });
// 4. Restore the Equalizer
sh.startBalancer();
// 5. Verification Distribution
db.orders.getShardDistribution();
5. Configurando um cluster fragmentado do Docker
Visão geral do conceito: A implantação de um cluster fragmentado é mais complexa do que a implantação de um conjunto de réplicas — ela requer um conjunto de réplicas do Config Server, vários conjuntos de réplicas de fragmentos e o roteamento do Mongos. O Docker Compose pode orquestrar todos esses componentes com um único comando, tornando-o ideal para ambientes de desenvolvimento e teste.
Arquitetura de implantação:
graph TB
subgraph "Config Server Dungeon Collection"
CS1[config1:27019]
end
subgraph "Shard 1 Dungeon Collection"
S1A[shard1a:27018]
end
subgraph "Shard 2 Dungeon Collection"
S2A[shard2a:27020]
end
subgraph "Mongos Routing"
MS[mongos:27017]
end
App[Applications] --> MS
MS --> CS1
MS --> S1A
MS --> S2A
style MS fill:#cce5ff
style CS1 fill:#fff3cd
style S1A fill:#d4edda
style S2A fill:#d4edda
Comparação entre as configurações de produção e de desenvolvimento:
| Componente | Ambiente de produção | Ambiente de desenvolvimento |
|---|---|---|
| Servidor de configuração | Conjunto de réplicas de 3 nós | 1 nó (apenas para testes) |
| Por fragmento | Conjunto de réplicas de 3 nós | 1 nó |
| Mongos | Várias instâncias (balanceamento de carga) | 1 instância |
| Número total de mongods | 3 + 3 × 3 = 12+ | 1 + 2 + 1 = 4 |
# docker-compose-sharding.yml
version: '3.8'
services:
# Config Server(Dungeon Collection)
config1:
image: mongo:7.0
command: mongod --configsvr --replSet configReplSet --port 27019
# Shard 1(Dungeon Collection)
shard1a:
image: mongo:7.0
command: mongod --shardsvr --replSet shard1ReplSet --port 27018
# Mongos Routing
mongos:
image: mongo:7.0
command: mongos --configdb configReplSet/config1:27019 --port 27017
ports:
- "27017:27017"
Etapas de inicialização:
| Etapa | Comando | Descrição |
|---|---|---|
| 1 | rs.initiate() na config1 |
Inicializando o conjunto de réplicas do servidor de configuração |
| 2 | rs.initiate() no shard1a |
Inicializando o conjunto de réplicas do Shard 1 |
| 3 | sh.addShard() no mongos |
Adicionar um shard ao cluster |
| 4 | sh.enableSharding() |
Ativar fragmentação do banco de dados |
| 5 | sh.shardCollection() |
Selecione uma chave de fragmento |
# === Initialize a sharded cluster ===
# 1. Initialization Config Server Dungeon Collection
mongosh --port 27019 --eval 'rs.initiate({_id: "configReplSet", members: [{_id: 0, host: "config1:27019"}]})'
# 2. Initialization Shard 1 Dungeon Collection
mongosh --port 27018 --eval 'rs.initiate({_id: "shard1ReplSet", members: [{_id: 0, host: "shard1a:27018"}]})'
# 3. Through Mongos Add a shard
mongosh --port 27017 --eval '
sh.addShard("shard1ReplSet/shard1a:27018");
sh.enableSharding("shopdb");
sh.shardCollection("shopdb.orders", { userId: 1 });
'
6. Monitoramento de clusters fragmentados
Explicação do conceito: O monitoramento de um cluster fragmentado é mais complexo do que o monitoramento de um único nó ou de um conjunto de réplicas — ele exige o monitoramento da integridade de cada componente, do equilíbrio da distribuição de dados, do status da migração de blocos e muito mais. Um monitoramento adequado pode ajudar a detectar desequilíbrios de dados, fragmentos sobrecarregados e problemas de configuração em tempo hábil.
Dimensões do monitor:
| Dimensão | Comando | Principais métricas |
|---|---|---|
| Visão geral do cluster | sh.status() |
Número de fragmentos, distribuição de blocos, status do balanceador |
| Distribuição de dados | db.col.getShardDistribution() |
O volume de dados está equilibrado entre os fragmentos? |
| Equalizador | sh.isBalancerRunning() |
Status da migração, andamento da migração |
| Informações de configuração | db.settings.find() |
Tamanho do bloco, configuração do equalizador |
| Saúde do Shard | sh.status().shards |
Acessibilidade do Shard |
// === View Shard Status ===
sh.status();
// === Data Distribution ===
db.orders.getShardDistribution();
// === Balancer Management ===
sh.startBalancer();
sh.stopBalancer();
sh.setBalancerState(true);
// === Layout ===
db.settings.find();
Solução de problemas comuns:
| Problema | Sintoma | Diagnóstico | Solução |
|---|---|---|---|
| Desvio de dados | O volume de dados em um determinado fragmento é muito maior do que nos demais | getShardDistribution() |
Dividir manualmente os blocos mais acessados |
| Bloco gigante | Blocos com mais de 64 MB não podem ser divididos | sh.status() Mostrar bloco gigante |
Aumente o tamanho do bloco ou divida a chave |
| Equalizador travado | Migração não está avançando | sh.isBalancerRunning() |
Verificar o estado do servidor de configuração |
| Transmissão de consulta | Todos os shards foram consultados | explain() Exibe SHARD_MERGE |
As condições da consulta incluem a chave do shard |
▶ Exemplo 2: Monitoramento e resolução de problemas de shards
// Bob's DataFlow system has detected that queries are running slowly, diagnosing sharding issues
// 1. View Cluster Status
sh.status();
// Discovery Shard1: 8000 chunks, Shard2: 2000 chunks → Severe tilt
// 2. View Data Distribution
db.orders.getShardDistribution();
// Shard 1: 80GB (80%), Shard 2: 20GB (20%)
// 3. Check to see if there is Jumbo Chunk
db.config.chunks.find({ jumbo: true }).count();
// 3 Jumbo Chunks
// 4. Manually Split Hotspots Chunk
sh.splitAt('shopdb.orders', { userId: 'user_100' });
sh.splitAt('shopdb.orders', { userId: 'user_200' });
// 5. Verify that the equalizer is running
sh.startBalancer();
sh.isBalancerRunning(); // true
// 6. Waiting for the balancing process to complete,Check again
db.orders.getShardDistribution();
// Shard 1: 50GB (50%), Shard 2: 50GB (50%) → Balance
7. Quando se deve usar o sharding?
Explicação do conceito: Nem sempre é melhor realizar o particionamento o mais cedo possível — embora proporcione escalabilidade, ele também aumenta a complexidade operacional. Realizar o particionamento muito cedo pode acarretar custos operacionais desnecessários; realizá-lo muito tarde pode resultar em gargalos em um único servidor e dificuldades na migração de dados. A decisão deve se basear em uma avaliação abrangente do volume de dados, da taxa de transferência de gravação e das tendências de crescimento.
Estrutura de tomada de decisão:
graph TB
A{Data volume?} -->|< 100GB| B[❌ Single-player + Dungeon Collection]
A -->|100GB-1TB| C{WriteQPS?}
A -->|> 1TB| D[✅ Sharding]
C -->|< 10K ops/s| E[⚠️ Dungeon Collection<br/>Monitor Growth Trends]
C -->|> 10K ops/s| D
B --> F[Optimize Indexes + Search]
E --> G[Pre-planned Sharding Keys]
D --> H[Select a partition key + Deploy a Sharded Cluster]
style B fill:#d4edda
style D fill:#cce5ff
style E fill:#fff3cd
| Cenário | Segmentação | Motivo |
|---|---|---|
| Volume de dados < 100 GB | ❌ Um único servidor é suficiente | O particionamento aumenta a complexidade sem oferecer nenhum benefício |
| Volume de dados: 100 GB – 1 TB | ⚠️ Depende da situação | Avalie o QPS de gravação e a taxa de crescimento |
| Volume de dados > 1 TB | ✅ Recomendado | Capacidade de um único servidor e gargalos de E/S |
| Gravação > 10 mil operações por segundo | ✅ Recomendado | Gargalo único na gravação primária |
| Volume de dados em constante crescimento | ✅ Recomendado | Planeje com antecedência para evitar o particionamento forçado |
Lista de verificação pré-sharding:
| Item de preparação | Descrição |
|---|---|
| Confirme se a otimização do índice não é possível | Primeiro, use explain() para descartar problemas relacionados à consulta |
| Confirme se o escalonamento vertical não é possível | Será que atualizar a CPU, a memória e o SSD será suficiente? |
| Escolha a chave de partição correta | Alta cardinalidade, baixa frequência de atualização, acertos nas consultas |
| Implantação de um conjunto de réplicas | A base do particionamento; cada fragmento é um conjunto de réplicas |
| Capacidade planejada | Estimar o crescimento dos dados e determinar o número de shards |
| Testes de compatibilidade de aplicativos | Certifique-se de que as consultas incluam a chave de fragmentação e que os índices exclusivos incluam a chave de fragmentação |
▶ Exemplo: Guia prático para implantar um cluster fragmentado com Docker + fragmentação de dados
# === 1. Start the sharded cluster(docker-compose-sharding.yml)===
# services:
# config1:
# image: mongo:7.0
# command: mongod --configsvr --replSet configReplSet --bind_ip_all --port 27019
# ports: ["27019:27019"]
#
# shard1a:
# image: mongo:7.0
# command: mongod --shardsvr --replSet shard1ReplSet --bind_ip_all --port 27018
# ports: ["27018:27018"]
#
# shard2a:
# image: mongo:7.0
# command: mongod --shardsvr --replSet shard2ReplSet --bind_ip_all --port 27020
# ports: ["27020:27020"]
#
# mongos:
# image: mongo:7.0
# command: mongos --configdb configReplSet/config1:27019 --bind_ip_all --port 27017
# ports: ["27017:27017"]
# depends_on: [config1, shard1a, shard2a]
docker-compose -f docker-compose-sharding.yml up -d
# === 2. Initialization Config Server Dungeon Collection ===
mongosh --port 27019 --eval '
rs.initiate({
_id: "configReplSet",
members: [{ _id: 0, host: "config1:27019" }]
});
'
# === 3. Initialization Shard Dungeon Collection ===
mongosh --port 27018 --eval '
rs.initiate({ _id: "shard1ReplSet", members: [{ _id: 0, host: "shard1a:27018" }] });
'
mongosh --port 27020 --eval '
rs.initiate({ _id: "shard2ReplSet", members: [{ _id: 0, host: "shard2a:27020" }] });
'
# === 4. Through Mongos Add a shard ===
mongosh --port 27017 --eval '
sh.addShard("shard1ReplSet/shard1a:27018");
sh.addShard("shard2ReplSet/shard2a:27020");
'
# === 5. Enable Database Sharding ===
mongosh --port 27017 --eval '
sh.enableSharding("shopdb");
sh.shardCollection("shopdb.orders", { userId: 1, createdAt: -1 }); // Composite Segmented Key
'
# === 6. Insert Test Data(Automatically distributed across different shards)===
mongosh --port 27017 --eval '
for (let i = 0; i < 10000; i++) {
db.orders.insertOne({
userId: "user_" + (i % 100),
total: Math.random() * 1000,
createdAt: new Date(),
status: "paid"
});
}
'
# === 7. View Shard Distribution ===
mongosh --port 27017 --eval 'sh.status();'
# Output:
# shards:
# { _id: 'shard1ReplSet', count: 5012 }
# { _id: 'shard2ReplSet', count: 4988 }
# The data is evenly distributed across 2 shards
# === 8. When querying Mongos Automatic Routing ===
mongosh --port 27017 --eval '
db.orders.find({ userId: "user_50" }).count();
'
# Mongos Automatically route to the corresponding shard(Based on userId Scope)
// === 9. App Connections Mongos(App Transparency,Transparent Sharding)===
const mongoose = require('mongoose');
await mongoose.connect('mongodb://localhost:27017/shopdb');
// No changes to the application code are required,Compared to a standalone system MongoDB Exactly the same
await Order.create({
userId: 'user_001',
total: 599,
items: [{ sku: 'PHONE-001', qty: 1 }]
});
// Mongos Automatically route to the appropriate shard
// === 10. Hashed Sharding(Uniform Distribution of Data)===
mongosh --port 27017 --eval '
sh.shardCollection("shopdb.products", { sku: "hashed" });
'
// sku Uniform Distribution After Hashing,Avoid Hot Spots
Resultado: 10.000 pedidos são distribuídos automaticamente entre 2 shards (5.012 + 4.988); o aplicativo se conecta via Mongos sem precisar estar ciente dos detalhes do particionamento.
❓ Perguntas Frequentes
P: Posso usar um índice único após o particionamento? R: Sim, mas o índice único deve incluir a chave de particionamento (índice único composto).
P: A chave de particionamento pode ser modificada? R: Não. Uma vez definida, a chave de particionamento não pode ser modificada (é necessário recriar a coleção).
P: Um maior número de shards é sempre melhor? R: Não. Um número excessivo de shards aumenta a complexidade operacional. Recomendamos de 3 a 12 shards.
P: Devemos usar o Atlas ou configurar nossos próprios shards para produção? R: Recomenda-se o uso do Atlas (gerenciado e automatizado). A configuração de shards próprios é recomendada apenas para grandes empresas com equipes dedicadas de administradores de banco de dados (DBAs).
📖 Resumo
- Arquitetura de fragmentação: Mongos + Servidor de Configuração + Fragmento
- Seleção de chave de fragmentação: ESRT (Igualdade / Ordenação / Intervalo / Tempo)
- Segmentação por intervalo versus segmentação por hash
- Divisão e balanceamento automáticos de blocos
- Configurando um cluster fragmentado do Docker
- Quando particionar: > 1 TB de dados / > 10.000 operações por segundo
📝 Exercícios
- Questões básicas (⭐): Compreender a arquitetura de sharding e seus componentes (Mongo / Servidor de Configuração / Shard).
- Pergunta básica (⭐): Analise o cenário da sua empresa e determine se o sharding é necessário.
- Exercício avançado (⭐⭐): Implemente um cluster com 1 configuração e 2 shards usando o Docker Compose.
- Questão avançada (⭐⭐): Teste a seleção da chave de fragmentação (userId x sku x composta).
- Desafio (⭐⭐⭐): Implantar um cluster fragmentado completo (conjunto de réplicas de configuração + 2 conjuntos de réplicas de fragmentos + Mongos + monitoramento).