Cache é uma camada de armazenamento de alta velocidade utilizada para armazenar dados de forma temporária, reduzindo a quantidade de vezes que os dados precisam ser obtidos da fonte. Os dados são armazenados em um hardware de alta velocidade (como memória RAM) e possibilitam aumentar drasticamente a performance e escalabilidade horizontal de aplicações.
Pelo fato da memória RAM e dos componentes que trabalham diretamente em memória suportarem um alto número de requisições, realizar cache dos dados melhora a performance durante a obtenção dos dados e reduz custos, pois para suportar a mesma quantidade de requisições com componentes tradicionais (como um banco de dados) seriam necessários recursos adicionais, e mesmo assim estes componentes ainda ofereceriam uma latência mais alta do que a necessária.
Por conta disso, o cache de dados pode ser utilizado para os mais diversos casos de uso, como por exemplo:
Sistemas operacionais: utilizam cache para exibir arquivos acessados com frequência
CDNs: armazenam artefatos como páginas HTML, arquivos javascript, vídeos e imagens
Aplicações diversas: seja na web, desktop, redes sociais ou jogos, as aplicações utilizam cache para acelerar performance e reduzir a necessidade de obtenção de dados
DNS: o serviço que traduz domínios para IPs utiliza cache em seus servidores e é por isso que alterações de rotas e domínios podem demorar algumas horas para serem propagadas ao redor do globo
Browsers: os navegadores atuais utilizam cache client-side para arquivos estáticos (imagens, arquivos javascript, etc)
Existem diferentes estratégias de caching, cada uma com suas próprias vantagens e desvantagens. A escolha da estratégia mais adequada depende de vários fatores, incluindo o tipo de dado que está sendo armazenado, o nível de acesso aos dados e o nível de desempenho desejado. As estratégias mais comuns são:
Lazy Loading
É uma estratégia que armazena os dados em cache apenas quando os dados não estão no cache e são solicitados pelo usuário.
De forma mais detalhada, essa estratégia funciona da seguinte maneira:
- Um usuário solicita informações para sua aplicação
- A aplicação irá verificar no cache se essa informação já está armazenada nele
- Em caso positivo, a aplicação retorna os dados que estavam contidos no cache
- Em caso negativo, a aplicação realiza uma consulta externa para obter os dados (banco de dados, APIs), armazena a informação obtida no cache e retorna os dados para o usuário.
A vantagem dessa estratégia é que somente os dados requisitados pelos usuários são armazenados em cache, evitando popular o cache com informações que não serão utilizadas. Falhas no componente de cache não afetam a aplicação, que pode obter os dados diretamente na fonte.
A desvantagem dessa estratégia é o fato do tempo de resposta ser consideravelmente maior caso os dados não estejam armazenados em cache, além da possibilidade dos dados se tornarem obsoletos, pois são armazenados em cache no momento que são solicitados pelo usuário e não há atualização desses dados caso o cache já tenha sido populado.
Write-through
É uma estratégia que adiciona ou atualiza dados armazenados no cache sempre que eles são escritos/atualizados no banco de dados. Funciona da seguinte maneira:
- Um usuário realiza uma alteração em um registro armazenado no banco de dados
- O registro é atualizado no banco de dados
- O registro é adicionado ou atualizado no cache
A vantagem dessa estratégia é que os dados armazenados em cache nunca se tornam obsoletos, pois são atualizados sempre que houver interações com o banco de dados.
No entanto, isso adiciona mais latência no processo de atualização de registros, pois é necessário a gravação dos registros em cache toda vez que algum registro no banco de dados for atualizado. Portanto, utilize essa estratégia caso seu sistema e usuários sejam tolerantes a uma maior latênca durante a atualização de registros.
Outra desvantagem dessa estratégia é que a maioria dos dados armazenados em cache não serão utilizados. Ao salvar qualquer alteração em cache sem um tempo de expiração, os dados sempre estarão lá, mesmo que eles não sejam acessados, desperdiçando espaço em cache. Para amenizar esse efeito, podemos combinar a utilização dessa estratégia utilizando Time to Live (TTL), que é um valor (geralmente em segundos) que especifica em quanto tempo os dados no cache serão removidos.
TTL (Time To Live)
O TTL é um valor utilizado para definir a expiração de um registro no cache. Isso permite que o componente de cache saiba por quanto tempo um determinado registro deverá permanecer no conjunto de dados.
Ao utilizar um componente de cache como o Redis, é muito simples definir um TTL:
Na imagem acima, observe o efeito do TTL:
- É criada uma chave chamada “fruta” com o valor “Laranja” com um TTL de 60s
- A chave “fruta” foi obtida com sucesso, pois o registro ainda estava armazenado em cache
- A chave “fruta” retornou nulo, pois o registro expirou devido ao TTL
A utilização do TTL permite que o dado armazenado em cache não se torne obsoleto, ao mesmo tempo que ele possibilita economizar espaço em cache, pois quando o TTL for atingido (ou seja, chegar em 0) o registro será automaticamente deletado.
Conclusão
É importante escolher cuidadosamente qual estratégia de cache é a mais adequada para um determinado sistema, pois a escolha inadequada de uma estratégia pode ter um impacto significativo no desempenho e na escalabilidade. Os fatores a serem considerados na escolha de uma estratégia incluem o tamanho dos dados, frequência das atualizações, padrões de acesso e a necessidade de persistência dos dados. Em alguns casos, pode ser necessário usar uma combinação de estratégias para atingir o equilíbrio desejado.
O cache pode parecer a solução ideal para todos os lugares do sistema, pois é muito mais rápido recuperar dados do cache do que em consultas no banco de dados ou APIs externas. Porém, tenha em mente que algumas partes do sistema precisam obter dados em tempo real ou possuem um baixo tempo de tolerância a dados obsoletos.