Pular para o conteúdo
fernando.moretes.com
BlogEstudosCursosE-booksOpen SourcePodcasts
Loading…
Fernando Azevedo

Arquiteto de TI Especialista

Arquitetura, AWS, IA em produção, sistemas financeiros e FinOps, escritos a partir do que foi operado, com os números.

  • LinkedIn
  • GitHub
  • E-mail

Conteúdo

  • Blog
  • Estudos de arquitetura
  • Cursos
  • E-books
  • Open Source
  • Podcasts
  • Assuntos
  • Trilhas

Ferramentas

  • Well-Architected self-check
  • Arquitetura deste site
  • Números públicos
  • Histórico de estudo

Sobre

  • Comunidade
  • IA Builder
  • Perfil
  • Currículo (CV)
  • Trabalhe comigo
  • Media kit
  • RSS do blog
  • RSS dos estudos
  • Artigos narrados (podcast)
  • llms.txt
  • Termos, privacidade e uso de IA

(c) 2026 Fernando Francisco Azevedo

Estudos/Decisão (ADR)
RSSMarkdownLLMs
Decisão (ADR)OLTP em alto crescimento (cenário)DadosAceito

ADR: Sharding no Aurora: App-Level vs Aurora Limitless vs Citus

18 de fev. de 2026 9 min Com apoio de IA000 visualizações00 reproduções
Ouvir estudo

cerca de 9 min · áudio gerado ao tocar

Quando um único writer Aurora PostgreSQL deixa de ser suficiente, a decisão de como distribuir a carga não é trivial. Cada abordagem de sharding carrega um contrato diferente com o time de engenharia: controle total com custo cognitivo alto, managed service com restrições de modelo, ou extensão de banco com trade-offs de portabilidade. Este ADR documenta o raciocínio que me levaria a escolher Aurora Limitless como caminho primário, e quando eu mudaria de ideia.

Contexto do Cenário

Sistema
Plataforma OLTP em alto crescimento (cenário composto, não empresa específica)
Engine atual
Aurora PostgreSQL 15, single writer, múltiplos read replicas
Escala do problema
Writer saturado: CPU > 85% sustentado, WAL lag crescente, latência P99 de writes > 400ms
Volume estimado
~50k transações/segundo de pico, dataset principal ~4TB, crescimento de 15% ao mês
Padrão de acesso
80% das writes concentradas em entidade principal com shard key natural (tenant_id / account_id)
Restrições
Time de dados de 6 engenheiros; SLA de 99.99%; janela de manutenção < 30 min/mês
Stack relevante
AWS (us-east-1), Aurora PostgreSQL, Lambda, ECS, Terraform, Datadog
Status do ADR
Accepted: Aurora Limitless como decisão primária

O Problema Real: Por Que Sharding É a Última Opção, Não a Primeira

Antes de qualquer conversa sobre sharding, é obrigatório esgotar as alternativas verticais e de leitura. Neste cenário, já fizemos isso: o writer está em db.r7g.16xlarge, os read replicas absorvem 100% das queries de leitura via PgBouncer com pool de sessão, e os índices foram revisados por um DBA sênior. O problema é estrutural, o volume de writes não cabe em um único nó, e Aurora não oferece write scaling horizontal nativo no modelo clássico.

O diagnóstico importa aqui. O gargalo não é I/O de storage: Aurora desacopla storage de compute e o distributed storage layer escala automaticamente. O gargalo é o processo de WAL writer e o lock manager no nó de compute. Cada transação commited precisa passar pelo writer, serializar o WAL e aguardar o ACK do quorum de storage nodes. Com 50k TPS de pico e transações médias de 5-8 statements, estamos falando de centenas de milhares de operações de lock/segundo. Isso é um limite de compute, não de storage.

A segunda dimensão do problema é o crescimento. Com 15% de crescimento mensal, mesmo que um upgrade vertical comprasse 6 meses, estaríamos de volta ao mesmo ponto em menos de um ano, e com uma instância ainda maior, mais cara, e com menos opções de escape. Sharding não é apenas sobre o presente; é sobre criar uma arquitetura que escale com o negócio sem exigir uma nova decisão de plataforma a cada ciclo de crescimento.

A terceira dimensão é o time. Seis engenheiros de dados com SLA de 99.99% significa que cada hora de oncall não planejado é cara. A escolha de sharding não pode criar uma superfície operacional que o time não consiga sustentar. Isso elimina imediatamente qualquer solução que exija que o time implemente seu próprio rebalanceamento, gerenciamento de metadados de shard, ou roteamento de queries cross-shard do zero.

As Forças em Jogo

Qualquer decisão de sharding envolve tensões que não se resolvem, só se gerenciam. Vou ser explícito sobre cada uma delas:

Shard key e distribuição de dados. Temos tenant_id como chave natural. Isso é uma vantagem enorme: a maioria das queries é scoped por tenant, o que significa que queries cross-shard são exceção, não regra. Mas tenants não são uniformes, alguns têm 100x mais dados que outros. Qualquer estratégia de sharding precisa lidar com hot shards de tenants grandes, seja via sub-sharding, seja via roteamento especial.

Queries cross-shard. Mesmo com 80% das queries scoped por tenant, os 20% restantes existem: relatórios agregados, queries de admin, joins entre tenants em features específicas. A pergunta não é se cross-shard queries acontecerão, mas qual é o custo de executá-las e quem paga esse custo, a aplicação, o banco, ou o engenheiro que precisa reescrever a query.

Rebalanceamento. Shards não são estáticos. Tenants crescem, novos tenants chegam, tenants saem. A capacidade de mover dados entre shards sem downtime é crítica. Soluções que exigem que o time implemente isso manualmente são um risco operacional sério para um time de 6 pessoas.

Compatibilidade com PostgreSQL. O sistema usa features específicas do PostgreSQL: JSONB, pg_trgm para full-text search parcial, e algumas stored procedures legadas. Qualquer solução precisa preservar essa compatibilidade ou o custo de migração de aplicação explode.

Custo. Aurora Limitless tem um modelo de pricing diferente do Aurora clássico, você paga por Distributed Processing Units (DPUs) além do storage. Para workloads que poderiam ser servidos por 2-3 writers independentes com sharding na aplicação, o custo do Limitless pode ser 30-50% maior (estimativa baseada em benchmarks públicos da AWS, não em medição direta neste cenário). Esse delta precisa ser justificado por redução de complexidade operacional.

Vendor lock-in. Aurora Limitless é AWS-specific. Citus é open-source mas tem uma versão gerenciada na Azure (Cosmos DB for PostgreSQL). App-level sharding com PostgreSQL padrão é o mais portável. Para um sistema com SLA de 99.99% e dependência crítica de negócio, a portabilidade tem valor real, mas não é gratuita.

Opções Avaliadas

Opção A: Sharding na Camada de Aplicação

Prós
  • Controle total sobre lógica de roteamento e rebalanceamento
  • Máxima portabilidade, qualquer PostgreSQL funciona como shard
  • Custo de infra potencialmente menor (Aurora writers independentes)
  • Sem dependência de features experimentais ou managed services específicos
Contras
  • Complexidade de implementação alta: shard registry, connection routing, distributed transactions
  • Queries cross-shard precisam ser implementadas e mantidas na aplicação (scatter-gather manual)
  • Rebalanceamento de shards é responsabilidade do time, risco operacional sério
  • Migrations de schema precisam ser coordenadas em todos os shards simultaneamente
  • Referência: Figma e Notion levaram 12-18 meses para estabilizar suas implementações

Viável para times grandes com expertise em distributed systems. Inadequado para time de 6 engenheiros com SLA crítico.

Opção B: Aurora Limitless Database

Prós
  • Sharding transparente gerenciado pela AWS, sem shard registry na aplicação
  • Rebalanceamento automático de shards sem downtime
  • Interface PostgreSQL padrão, compatibilidade com drivers existentes via Transaction Router
  • Escala horizontal de writes sem mudança de arquitetura de aplicação
  • Integração nativa com ecossistema AWS (IAM, CloudWatch, Parameter Groups)
Contras
  • Vendor lock-in: feature exclusiva da AWS, sem path de migração direto para outro provider
  • Custo de DPUs adicional, pode ser 30-50% mais caro que sharding manual em escala moderada (estimativa)
  • Limitações documentadas: algumas DDLs e features PostgreSQL não suportadas no modelo distribuído
  • Feature relativamente nova (GA em 2024), menor histórico de battle-tested em produção
  • Shard key deve ser definida na criação da tabela, mudança posterior é complexa

Melhor trade-off para este cenário: reduz drasticamente a carga operacional mantendo compatibilidade PostgreSQL e escalabilidade de writes.

Opção C: Citus / PostgreSQL Gerenciado (Azure ou self-managed)

Prós
  • Open-source com extensão madura e bem documentada
  • Suporte nativo a queries distribuídas, incluindo aggregations e joins cross-shard
  • Portabilidade maior que Limitless, pode rodar em qualquer cloud ou on-prem
  • Rebalanceamento de shards suportado nativamente pela extensão
Contras
  • Self-managed Citus: carga operacional alta, upgrades, HA, backups, rebalanceamento são responsabilidade do time
  • Managed Citus (Azure Cosmos DB for PostgreSQL): mudança de cloud provider, custo de migração de infra e operacional alto
  • Modelo de coordinator/worker introduz single point of failure no coordinator (mitigável com HA, mas adiciona complexidade)
  • Compatibilidade com algumas features PostgreSQL avançadas pode variar por versão

Excelente opção técnica se o sistema não estiver fortemente acoplado à AWS ou se portabilidade for prioridade estratégica. Não é o caso aqui.

Decisão de Arquitetura

Aceito
Contexto

Workload OLTP com writer Aurora PostgreSQL saturado, time de dados de 6 engenheiros, SLA de 99.99%, shard key natural disponível (tenant_id), e stack fortemente integrada à AWS. As alternativas de escala vertical foram esgotadas. A decisão precisa balancear escalabilidade de writes, carga operacional e custo.

Decisão

Adotar **Aurora Limitless Database** como estratégia de sharding primária, com `tenant_id` como shard key para as tabelas de alta escrita. Tabelas de referência (lookup tables, configurações) serão definidas como reference tables no Limitless para evitar joins cross-shard. A migração será feita via dual-write com validação de consistência antes do cutover. Manter Aurora clássico como fallback por 90 dias pós-migração.

Consequências
  • ✅ Escala de writes horizontal sem mudança de lógica de aplicação, o Transaction Router do Limitless absorve o roteamento
  • ✅ Rebalanceamento automático de shards elimina a principal fonte de risco operacional do sharding manual
  • ✅ Compatibilidade com drivers PostgreSQL existentes, sem refatoração de DAL (Data Access Layer)
  • ⚠️ Vendor lock-in aumenta: saída do Limitless exige migração para Aurora clássico com sharding manual ou Citus
  • ⚠️ Custo de DPUs precisa ser monitorado, risco de custo não linear com crescimento de TPS
  • ⚠️ Shard key (tenant_id) precisa estar presente em todas as queries de escrita nas tabelas distribuídas, queries sem shard key farão broadcast e serão caras

Por Que Não Sharding na Aplicação: A Lição de Figma e Notion

Figma e Notion são casos bem documentados de sharding na camada de aplicação. Ambos funcionaram, mas ambos têm times de engenharia de dados de dezenas de pessoas, anos de runway para estabilizar a implementação, e a capacidade de absorver os custos de uma migração complexa. O que esses casos ensinam não é que sharding na aplicação é uma boa ideia para todos, é que é uma boa ideia para quem tem os recursos para fazê-lo corretamente.

Para um time de 6 engenheiros com SLA de 99.99%, o custo real do sharding na aplicação não é o código de roteamento inicial. É o que vem depois: o primeiro hot shard que aparece às 2h da manhã e precisa ser rebalanceado manualmente; a migration de schema que precisa ser executada em 8 shards de forma coordenada com rollback testado; a query de relatório que alguém escreveu sem shard key e que agora está fazendo full scan em todos os shards; o bug no shard registry que faz 0.1% das writes irem para o shard errado e só é descoberto 3 dias depois.

Esses não são problemas hipotéticos. São os problemas que aparecem invariavelmente em implementações de sharding manual, e a pergunta é se o time tem capacidade de resolvê-los sem comprometer o SLA. A resposta honesta, para um time de 6 pessoas sem experiência prévia em sharding distribuído, é não.

Isso não significa que sharding na aplicação seja errado. Significa que tem um custo de maturidade organizacional que precisa ser reconhecido. Se o time crescer para 15-20 engenheiros com experiência específica em distributed systems, a equação muda, e a portabilidade do sharding manual se torna um ativo real. Hoje, não é.

Arquitetura Alvo: Aurora Limitless com Roteamento por Tenant

Fluxo de write/read em produção após migração para Aurora Limitless. O Transaction Router é o ponto de entrada único, a aplicação não conhece os shard groups. Reference tables são replicadas em todos os shard groups para evitar joins cross-shard.

🖥️ Application Layer
  • Application · (ECS Tasks)
  • PgBouncer · Connection Pool
🔀 Aurora Limitless: Router Layer
  • Transaction Router · (Limitless Endpoint)
🗄️ Aurora Limitless: Shard Groups
  • Shard Group 1 · tenant_id: 0-33%
  • Shard Group 2 · tenant_id: 33-66%
  • Shard Group 3 · tenant_id: 66-100%
  • Reference Tables · (replicated all shards)
📊 Observability
  • CloudWatch · DPU / Latency / Errors
  • Datadog · APM + DB Metrics
🔒 Security
  • IAM Auth · DB Credentials via Secrets Manager

Comparação Técnica Detalhada

CritérioApp-Level ShardingAurora LimitlessCitus Gerenciado
Carga operacionalAltaBaixaMédia
Queries cross-shardManual (scatter-gather na app)Suportado via Transaction RouterSuportado nativamente (Citus planner)
RebalanceamentoManual, responsabilidade do timeAutomático pela AWSSuportado pela extensão Citus
Compatibilidade PostgreSQLTotal (PostgreSQL padrão)Alta, com limitações documentadas em DDLAlta, com limitações em algumas queries complexas
PortabilidadeMáximaMínima (AWS-only)Alta (open-source)
Custo relativo (estimativa)Menor (Aurora writers independentes)Maior (DPUs adicionais)Médio (depende de managed vs self-hosted)
Maturidade da featureAlta (padrão da indústria)Média (GA 2024)Alta (Citus existe desde 2012)
Tempo até produção (estimativa)12-18 meses para estabilizar3-6 meses (migração + validação)6-9 meses (se mudança de cloud)

Plano de Migração para Aurora Limitless

  1. 1

    Fase 1: Auditoria (Semanas 1-3)

    Mapear todas as queries que não incluem tenant_id. Identificar stored procedures com DDL incompatível com Limitless. Catalogar reference tables candidatas. Medir distribuição de dados por tenant para identificar hot tenants.

  2. 2

    Fase 2: Ambiente Limitless (Semanas 4-6)

    Provisionar cluster Aurora Limitless em ambiente de staging. Criar tabelas distribuídas com tenant_id como shard key. Criar reference tables para lookup data. Executar testes de carga com shadow traffic.

  3. 3

    Fase 3: Dual-Write (Semanas 7-10)

    Implementar dual-write na DAL: todas as writes vão para Aurora clássico E Aurora Limitless. Reads continuam no Aurora clássico. Executar validação de consistência contínua entre os dois sistemas. Monitorar divergências.

  4. 4

    Fase 4: Cutover Gradual (Semanas 11-14)

    Migrar reads para Aurora Limitless por tenant (começando com tenants menores). Monitorar latência P99 e error rate. Aumentar percentual gradualmente. Cutover completo quando 100% dos tenants validados.

  5. 5

    Fase 5: Estabilização (Semanas 15-24)

    Manter Aurora clássico como fallback por 90 dias. Monitorar custo de DPUs vs projeção. Desativar dual-write. Após 90 dias sem incidentes, deprecar Aurora clássico e liberar recursos.

FA
Minha Perspectiva: O Custo Invisível da Complexidade
Arquiteto de TI Especialista

Quando eu analiso esse tipo de decisão, a primeira pergunta que faço não é técnica, é organizacional: quem vai acordar às 3h da manhã quando isso quebrar, e o que eles precisarão saber para resolver? Sharding na aplicação é tecnicamente elegante quando bem feito. Mas 'bem feito' requer um nível de maturidade operacional que a maioria dos times subestima. O código de roteamento é a parte fácil. O difícil é o rebalanceamento de hot shards em produção com SLA ativo, a coordenação de schema migrations em múltiplos shards, e o debugging de inconsistências que só aparecem em queries cross-shard em horário de pico. Aurora Limitless resolve exatamente esses problemas, ao custo de vendor lock-in e DPUs adicionais. Para um time de 6 engenheiros com SLA de 99.99%, esse é um trade-off que eu aceitaria sem hesitação. O custo de DPUs é previsível e monitorável; o custo de um incidente de sharding mal implementado às 3h da manhã não é. O que eu faria diferente do que está documentado aqui: eu adicionaria um circuit breaker explícito no Transaction Router: se o Limitless retornar erros acima de um threshold, a aplicação cai automaticamente para o Aurora clássico (que permanece em dual-write por 90 dias). Isso não é paranoia; é reconhecer que o Limitless tem GA desde 2024 e que qualquer feature nova de banco de dados terá edge cases que só aparecem em produção. Sobre Citus: é uma opção genuinamente boa que eu escolheria se o sistema não estivesse fortemente acoplado à AWS ou se houvesse um requisito estratégico de portabilidade. O fato de a versão managed estar na Azure é um problema real para um sistema AWS-first, não é impossível de resolver, mas adiciona uma camada de complexidade operacional que não está justificada aqui. A lição geral: sharding é uma decisão de equipe, não só de arquitetura. A melhor solução técnica que o time não consegue operar é pior que uma solução boa o suficiente que o time domina.

AWS Well-Architected: Impacto da Decisão

Segurança

IAM authentication para o endpoint Limitless via Secrets Manager. Encryption at rest e in transit herdados do Aurora. O Transaction Router é o único ponto de entrada, reduz superfície de ataque vs múltiplos writers independentes no modelo app-level sharding.

Confiabilidade

Aurora Limitless herda a durabilidade do storage distribuído Aurora (6 cópias em 3 AZs). O rebalanceamento automático de shards reduz o risco de hot shard causar degradação de serviço. O plano de dual-write com fallback para Aurora clássico garante RTO < 5 minutos em caso de regressão.

Eficiência de performance

O Transaction Router distribui writes por shard group baseado em tenant_id hash, eliminando o gargalo do single writer. Reference tables evitam joins cross-shard para dados de lookup. Queries sem shard key fazem broadcast, precisam ser monitoradas e eliminadas.

Sustentabilidade

Consolidação de compute em Limitless vs múltiplos writers independentes pode reduzir consumo total de recursos se o Limitless for mais eficiente na alocação de DPUs por TPS. Requer validação com benchmarks reais.

Veredicto

Aurora Limitless é a decisão correta para este cenário, não porque seja a solução tecnicamente mais elegante, mas porque é a que melhor alinha capacidade do time, restrições de SLA e velocidade de entrega. Sharding na aplicação é uma solução legítima para times grandes com expertise em distributed systems e tempo para estabilizar a implementação. Para um time de 6 engenheiros com SLA de 99.99%, o custo operacional do sharding manual é proibitivo, não em dinheiro, mas em risco e capacidade cognitiva. Citus é tecnicamente excelente, mas a versão managed está na Azure, e mover um sistema AWS-first para outro cloud provider para resolver um problema de banco de dados é uma troca que não faz sentido aqui. Os riscos reais da decisão são dois: o custo de DPUs pode ser não-linear com crescimento de TPS (monitorar desde o primeiro dia), e o Limitless tem GA desde 2024 (manter o fallback para Aurora clássico por pelo menos 90 dias pós-cutover). Nenhum desses riscos invalida a decisão, eles precisam ser gerenciados. A decisão de sharding é, em última análise, uma decisão sobre onde você quer que a complexidade viva: no código da aplicação, no managed service, ou na extensão do banco. Para este cenário, o managed service é a resposta certa.

Referências

Amazon Aurora Limitless Database: Official DocumentationAmazon Aurora: Product Page
#aurora#sharding#postgresql#oltp#aurora-limitless#citus#data-platform#scalability
Fontes do caso
Amazon Aurora: Limitless DatabaseAWS: Amazon Aurora
Compartilhar:LinkedInWhatsAppXBaixar em Markdown
Escrito com apoio de IA a partir do caso público e da minha leitura como arquiteto.
Próximo passo
Trilha Arquiteto de IA, gratuitaFundamentos, LLMs, RAG, tools, MCP e arquitetura na AWS, em aulas curtas e interativas.Começar a trilhaAgentes de IA em produção na AWSComo eu desenho, oriento e audito agentes que vão ao ar, com os números e as fontes.Ver o IA Builder

Continue lendo

Decisão (ADR)ADR: Aurora vs DynamoDB para um Ledger de Dupla Entrada em Core BankingEste ADR avalia Aurora PostgreSQL e DynamoDB como motor de persistência para um ledger de dupla entrada em um sistema de core banking, pesando consistência forte, padrões de acesso, auditabilidade e custo. A decisão favorece Aurora com particionamento por range de data e uma camada de eventos imutável, reconhecendo as limitações de escala horizontal que essa escolha impõe.Ler Decisão (ADR)ADR: OpenSearch Serverless vs Banco Vetorial Dedicado para RAG AgênticoEste ADR avalia as opções de infraestrutura de busca vetorial para uma plataforma RAG agêntica multi-tenant na AWS, comparando OpenSearch Serverless, bancos vetoriais dedicados (Pinecone, pgvector) e busca híbrida própria. A decisão considera custo, latência p99, filtros por permissão, ingestão incremental e integração nativa com Bedrock Knowledge Bases.Ler TeardownFigma: Sharding Horizontal de Postgres Sem Parar de CrescerEm 2022, o Figma enfrentou limites físicos do seu banco de dados Postgres monolítico e executou uma migração de sharding horizontal com particionamento por chave, roteamento dinâmico e migração incremental, tudo isso sem downtime e sem travar o crescimento do produto. Este teardown reconstrói a arquitetura, analisa as decisões técnicas e aponta o que eu faria diferente.Ler
AnteriorDesign Doc: RDS Proxy para Lambda + RDS sem derreter o bancoPróximoCloudflare (2026): quando uma dependência single-AZ derruba um cluster 'HA'
Gostou deste estudo? Receba o próximo.

Post-mortems, ADRs e deep dives de arquitetura no seu email, do jeito que um arquiteto lê.

Sem spam · cancele quando quiser

Pergunte ao Fernando sobre isto

Uma resposta focada sobre este estudo, do meu assistente de IA, baseada no meu trabalho.

Participe da conversa

Entre para comentar

Confirme seu e-mail para participar, você também recebe a newsletter. Sem senha.

Neste estudo
O Problema Real: Por Que Sharding É a Última Opção, Não a PrimeiraAs Forças em JogoOpções AvaliadasDecisão de ArquiteturaPor Que Não Sharding na Aplicação: A Lição de Figma e NotionArquiteturaComparação Técnica DetalhadaPlano de Migração para Aurora LimitlessWell-ArchitectedVeredictoReferências