Penetração de Cache + Soluções
- Penetração de Cache (consultando dados inexistentes)
- Quando uma consulta não encontra dados no cache, devido a uma falha no cache e por razões de tolerância a falhas, a solicitação é direcionada para a camada de armazenamento
- Se os dados não forem encontrados na camada de armazenamento, esses dados inexistentes não são gravados no cache
- Risco: Se muitas solicitações consultarem dados inexistentes, sem acertar o cache e sem gravar no cache, as solicitações contínuas para a camada de armazenamento podem sobrecarregar o banco de dados
- Prevenção
- Adicionar validação na camada de interface para verificar a validade dos dados
- Para chaves que não existem nem no cache nem no banco de dados, pode-se gravar "key-null" no cache com um tempo de expiração curto para evitar ataques contínuos pela mesma chave
- Solução com SpringCache
- Cacheie também resultados vazios, o que é o comportamento padrão quando não há configuração de condition ou unless
cache:
# Tipo de cache utilizado
type: redis
# Tempo de expiração
redis:
time-to-live: 3600000
# Habilitar prefixo, padrão é true
use-key-prefix: true
# Prefixo da chave, o padrão é o nome do cache cacheNames
key-prefix: MEU_CACHE
# Se deve cachear valores nulos, para evitar penetração de cache, padrão é true
cache-null-values: true
Quebra de Cache + Soluções
- Quebra de Cache
- Quando uma chave quente expira, nesse momento, muitas solicitações para essa chave quente não encontram o cache e são direcionadas para o banco de dados, causando um aumento explosivo na solicitação ao banco de dados e aumento da pressão
- Prevenção
- Definir chaves quentes para nunca expirar
- Atualizar o cache de chaves quentes através de tarefas programadas
- Definir um mutex lock
- Solução com SpringCache
- Sincronização de cache sync
- O sync pode instruir a camada subjacente a bloquear o cache, permitindo que apenas uma thread entre no cálculo, enquanto outras threads são bloqueadas até que o resultado seja retornado e atualizado no cache
@Cacheable(value = {"produto"}, key = "#root.args[0]", cacheManager = "gerenciadorCachePersonalizado", sync=true)
Avalanche de Cache + Soluções
- Muitas chaves foram configuradas com o mesmo tempo de expiração, fazendo com que todos os caches expirem ao mesmo tempo, causando um aumento instantâneo nas solicitações ao banco de dados e um aumento súbito na pressão, resultando em uma avalanche
- Prevenção
- Definir tempos de expiração aleatórios para os dados armazenados, para evitar o fenômeno de muitos dados expirando ao mesmo tempo
- Definir dados quentes para nunca expirar, atualizando-os periodicamente através de tarefas programadas
- Solução com SpringCache
- Definir diferentes tempos de expiração
- Por exemplo, configurar múltiplas dimensões de tempo de expiração no CacheManager
- Configuração do arquivo time-to-live
cache:
# Tipo de cache utilizado
type: redis
# Tempo de expiração
redis:
time-to-live: 3600000
# Habilitar prefixo, padrão é true
use-key-prefix: true
# Prefixo da chave, o padrão é o nome do cache cacheNames
key-prefix: MEU_CACHE
# Se deve cachear valores nulos, para evitar penetração de cache, padrão é true
cache-null-values: true
Chaves Quentes + Soluções
Riscos do armazenamento inadequado de chaves quentes: Algumas chaves no cache correspondem a valores armazenados em uma única máquina do cluster, fazendo com todo o tráfego se dirija para a mesma máquina, tornando-a um gargalo do sistema, incapaz de ser resolvido aumentando a capacidade da máquina
Soluções
- Evitar influência de largura de banda ou transmissão, armazenando dados de chaves quentes no cache local. Para cada solicitação de leitura, primeiro verifica se a chave existe no cache local; se existir, retorna diretamente; caso contrário, acessa a máquina de cache distribuída
- Cluster de alta disponibilidade ou modo mestre-escudeiro-sentniela, armazenando chaves quentes no cache local, com armazenamento uniforme dos dados