Réplicas de leitura: quando roteamento vence cache

Cache desloca carga de leitura fora do banco até tempestades de invalidação ou dados obsoletos quebrarem a confiança. Réplicas de leitura com roteamento explícito de queries trocam complexidade operacional por latência previsível — e um caminho que sobrevive quando o cache não pode.

Engenharia6 min de leitura
PostgresRéplicas de leituraBanco de dadosCacheRoteamento de queries
Compartilhar

Tráfego de leitura dobrou. O time adicionou Redis. Taxas de acerto pareciam boas — 94%. Depois uma atualização em massa de admin invalidou metade do keyspace e Postgres absorveu a estampida mesmo assim. O p99 do dashboard subiu para quatro segundos. Cache-aside tinha escondido a carga de leitura até esconder falhar. Roteamento de réplicas de leitura no Postgres aborda um problema diferente: distribuir queries de leitura para nós standby com trade-offs de lag de replicação conhecidos — em vez de esperar que a lógica de invalidação permaneça correta sob todo padrão de escrita.

Cache e réplicas são complementos, não substitutos. Cache vence em chaves quentes com staleness tolerável. Réplicas vencem em queries analíticas de muita leitura, padrões de acesso imprevisíveis e cargas onde invalidar cache é mais difícil que gerenciar lag de replicação.

Quando cache deixa de bastar

SymptomLikely causeReplica vs cache
Tempestades de invalidação após escritas em massaExplosão de chaves de cacheRéplicas absorvem pico de leitura diretamente
Leituras obsoletas quebram confiança do usuárioTTL longo demais ou invalidação omitidaRéplicas: lag limitado, muitas vezes subsegundo
Custo de memória excede custo de leitura no DBWorking set grandeRéplicas mais baratas por GB escaneado
Padrões de query complexosDifícil chavear entradas de cacheRéplicas executam SQL; cache precisa de chaves sob medida
Cache frio após deployTodos os misses de uma vezRéplicas sempre quentes para a rota SQL

Cache esconde carga. Não a remove — atrasa e concentra no momento do miss. Réplicas distribuem carga continuamente ao custo de lag de replicação e complexidade operacional de roteamento.

Um cache com invalidação errada é uma máquina de leituras obsoletas com boas métricas de hit rate.

Arquitetura de roteamento para réplicas de leitura

O primary trata escritas e, opcionalmente, leituras com consistência forte.

As réplicas tratam queries somente leitura roteadas explicitamente — não por acidente.

Camadas de roteamento:

  1. Nível de aplicação. O código passa flag read_consistency: strong | eventual; o pool de conexões seleciona datasource primary ou réplica.

  2. ORM / middleware. Splitter read/write intercepta SELECT versus INSERT/UPDATE/DELETE.

  3. Proxy. PgBouncer, RDS Proxy ou router custom — centraliza roteamento; o risco é magia opaca se times não entendem as regras.

  4. Modelos de leitura CQRS. Tabelas de projeção dedicadas em réplica ou store de leitura separado — ver modelo de leitura CQRS para quando projeções substituem roteamento ad hoc a réplicas.

Regras de roteamento explícitas vencem o implícito "todos os SELECT vão para réplica":

Query typeRouteReason
Checagem de auth de sessão do usuárioPrimaryDeve ver estado mais recente de credenciais
Status de pedido pós-checkoutPrimaryUsuário acabou de pagar — lag inaceitável
Dashboard analíticoReplicaSegundos de lag OK
Paginação de busca/listagemReplicaAlto volume, eventual OK
Exportações de reportingReplicaScans longos prejudicam o primary
Read-after-write na mesma requestPrimaryBug clássico de lag de replicação

Lag de replicação é o TTL de cache da réplica

Réplicas são eventualmente consistentes. O lag varia:

  • Normal: milissegundos a poucos segundos
  • Carga de escrita pesada: segundos
  • Manutenção de réplica, blip de rede: minutos possíveis

Mitigações:

Monitoramento de lag. Alertar quando lag de réplica excede o SLO — a mesma disciplina de SLIs sem time SRE.

Pinning de leituras críticas. Após escrita, rotear leituras subsequentes na mesma sessão para o primary por N segundos ou até confirmar catch-up de replicação.

Consciência de RPO/RTO. Promoção de réplica para failover é diferente de escalar leitura — saber quais réplicas são candidatas a promoção versus analytics somente leitura.

Evitar queries de "leitura" com muita escrita. Relatórios longos que bloqueiam linhas na réplica ainda prejudicam — réplicas não são compute grátis, são cópia da rota de escrita do primary.

Combinar cache e réplicas

Stack saudável usa ambos:

Write → Primary
Read (hot, stale-OK) → Cache → on miss → Replica
Read (must be fresh) → Primary
Read (heavy scan) → Replica (bypass cache — don't cache 10MB result sets)

Cachear resultados computados caros de leituras na réplica — não cada lookup de linha. Triggers de invalidação na escrita ainda são necessários, mas a réplica absorve carga SQL de cache miss.

Não cachear o que réplicas tratam barato na escala atual. Não rotear para réplicas o que exige leituras frescas ao milissegundo.

Dimensionamento de pool de conexões se divide entre primary e réplicas — connection pooling em serverless aplica a ambos; pools de réplica famintos causam timeouts na app que parecem falhas de banco.

Checklist operacional para roteamento a réplicas

  • Documentar requisito de consistência por endpoint — strong vs eventual.
  • Testes de integração que afirmem que rotas read-after-write atingem o primary.
  • Load test da rota de réplica de forma independente — saturação de réplica é incidente separado.
  • Revisão de queries: padrões N+1 de leitura prejudicam réplicas como o primary — corrigir queries antes de adicionar infra.
  • Indexar réplicas igual ao primary — réplicas executam os mesmos planos; índices faltando doem em dobro.

Como times devem escolher roteamento a réplicas em vez de mais cache?

Essas decisões esclarecem quando investir em complexidade de roteamento.

Quando lag de replicação é aceitável?

Quando o produto tolera dados de segundos atrás na leitura — dashboards, listagens, recomendações. Não quando o usuário acabou de mutar entidade e espera reflexo imediato — pin no primary.

Quantas réplicas bastam?

Escalar até que p99 de leitura em rotas roteadas atinja SLO no pico. Uma réplica é single point of failure para a rota de leitura — planejar perda de réplica com failover de leituras para o primary com headroom de capacidade ou segunda réplica.

O ORM deve auto-rotear todos os SELECT para réplica?

Default perigoso. Auto-roteamento sem flags de consistência por query causa bugs sutis — status de checkout da réplica, checagens de permissão da réplica. O explícito vence a magia.

Uma visão oposta

A postura contrária sustenta que réplicas duplicam custo e complexidade — que melhor cache e otimização de queries eliminam carga de leitura no primary.

Otimização de queries é obrigatória de qualquer forma. Cache ajuda em rotas quentes. Réplicas abordam volume de leitura de cauda longa e scans imprevisíveis que resistem ao keying de cache. Com ratio leitura/escrita suficiente, custo de réplica é previsível; tempestades de cache miss não são.

Ofertas de Postgres serverless costumam incluir réplicas de leitura — disciplina de roteamento importa mesmo quando a infra é gerenciada.

Key takeaways

  • Cache esconde carga de leitura até invalidação falhar; réplicas distribuem carga com lag de replicação limitado.
  • Roteamento explícito por query — leituras strong no primary, leituras eventual na réplica.
  • Read-after-write na mesma sessão deve pin no primary ou aguardar catch-up.
  • Combinar cache (resultados quentes) com réplicas (execução SQL) — não um ou outro.
  • Monitorar lag de réplica como SLI; alertar antes de usuários verem dados obsoletos.
  • Indexar e otimizar queries antes de escalar réplicas — SQL ruim escala mal em todo lugar.

Conclusion

Roteamento de réplicas de leitura é honestidade sobre consistência: algumas leituras toleram lag, outras não. Cache sem essa honestidade produz hit rates que mentem sobre a saúde do sistema. Times que documentam regras de roteamento por endpoint dormem durante atualizações em massa; times que roteiam todos os SELECT para uma réplica se perguntam por que o checkout mostra pedidos pagos como pendentes.

Começar com inventário de endpoints: quais leituras exigem consistência forte? Todo o resto é candidato a réplica — depois medir lag, depois adicionar cache por cima onde a economia justificar.

Artigos relacionados

Paleta de comandos

Pesquise um comando para executar...