04 - Desafios (Re-sharding, Consultas globais)
video: https://youtu.be/... no frontmatter da nota.Desafios (Re-sharding, Consultas globais)
O sharding entrega escala horizontal de escrita e armazenamento, mas cobra o preço em moeda de complexidade distribuída: operações que eram locais no banco único passam a atravessar nós, redes e ciclos de consistência. Os quatro desafios maiores são o re-sharding, a redistribuição de dados em produção; as consultas globais, que não carregam a chave e varrem todos os fragmentos; as transações que cruzam shards, com dois-phase commit ou sagas; e o desbalanceamento, com hot shards dominando a capacidade do cluster. Nenhum desses desafios é bloqueante a ponto de inviabilizar o sharding em quem precisa dele; todos, porém, são caros o bastante para recomendar cautela a quem ainda não precisa. Este registro mapeia cada desafio com seus mecanismos de mitigação consolidados e fecha com os critérios que indicam quando o sharding não é a resposta certa.
Conceito: o preço estrutural da distribuição
O banco único esconde uma lista de facilidades que só aparecem como problema quando os dados se separam. Transações ACID cobrem qualquer conjunto de linhas; JOINs cruzam tabelas livremente; chaves únicas globais são garantidas pelo próprio motor; backups, índices e consistência referencial são administrados em um lugar. No sharding, cada uma dessas facilidades vira um projeto: transações precisam de protocolo distribuído, JOINs precisam de co-localização ou fanout, unicidade precisa de geradores globais de ID e a operação se multiplica pelo número de fragmentos.
O re-sharding é o desafio que fecha o ciclo, pois a própria distribuição criada precisa ser revista quando o volume cresce, quando a chave se mostra mal dimensionada ou quando shards individuais ficam quentes. A qualidade de uma plataforma de sharding pode ser medida pela dor dessas quatro operações, e times maduros as ensaiam antes de precisar delas.
Re-sharding em produção
Re-sharding é a operação de mudar o esquema de distribuição de dados vivos: aumentar o número de shards, alterar a chave ou trocar a estratégia. O motivo mais comum é crescimento simples, com shards alcançando limites de armazenamento ou de capacidade de escrita; o segundo é o hot shard, um fragmento que cresce desproporcionalmente; o terceiro é a correção de escolhas originais, como chave com cardinalidade insuficiente. Em qualquer variante, a operação repete um fluxo consagrado de quatro fases:
- Fase de espelhamento: instalar a nova topologia e replicar os dados atuais para ela, sem afetar o tráfego, usando CDC, VReplication ou mecanismo equivalente de cópia com ponto de corte.
- Backfill incremental: copiar o acervo histórico em lotes controlados, com limitação de banda para não saturar os nós de origem e com retomada idempotente após interrupções.
- Camada dupla e validação: escrever simultaneamente nas duas topologias, comparar contagens, somas de verificação e amostras de linha, e medir o atraso de convergência.
- Corte de tráfego: alternar leitura e escrita para a nova topologia por etapas, primeiro tráfego interno, depois leitura, por fim escrita, com reversão rápida disponível.
O corte por etapas é o que separa uma migração profissional de uma aposta: cada etapa tem critério de avanço e critério de reversão, e o sistema inteiro pode voltar à topologia anterior até o momento em que a escrita única se estabelece. A janela total tipicamente varia de dias a semanas, dominada pelo backfill do acervo histórico, e não pela lógica de roteamento.
# Plano de re-sharding em YAML: contrato operacional do evento
operacao: re-sharding-pedidos
origem:
shards: 8
chave: user_id
estrategia: hash_modulo
destino:
shards: 32
chave: user_id
estrategia: consistent_hashing
fases:
espelhamento: { ferramenta: cdc_debezium, banda_max_mbps: 200 }
backfill: { lote_linhas: 50000, pausa_entre_lotes_ms: 500 }
validacao: { comparar: [contagem, checksum_por_lote], amostragem: 0.1 }
corte: { etapas: [interno, leitura, escrita], reversao: por_etapa }
limites:
atraso_cdc_max_seg: 30
erro_validacao_max: 0
Ferramentas de resharding online
A operação manual de re-sharding é possível e alguns times a executam, mas a prática consolidada usa ferramentas que automatizam espelhamento, backfill e corte. A tabela compara as principais:
| Ferramenta | Ecossistema | Mecanismo de migração | Destaque |
|---|---|---|---|
| Vitess (VReplication) | MySQL | Fluxos de cópia contínua com corte controlado por workflow | Padrão em escala de web massiva, usado por grandes plataformas |
| MongoDB reshardCollection | MongoDB | Redistribuição coordenada pelo próprio cluster | Operação nativa, sem proxy externo |
| Citus | PostgreSQL | Rebalanceamento de shards distribuídos por metadata | Extensão nativa, co-localização de tabelas |
| ShardingSphere | MySQL, PostgreSQL | Migração com proxy e scaling job | Ecossistema Apache, configuração declarativa |
| Movimento manual | Qualquer | CDC, camada dupla e scripts próprios | Controle total, custo de engenharia alto |
A escolha da ferramenta é subordinada à plataforma de sharding já adotada; trocar de plataforma para obter resharding mais fácil raramente compensa. O ponto de atenção comum a todas é a capacidade de reversão: ensaiar o retorno à topologia original é parte do plano, não um extra.
Consultas globais e agregações entre shards
Consultas globais são as que não informam a chave de sharding: contagem de pedidos do dia, ranking de produtos, busca por nome de cliente. Cada uma delas vira scatter-gather, enviada a todos os fragmentos com resultados agregados em um coordenador. A latência passa a ser regida pelo shard mais lento, e o custo linear no número de nós transforma consultas globais frequentes em assassinas de capacidade.
As mitigações formam camadas. A primeira é paralelizar o fanout com limite de concorrência e agregação parcial por shard, que transforma a soma global em somas locais somadas no coordenador, reduzindo o tráfego de retorno. A segunda é o índice secundário global, mantido de forma assíncrona, que mapeia atributos de busca ao fragmento de destino ao custo de consistência eventual. A terceira é o offload analítico: consultas globais pesadas migram para um data warehouse ou motor colunar alimentado por CDC, deixando o cluster transacional com rota direta apenas. A quarta é o cache de resultado para agregações caras e tolerantes a defasagem, com TTL curto e invalidação por evento.
A regra de desenho que decorre disso é clássica: o cluster transacional shardado não é o lugar para analytics. Tentar servir BI sobre fragmentos transacionais degrada ambos os mundos, e a separação de camadas é mais barata que a guerra por recursos.
A medição do problema também tem camada própria: contar consultas globais por minuto, medir o fanout efetivo, isto é, quantos shards cada consulta toca, e registrar a latência do gather por endpoint. Com esses números, o time prioriza quais consultas merecem índice global, quais vão para o warehouse e quais permanecem como fanout aceitável, transformando o scatter-gather de vilão invisível em item gerenciado de backlog.
Transações distribuídas: 2PC e sagas
Quando uma transação precisa alterar linhas em dois shards, o banco único não ajuda mais, e duas famílias de protocolo disputam o caso. O two-phase commit, 2PC, coordenador propõe a mudança a todos os participantes, aguarda promessa de commit e então confirma; garante atomicidade, mas bloqueia recursos entre as fases, e um coordenador que falhe no meio deixa os participantes presos, situação clássica de indisponibilidade prolongada. Por isso a maioria dos sistemas de alta escala evita 2PC no caminho transacional quente.
As sagas dividem a transação em passos locais, cada um com transação ACID própria, e encadeiam ações de compensação para desfazer caminhos parciais em caso de falha. Um pedido que reserva estoque no shard A e grava cobrança no shard B executa dois passos locais; a falha no segundo dispara a compensação de liberação do estoque no primeiro. O resultado é eventualmente consistente, exige idempotência em cada passo e produz estados intermediários visíveis, que a interface precisa saber interpretar, como pedido com status reservando, confirmado ou cancelado.
Saga de pedido entre shards: passos locais com compensações
1. Reservar estoque (shard de produtos) compensa: liberar estoque
2. Gravar cobrança (shard de pagamentos) compensa: estornar cobrança
3. Confirmar pedido (shard do usuário) compensa: marcar cancelado
Falha em qualquer passo executa as compensações dos passos anteriores
na ordem inversa, com idempotência garantida por chave de operação
A melhor transação distribuída, porém, é a que não existe: desenhar agregados co-localizados pela chave de sharding, como discutido no arquivo da chave, mantém a maioria absoluta das transações dentro de um único fragmento. O orçamento de transações cross-shard deve ser medido e mantido raro, e os casos inevitáveis adotam sagas com compensações explícitas.
| Aspecto | 2PC | Sagas |
|---|---|---|
| Garantia | Atomicidade forte | Consistência eventual com compensação |
| Bloqueio de recursos | Sim, entre as fases | Não, cada passo é transação local |
| Falha do coordenador | Participantes podem ficar presos | Passos retomáveis com idempotência |
| Estados intermediários | Invisíveis | Visíveis, parte do desenho |
| Complexidade no código | No motor ou coordenador | Nos serviços, com lógica de compensação |
| Uso típico | Coordenação de infraestrutura, lotes | Caminho transacional de aplicações distribuídas |
Desbalanceamento e hot shards
Hot shard é o fragmento que recebe carga desproporcional, seja por viés da chave, seja pela celebridade de uma entidade: o usuário viral, o inquilino corporativo gigante, o produto campeão de campanha. O sintoma é o cluster com nós ociosos e um nó em saturação, limitando a capacidade total ao pior fragmento. O diagnóstico vem do monitoramento por shard de CPU, I/O, contagem de linhas e latência por consulta.
As respostas seguem uma gradação. A divisão do shard quente redistribui seus intervalos ou arcos, útil quando o viés está na distribuição e não na entidade. O shard dedicado isola a entidade gigante em fragmento próprio, com dimensionamento individual, o desenho mais comum para inquilinos corporativos. O cache na frente da leitura quente absorve o tráfego de consulta sem tocar o banco. O salting da chave quente divide a escrita da entidade em subchaves, com agregação na leitura. Nenhuma dessas respostas é global; a escolha depende de o peso estar em leitura ou em escrita e de a origem ser distribuição ou entidade.
A prevenção também existe e é mais barata que qualquer resposta: escolher chaves de alta cardinalidade, monitorar o desvio de carga desde o primeiro dia e reservar margem de fragmentos para movimentação. Clusters sem margem livre transformam a divisão de um shard quente em evento de emergência, porque não há espaço para receber os dados movidos.
Quando NÃO shardar
O desafio mais barato de resolver é o sharding desnecessário, e os sinais de que ele é desnecessário aparecem antes de qualquer migração. Alternativas que resolvem a maioria dos casos sem a complexidade distribuída:
- Escala vertical: classes de instância modernas oferecem CPU, memória e NVMe que sustentam terabytes transacionais; subir a classe é a solução mais barata enquanto ela alcança.
- Réplicas de leitura: a maior parte das cargas tem proporção de leitura dominante, e réplicas resolvem esse lado sem tocar o caminho de escrita.
- Caching distribuído: um cache adequado retira a leitura quente do banco e frequentemente posterga qualquer projeto de sharding em anos.
- Particionamento e arquivamento: particionamento no servidor resolve manutenção de tabelas grandes, e arquivamento para armazenamento frio corta o acervo quente.
- Ajuste de workload: índices corretos, consultas ajustadas, transações curtas e filas para escritas diferidas resolvem mais saturação do que qualquer redistribuição.
- Bancos novos com armazenamento elástico: motores com camada de armazenamento separada e compute escalável postergam o teto físico e mudam o cálculo do gatilho.
Os gatilhos legítimos de sharding continuam sendo limites físicos reais: escrita que não acompanha na maior classe disponível, acervo que excede o armazenamento do nó, requisitos regulatórios de residência por cliente e isolamento contratual forte. Fora desses casos, a recomendação prática é tratar o sharding como seguro de escala de último recurso, contratado quando o risco é comprovado, e não como status de arquitetura.
Erros comuns e boas práticas
- Erro: re-sharding em evento único, com parada de escrita e esperança de que tudo funcione; prática: fases de espelhamento, backfill, validação e corte por etapas com reversão.
- Erro: ignorar o backfill e descobrir que semanas de cópia saturaram os nós de origem; prática: limitação de banda, lotes pequenos e métrica de atraso de CDC durante toda a migração.
- Erro: aceitar consultas globais frequentes no caminho transacional; prática: offload analítico, índices globais seletivos e cache de agregação para o resto.
- Erro: usar 2PC por padrão para qualquer transação entre shards; prática: co-localizar agregados para eliminar a transação distribuída e reservar sagas para os casos remanescentes.
- Erro: tratar hot shard como problema de infraestrutura quando é problema de entidade; prática: diagnóstico por entidade quente, com shard dedicado, cache ou salting conforme o caso.
- Erro: executar o corte de tráfego sem ensaio prévio em ambiente de staging; prática: simulação completa das quatro fases com dados sintéticos e métricas comparadas antes do evento real.
- Erro: shardar por motivo de reputação técnica com carga que cabe em um nó; prática: exaurir vertical, réplicas, cache e particionamento, e shardar apenas com gatilho físico comprovado.
A visão final do módulo é equilibrada: o sharding é a ferramenta que quebra o teto físico do banco único, e os desafios listados aqui são o custo conhecido e administrável dessa quebra. Times que os antecipam com co-localização de agregados, roteamento disciplinado, ferramentas de resharding ensaiadas e camada analítica separada operam clusters de milhares de fragmentos com tranquilidade; times que os descobrem em produção pagam cada lição com incidente. A decisão madura começa sempre pela pergunta oposta: o que precisa acontecer para este sistema realmente precisar de sharding.