System Design/02 - Componentes/Caching2 min
Refresh Ahead
- Que problema isso resolve?
- Quando usar / quando NÃO usar?
- Qual o principal trade-off?
- Como isso falha em produção?
Conceito
O cache atualiza a entrada antes de ela expirar, de forma proativa, para que o usuário nunca encontre um miss.
TTL = 60s, fator de refresh = 0,75
t=0 escrito no cache
t=45 alguém lê → serve do cache E dispara refresh em background
t=60 expiraria — mas já foi renovado
O gatilho usual: um acesso ocorre depois de 75% do TTL ter passado. A leitura é servida do cache imediatamente, e a atualização acontece fora do caminho da requisição.
Trade-offs
| Ganha | Perde |
|---|---|
| Usuário nunca paga o custo do miss | Prevê errado: atualiza o que ninguém vai pedir |
| Elimina o cache stampede | Carga constante na fonte |
| Latência previsível (sem cauda) | Complexidade a mais |
A eficácia depende inteiramente da previsibilidade do acesso. Para chaves consistentemente populares, refresh ahead é quase perfeito: elimina o miss e o stampede de uma vez. Para chaves de acesso esporádico, ele desperdiça — atualiza entradas que expirariam sem ninguém notar.
Daí a regra: aplique a poucas chaves, as mais quentes, não ao cache inteiro. Refresh ahead global transforma cache numa fonte de carga permanente sobre o banco.
O primo mais simples e frequentemente melhor é stale-while-revalidate: serve o dado vencido imediatamente e revalida em background. A diferença é sutil — SWR reage ao vencimento, refresh ahead se antecipa a ele — e SWR não desperdiça atualização em chave fria, porque só atualiza o que é realmente pedido.
Exemplo prático
Cotação de moeda exibida na home, consultada por milhares de usuários por minuto e vinda de uma API externa lenta (300 ms) e com limite de requisições.
Com Cache-Aside e TTL de 60 s: a cada minuto, o primeiro usuário espera 300 ms — e, sob concorrência, dezenas de requisições disparam a chamada externa simultaneamente, ameaçando o rate limit.
Com refresh ahead: aos 45 s uma atualização é disparada em background. Nenhum usuário espera, e a API externa recebe exatamente uma chamada por minuto.
O desperdício potencial — atualizar a cotação de madrugada, quando ninguém acessa — é irrelevante aqui, porque a chave é uma só e sempre quente. Se fossem 5.000 cotações de acesso irregular, a conta se inverteria.
Relacionado
Parte de Caching · roadmap.sh/system-design