Back home

Taxa de acertos de cache e qualidade da política de cache

A taxa de acerto é apenas um indicador de resultado. O que realmente determina o custo do sistema é o modo de falha, a pressão de retorno e o raio de propagação do erro.

Quando muitas equipes falam sobre cache, a primeira coisa que dizem é taxa de acerto.

Uma taxa de acerto de 95% parece boa; 98% parece estar otimizado; 99% dá até às pessoas a ilusão de que o sistema foi “domesticado”.

Mas quando algo dá errado online, todo mundo muitas vezes vê outro conjunto de problemas ao revisar: o banco de dados é invadido depois que um determinado lote de chaves expira ao mesmo tempo, os usuários ainda veem dados antigos dentro de uma hora após a alteração do preço, o nó do cache treme e as consultas mais caras chegam diretamente ao banco de dados principal.

Meu julgamento é simples: **O objetivo da estratégia de cache é controlar o custo de “erros”. ** Uma alta taxa de acerto significa apenas que muitas solicitações são lidas no cache; isso não significa que o projeto da falha esteja correto, não significa que o custo de retorno à fonte seja controlável e não significa que os erros serão limitados a uma pequena faixa.

Se um cache aumentar a taxa de acerto de 92% para 99%, mas ao custo de dificultar a invalidação, dificultar a localização de dados sujos e aumentar a probabilidade de formar uma tempestade de volta à origem durante o jitter, provavelmente não será uma otimização, mas apenas moverá a complexidade do banco de dados para outro canto.

A questão não é “quantos acertos”, mas “onde acertar quando errar”

O indicador de taxa de acerto tem uma falha natural: ele nivela a distribuição de quente e frio.

Uma interface recebe um milhão de solicitações por dia, das quais 990 mil leem detalhes de produtos populares e as 10 mil restantes leem produtos de cauda longa. Armazene em cache os dados populares e a taxa de acertos será muito boa imediatamente. Mas se essas 10.000 falhas de cauda longa ocorrerem na consulta mais lenta e mais cara que também envolve a união de tabelas, a pressão do banco de dados pode não ser menor do que se imagina.

Em outras palavras, a taxa de acerto é contada como “número de vezes”, mas o custo do sistema é frequentemente definido como “preço”. **

Isso também mostra que algumas equipes estão vendo claramente belos indicadores de cache, mas a CPU do banco de dados ainda não consegue desacelerar: o cache bloqueia solicitações baratas e erros realmente caros ainda estão em execução.

Ao julgar uma estratégia de cache, prefiro examinar primeiro três coisas:

  1. Perder a parte mais cara da solicitação;
  2. Se os erros ocorrerão de forma concentrada e não uniforme;
  3. A tensão será transmitida a jusante após a falha?

Essas três perguntas estão mais próximas do custo real do que “a taxa geral de acertos aumentou mais 2 pontos?”

O que realmente determina a qualidade do cache geralmente é o método de falha.

Muitos acidentes de cache são essencialmente “o design com falha é muito grosseiro”.

A abordagem mais comum é apenas definir um TTL. A implementação é simples e os indicadores são fáceis de melhorar, porque desde que o TTL seja longo o suficiente, a taxa de acerto geralmente não é tão ruim. Mas existem dois problemas típicos com esquemas TTL.

Primeiro, deixa tempo para decidir quando os dados irão expirar, em vez de mudanças nos negócios. **

Os preços mudaram, o inventário mudou, as permissões mudaram, mas o cache ainda está ativo. É claro que o TTL pode ser reduzido, mas uma vez reduzido o TTL, a frequência de retorno à fonte aumentará novamente. Muitas equipes ficam alternando entre “os dados antigos são muito antigos” e “o banco de dados está muito ocupado”.

Segundo, é fácil criar falhas de sincronização. **

Se um lote de teclas de atalho for gravado em um horário semelhante e usar o mesmo TTL, elas provavelmente expirarão juntas em um horário semelhante. Normalmente, a taxa de acerto é boa, mas assim que atingir o ponto de expiração, haverá um pico instantâneo de volta à fonte. Isso pode ser uma instabilidade de apenas cinco minutos no painel, mas é um impacto muito real no banco de dados e nos serviços downstream.

Portanto, o mais importante no design do cache é frequentemente se o mecanismo de falha está alinhado com as mudanças nos negócios.

Modificações comuns incluem:

  • Utilize falhas orientadas a eventos em vez de confiar apenas no TTL;
  • Adicione jitter aleatório ao TTL para evitar que as chaves do hotspot expirem ao mesmo tempo;
  • Coloque o número da versão ou carimbo de data/hora na chave para alternar explicitamente a geração de dados;
  • Permitir que valores antigos sejam retornados por um curto período de tempo, mas atualizados de forma assíncrona em segundo plano, em vez de fazer com que todas as solicitações voltem juntas para a origem.

O ponto principal aqui é que você precisa decidir quando aceitar dados antigos, quando eles devem ser consistentes imediatamente e quando você prefere retornar o resultado do downgrade a explodir o banco de dados principal. ** Esta é a estratégia de cache, e a taxa de acerto é apenas uma sombra dela.

Estender o TTL geralmente apenas adia o problema.

Já vi muitas “otimizações de cache” feitas assim: o banco de dados online está sob pressão, então o TTL é alterado de 5 minutos para 30 minutos e depois para 1 hora. Como resultado, a taxa de acerto aumentou e a curva do banco de dados ficou um pouco plana, e a equipe anunciou que a otimização foi concluída.

O mais perigoso desta abordagem é que é demasiado fácil parecer eficaz a curto prazo.

Porque a maioria dos sistemas de indicadores são melhores para registrar “quantas consultas são salvas” e não são bons para registrar “quantos dados errados são salvos”. Quando preços antigos, configurações antigas e permissões antigas são lidas por mais usuários, as perdas muitas vezes não são refletidas imediatamente no painel de cache, mas aparecerão posteriormente em reclamações, compensações, verificação manual e análises de acidentes.

Especialmente para os seguintes tipos de dados, muitas vezes é uma má ideia estender aproximadamente o TTL:

  • Dados que afetarão a liquidação do valor;
  • Dados que afetam permissões e visibilidade;
  • Dados que não são atualizados com frequência, mas devem convergir o mais rápido possível depois de atualizados.

Para este tipo de dados, se a maior taxa de acerto for obtida por “reconhecimento tardio de alterações”, está superestimando a precisão. **

A parte mais difícil do cache é limitar os erros

Uma situação comum é pensar no cache como “uma camada extra na frente do banco de dados”. Este entendimento não está errado, mas é demasiado optimista.

O cache em sistemas reais é uma superfície de tensão que amplifica as falhas de projeto. Se a chave for projetada com muita espessura, o escopo da falha será muito grande; se a chave for projetada muito fina, o uso de memória e a complexidade de manutenção aumentarão; a montagem de dados é colocada na camada de cache e é fácil repetir os cálculos ao retornar à fonte; o cache local e o cache distribuído são empilhados juntos e haverá uma camada adicional de problemas de consistência.

Portanto, dividirei a solução de cache em duas questões a serem revisadas:

  • Você costuma ficar feliz ou não?
  • Quando algo dá errado, isso prejudicará outras partes do sistema?

A última questão é geralmente mais importante.

Uma implementação de cache mais confiável geralmente lidará explicitamente com o seguinte:

v, ok := cache.Get(key)
if ok && !v.SoftExpired() {
  return v.Data
}

return singleflight.Do(key, func() any {
  fresh := db.Load(id)
  cache.Set(key, fresh, ttlWithJitter())
  return fresh
})

O que é realmente valioso aqui são duas restrições:

  • Quando a mesma chave é retornada para a origem, apenas uma requisição pode realmente atingir o banco de dados;
  • A expiração fornece ao sistema uma janela de atualização controlável.

Este tipo de projeto pode não atingir necessariamente a melhor taxa de acerto, mas pode reduzir significativamente as tempestades de retorno e a amplificação instantânea. Sem jitter, o sistema parece mais “desacelerar” do que “entrar em colapso”.

Um mal-entendido comum: tratar a taxa de acertos do cache como um KPI de equipe

Depois que a porcentagem atingida se torna um KPI, é fácil para as equipes trabalharem na direção errada.

Porque a maneira mais fácil de melhorar a taxa de acerto geralmente é melhorar os resultados estatísticos:

  • Alongamento TTL;
  • Colocar mais dados que não deveriam ser armazenados em cache;
  • Use teclas de granulação mais grossa para misturar cenas diferentes;
  • Dividir a interface para torná-la compatível com o cache piora a semântica do negócio.

Essas ações podem melhorar a aparência do gráfico, mas criarão outros problemas: a janela de dados sujos será mais longa, a falha será mais difícil, a solução de problemas será mais difícil, a memória será mais cara e os limites de negócios serão confusos.

Uma abordagem mais saudável é analisar o cache junto com as seguintes métricas:

  • A senhorita P95/P99 demora para retornar à fonte;
  • Número de chaves de hotspot back-to-source simultâneas;
  • Taxa de erros e pico do banco de dados após invalidação do cache;
  • O tempo que os dados levam para convergir para novos valores após a atualização;
  • Quantos caminhos de código e ações operacionais adicionais são introduzidos para manter o cache.

Somente quando esses custos são somados é que a taxa de acerto tem poder explicativo. Olhando sozinho, é muito fácil ser enganado.

Exemplo de contador: Em alguns cenários, a taxa de acerto deve ser a mais alta possível

Você não pode simplesmente dizer isso até a morte.

Se os dados forem naturalmente estáveis ​​ou simplesmente um recurso imutável, como arquivos estáticos, configurações versionadas, conteúdo de distribuição CDN e tabelas de dicionário que raramente mudam, então a taxa de acerto é de fato uma meta muito importante. Porque neste tipo de cenário, “mais antigo” não é um problema sério, a falha é relativamente simples e o caminho de volta à fonte geralmente é claro e controlável.

Existem também alguns sistemas internos baseados em ferramentas onde a quantidade de dados não é grande, a gravação é pouco frequente e o custo comercial de leituras sujas ocasionais também é muito baixo. Neste caso, uma solução TTL simples provavelmente está correta. Superficialmente parece sofisticado, mas na realidade está mais perto de ser barato o suficiente.

Portanto, este artigo é contra tirar a taxa de acertos do contexto e usá-la sozinha como evidência de que o cache foi bem-sucedido.

Resumo

Para avaliar se uma solução de cache é confiável, eu primeiro perguntaria: **O que acontecerá quando ocorrer a falha mais cara neste sistema? **

Se a resposta for “só um pouco mais lento, o sistema ainda pode estar estável”, então o cache provavelmente foi projetado.

Se a resposta for “a taxa de acerto geralmente é muito alta, mas quando falha, penetra no banco de dados principal e diminui a precisão”, então é apenas um perigo oculto que parece funcionar muito em momentos normais.

O cache nunca se trata apenas de “colocar os dados mais próximos”. O que realmente testa é como lidar com mudanças, falhas e custos. Uma alta taxa de acerto significa que você executou bem a primeira metade da frase, no máximo; é a segunda metade da frase que determina se a estratégia vale a pena.

FAQ

What to read next

Related

Continue reading