Redis Cache (Cache Aside)

TTL, eviction e invalidação

Configurando expiração e invalidação para evitar dado stale no customer-service.

Avançado 30 min 25 pontos Leitura 0%

Nesta aula você vai

  • Definir TTL adequado para perfil de leitura de cliente
  • Configurar eviction policy do Redis no ambiente local
  • Invalidar cache em update e delete de cliente

TTL, eviction e invalidação

Objetivos

  • Evitar dados desatualizados no cache.
  • Manter memória Redis sob controle.
  • Garantir consistência após escrita no banco.

Pré-requisitos

  • Aula anterior (cache-aside-por-que-como) concluída.
  • Redis com persistência e métricas habilitadas.
  • Operações PUT e DELETE no customer-service.

Conceito

TTL limita tempo de vida. Eviction define como Redis remove chaves quando a memória acaba. Invalidação garante que um dado alterado no banco não continue sendo servido do cache antigo.

Estrutura de arquivos

infra/redis/
└── redis.conf
services/customer-service/src/main/java/br/com/sistemasamo/customer/
├── cache/CustomerCacheRepository.java
└── service/CustomerService.java

Passo a passo

  1. Configure Redis (infra/redis/redis.conf):
maxmemory 256mb
maxmemory-policy allkeys-lru
  1. Defina TTL com jitter no cache:
public void put(CustomerResponse value) {
  try {
    long jitterSeconds = ThreadLocalRandom.current().nextLong(0, 30);
    Duration ttl = Duration.ofMinutes(10).plusSeconds(jitterSeconds);
    redis.opsForValue().set(key(value.id()), objectMapper.writeValueAsString(value), ttl);
  } catch (Exception ignored) {
  }
}
  1. Invalide após update e delete em CustomerService.java:
@Transactional
public CustomerResponse updateCustomer(String id, UpdateCustomerRequest request) {
  Customer entity = customerRepository.findById(id)
      .orElseThrow(() -> new NotFoundException("Cliente não encontrado: " + id));

  entity.setName(request.name());
  entity.setEmail(request.email());
  customerRepository.save(entity);
  cacheRepository.evict(id);
  return mapper.toResponse(entity);
}

@Transactional
public void deleteCustomer(String id) {
  customerRepository.deleteById(id);
  cacheRepository.evict(id);
}
  1. Método de remoção:
public void evict(String customerId) {
  try {
    redis.delete(key(customerId));
  } catch (Exception ignored) {
  }
}

Como testar

docker compose up -d redis customer-service postgres
curl -s http://localhost:8081/customers/c-2 | jq
curl -s -X PUT http://localhost:8081/customers/c-2 \
  -H "Content-Type: application/json" \
  -d '{"name":"Cliente Novo","email":"novo@sistemasamo.com"}' | jq
curl -s http://localhost:8081/customers/c-2 | jq

No Redis CLI:

docker compose exec redis redis-cli TTL customer-service:customer:c-2

Dicas de projeto

  • Use jitter no TTL para reduzir cache stampede.
  • Prefira invalidação explícita em dados críticos.
  • Acompanhe evicted_keys e used_memory nas métricas.

Erros comuns

  • Aplicar TTL=0 sem querer (chave sem expiração).
  • Atualizar banco e esquecer invalidação.
  • Usar policy noeviction com memória subdimensionada.

Resumo

Você configurou TTL, eviction e invalidação de forma prática, deixando o cache rápido sem abrir mão da consistência.