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.
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
| Symptom | Likely cause | Replica vs cache |
|---|---|---|
| Tempestades de invalidação após escritas em massa | Explosão de chaves de cache | Réplicas absorvem pico de leitura diretamente |
| Leituras obsoletas quebram confiança do usuário | TTL longo demais ou invalidação omitida | Réplicas: lag limitado, muitas vezes subsegundo |
| Custo de memória excede custo de leitura no DB | Working set grande | Réplicas mais baratas por GB escaneado |
| Padrões de query complexos | Difícil chavear entradas de cache | Réplicas executam SQL; cache precisa de chaves sob medida |
| Cache frio após deploy | Todos os misses de uma vez | Ré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:
-
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. -
ORM / middleware. Splitter read/write intercepta
SELECTversusINSERT/UPDATE/DELETE. -
Proxy. PgBouncer, RDS Proxy ou router custom — centraliza roteamento; o risco é magia opaca se times não entendem as regras.
-
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 type | Route | Reason |
|---|---|---|
| Checagem de auth de sessão do usuário | Primary | Deve ver estado mais recente de credenciais |
| Status de pedido pós-checkout | Primary | Usuário acabou de pagar — lag inaceitável |
| Dashboard analítico | Replica | Segundos de lag OK |
| Paginação de busca/listagem | Replica | Alto volume, eventual OK |
| Exportações de reporting | Replica | Scans longos prejudicam o primary |
| Read-after-write na mesma request | Primary | Bug 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.