Cache sem Redis: Como Reduzi Latência de API em 95%
4,2 segundos por requisição. Esse era o tempo que minha plataforma levava para processar cada lead — e tempo de resposta acima de 3 segundos já é suficiente para aumentar taxa de rejeição em mais de 50%.
Cache modular é uma arquitetura onde cada módulo de dados gerencia o próprio cache de forma independente, com TTL e estratégia de invalidação específicos para o tipo de dado que serve — ao contrário de um cache central com configuração única para tudo. Foi essa abordagem que me levou de 4,2s para 180ms sem adicionar nenhuma infraestrutura nova.
Vou te mostrar a arquitetura, os problemas reais que encontrei no caminho e o resultado depois de 12 dias em produção.
O Problema: Três APIs Chamadas do Zero a Cada Requisição
A plataforma consulta três APIs (interfaces padronizadas de comunicação entre sistemas) externas a cada operação. Sem cache, cada requisição refaz o mesmo trabalho do zero. Em testes com 50 usuários simultâneos, o sistema degrada a ponto de timeout — e timeout em horário de pico significa lead perdido.
Tentei o Redis (banco de dados em memória amplamente usado para cache) como primeira solução. Mas adicionar uma nova camada de infraestrutura significava mais dependência, mais ponto de falha e custo de manutenção que não queria agora. Precisava de outra abordagem.
O insight veio de uma analogia com DLLs (Dynamic Link Libraries — arquivos de código reutilizável que múltiplos programas compartilham sem duplicar). Em vez de um cache central que serve tudo igual, cada módulo de dados gerencia o próprio cache de forma independente. Configurações de sistema têm TTL longo. Dados de lead têm TTL curto. Cada módulo sabe exatamente o que precisa.
A Arquitetura: Cache Modular em Três Camadas
O contrato de cada módulo é simples. Implementado em TypeScript (versão tipada do JavaScript que detecta erros antes da execução):
interface CacheModule<T> {
key: string // namespace do módulo — prefixo único que evita conflitos
ttl: number // time-to-live — tempo em segundos que o dado permanece válido
fetch: () => Promise<T> // função que busca os dados quando o cache expira
}
Camada 1 — Memória local com LRU: LRU (Last Recently Used) é o algoritmo que descarta os dados acessados há mais tempo quando a memória enche. Para dados que raramente mudam — configurações, planos, metadados — essa camada responde em 3–8ms sem nenhuma chamada de rede. É o nível mais rápido e o primeiro consultado em cada requisição.
Camada 2 — Stale-while-revalidate: Stale-while-revalidate (servir o dado desatualizado enquanto busca o novo em background — processo rodando em paralelo, sem bloquear o usuário) é o padrão que browsers já usam há anos. A especificação está documentada no web.dev. Adaptei para chamadas de API no backend: o usuário recebe a resposta imediatamente, a atualização acontece por baixo.
O hash (código único gerado a partir dos parâmetros de cada requisição) garante que combinações diferentes de parâmetros sejam cacheadas separadamente. A documentação oficial do TypeScript foi referência central para implementar os tipos genéricos corretamente.
Camada 3 — Invalidação por evento: Para dados críticos que não podem ficar desatualizados, o cache é invalidado quando eventos específicos acontecem — não quando o TTL expira. Uma atualização de plano, por exemplo, invalida imediatamente o cache daquele usuário. Mais preciso e menos desperdício de recursos do que polling por tempo.
Os Problemas Reais no Caminho
Hot reload quebrando o cache
Hot reload (recarga automática do código durante o desenvolvimento sem reiniciar o servidor) estava invalidando o cache inteiro a cada mudança de arquivo. Levei meia tarde para identificar — o sintoma era latência inconsistente em desenvolvimento que não aparecia em produção. A solução foi simples: um flag de ambiente que desativa o cache completamente em desenvolvimento.
Memory leak no LRU
Memory leak (vazamento de memória — consumo crescente que nunca é liberado) aconteceu porque o LRU estava sem limite de tamanho máximo por módulo. O processo acumulava entradas indefinidamente. Corrigi definindo um teto de entradas por módulo e adicionando log de uso de memória para monitorar em produção.
Cache stampede nos edge cases
Edge cases (situações extremas que escapam do fluxo normal) mais difíceis: dois processos tentando popular o mesmo cache simultaneamente. Sem controle, ambos fazem a chamada externa ao mesmo tempo — anulando o benefício do cache. Implementei um lock simples: o primeiro processo busca e popula, os demais aguardam o resultado em background.
Resultado: 12 Dias em Produção
- Latência média: 4,2s → 180ms (redução de 95,7%)
- Hit rate: 87% das requisições atendidas direto pelo cache
- Custo adicional de infraestrutura: R$0
- Tempo de implementação com vibe coding: 5 dias
Nenhum incidente de estabilidade desde o deploy. Consumo de memória estável, sem crescimento ao longo do tempo.
Por Que o Vibe Coding Acelerou Tudo
Sozinho eu chegaria nessa arquitetura? Provavelmente. Em uma semana? Não.
Trabalhando com IA no ciclo de implementação, o processo de identificar os padrões certos, gerar os tipos TypeScript e refatorar sem quebrar o que já funcionava ficou muito mais rápido. A IA não entrega a solução pronta — ela acelera cada iteração. Identifica padrões de cache que eu levaria horas pesquisando, sugere edge cases que eu testaria só depois de ver em produção.
Já falei sobre esse padrão em outro contexto: usando IA na pós-graduação o resultado é o mesmo. Mais ciclos de experimentação por dia, resultado melhor ao final. Se quiser ver quais ferramentas de IA realmente entregam no dia a dia, veja as 8 IAs que uso para gerenciar campanhas — algumas se aplicam diretamente ao desenvolvimento. E para quem quer aplicar essa mesma lógica de automação no atendimento, mostrei como criar um chatbot sem programar usando ferramentas no-code. Se o objetivo for ir além e construir um produto digital completo com esse método, o Criar Produto Digital Sem Programar: Guia 2026 cobre todo o processo do zero. Para um exemplo prático de automação com WhatsApp, documentei como Construí um Bot de WhatsApp com IA Sem Programar — o mesmo método aplicado a um canal de alto volume.
FAQ: Dúvidas sobre Cache Modular
O que é cache modular e quando usar?
Cache modular é a abordagem de dar a cada módulo de dados a própria estratégia de cache — TTL, algoritmo de invalidação e política de atualização específicos para o tipo de dado que aquele módulo serve. Faz sentido usar quando diferentes partes da aplicação têm perfis de leitura muito diferentes: configurações mudam raramente, dados de sessão mudam o tempo todo. Um cache único com TTL global ou força revalidações desnecessárias ou serve dados velhos demais.
Qual a diferença entre cache modular e Redis?
Redis é a camada de armazenamento — um banco em memória que pode servir como cache. Cache modular é a arquitetura de como os módulos da aplicação interagem com o cache, independente de onde os dados ficam armazenados. Você pode implementar cache modular usando Redis como storage, usando memória local, ou ambos em camadas. No meu caso usei memória local para evitar a dependência de infraestrutura externa, mas o padrão modular funcionaria com Redis igualmente.
O que é cache stampede e como evitar?
Cache stampede acontece quando o cache de uma chave expira e múltiplas requisições simultâneas tentam populá-la ao mesmo tempo — todas fazem a chamada externa e apenas uma vence, desperdiçando o trabalho das demais e sobrecarregando a API de origem. A solução mais simples é um lock por chave: a primeira requisição adquire o lock, faz a chamada e popula o cache, as demais aguardam o resultado em vez de disparar novas chamadas.
Vale a pena implementar sem Redis para projetos pequenos?
Vale, especialmente no início. Redis adiciona dependência de infraestrutura, custo de manutenção e mais um ponto de falha. Para plataformas com até alguns milhares de usuários simultâneos, cache em memória local com LRU e stale-while-revalidate resolve a maioria dos gargalos sem complexidade adicional. A migração para Redis mais tarde é direta — basta trocar a implementação de storage dentro de cada módulo sem mudar a interface.
O princípio é replicável independente do stack: cada módulo de dados precisa da própria estratégia de cache. Não um cache global que serve tudo com o mesmo TTL.
Se sua plataforma tem gargalos de performance — tempos acima de 1 segundo, usuários reclamando de lentidão, timeouts em horário de pico — entre em contato para uma auditoria de arquitetura e performance.
Este artigo foi útil?
CEO @leadmarkbr · Especialista em SEO e Tráfego Pago
CEO da LeadMark desde 2012. Mais de 15 anos em Google Ads, SEO/GEO e Meta Ads. Gero +60k leads/mês para 30 mil corretores de planos de saúde em todo o Brasil. Certificado Google Ads Search. Palestrante em eventos de marketing digital.
Nenhum comentário ainda
Seja o primeiro a compartilhar sua opinião