O Redis, abreviação para Remote Directory Server, é um sistema de armazenamento remoto de estrutura de dados em memória, sendo um banco de dados de código aberto licenciado sob BSD. Destaca-se por seu alto desempenho, replicação e um modelo de dados exclusivo.
Redis oferece uma variedade de estruturas de dados, como strings, hashes, listas, conjuntos, conjuntos classificados com consultas de intervalo, bitmaps, hiperloglogs, índices geoespaciais e fluxos.
Compatível com a maioria das linguagens de programação, o Redis é escrito em ANSI C e é funcional em diversos sistemas POSIX, como Linux e OS X, sem necessidade de dependências externas.
Hoje, você vai aprender a como integrar o Redis em uma aplicação Spring Boot, ao final vamos realizar um teste de desempenho em uma Api com o Postman, acompanhe até o final e melhore o desempenhos dos seus projetos em Java.
Integrando o Redis com Spring Boot
Vamos criar um tutorial detalhado, passo a passo, sobre como integrar o Redis com o Spring Boot. Neste tutorial, iremos utilizar o banco de dados Postgres e testar nossa API utilizando o Postman.
Configuração do Ambiente
Em primeiro momento, precisamos baixar o redis em seu ambiente de de desenvolvimento, caso você preferir baixar uma imagem no docker, segue abaixo as comandos:
docker pull redis/redis-stack-server:latest
Depois de baixar a imagem, você pode iniciar um contêiner Redis com o seguinte comando. Se a imagem ainda não estiver baixada, o comando cuidará disso, criando o contêiner ao mesmo tempo.
Agora, você tem a flexibilidade de definir o mapeamento da porta do servidor para uma porta diferente. Basta substituir “6379:6379” pela porta desejada, seguindo o formato “MY_PORT:6379”:
docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest
Configuração do Spring Boot
Crie um projeto Spring Boot, em nosso exemplo vamos utilizar a versão 17 do Java e versão superior a 3.x.x do Spring, porém você pode utilizar qualquer outra versão.
Repositório do projeto no GitHub: GuilhermeJWT/redis-spring-boot.
Adicione a seguinte dependência do Redis no arquivo pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
Agora precisamos habilitar a configuração de cache no projeto, na classe Principal do Spring Boot, adicione a seguinte anotação:
package br.com.virandoprogramador.redis_spring_boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @EnableCaching @SpringBootApplication public class RedisSpringBootApplication { public static void main(String[] args) { SpringApplication.run(RedisSpringBootApplication.class, args); } }
A anotação @EnableCaching é uma configuração do Spring Boot que facilita a implementação de cache em aplicações. Ao ser adicionada a uma classe de configuração ou à classe principal da aplicação, essa anotação habilita o suporte a caching no contexto do Spring.
Uma vez ativado, o Spring Boot gerencia o cache para métodos anotados com @Cacheable, @CachePut e @
CacheEvict. Essas anotações permitem definir o comportamento de caching para métodos específicos, melhorando o desempenho da aplicação, especialmente em operações que envolvem acesso a banco de dados, chamadas de API externas ou outros processos.
Configurando o arquivo application.properties
No seu arquivo application.properties, adicione as seguintes configurações:
spring.cache.type=redis spring.cache.redis.cache-null-values=true spring.data.redis.host=localhost spring.data.redis.port=6379
Observação: note que configuramos o host e porta do servidor Redis, se você adicionou alguma senha para acessar, utilize a variavel spring.data.redis.password, em nosso exemplo não iremos utilizar.
Após esse passo, já temos nosso ambiente configurado com Redis, os próximos passos será a criação de uma api bem simples para teste.
package br.com.virandoprogramador.redis_spring_boot.service; import br.com.virandoprogramador.redis_spring_boot.exception.UsuarioNaoEncontradoException; import br.com.virandoprogramador.redis_spring_boot.model.ModelUsuario; import br.com.virandoprogramador.redis_spring_boot.repository.UsuarioRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; @Service public class UsuarioService { @Autowired private UsuarioRepository usuarioRepository; @Cacheable(value = "ModelUsuario") public List<ModelUsuario> listarUsuarios(){ return usuarioRepository.findAll(); } @Cacheable(value = "ModelUsuario", key = "#id") public ModelUsuario pesquisaPorId(Long id){ Optional<ModelUsuario> modelUsuario = usuarioRepository.findById(id); return modelUsuario.orElseThrow(() -> new UsuarioNaoEncontradoException("Usuario não encontrado")); } public ModelUsuario salvarUsuario(ModelUsuario modelUsuario){ return usuarioRepository.save(modelUsuario); } @CachePut(value = "ModelUsuario", key = "#id") public ModelUsuario alterarUsuario(ModelUsuario modelUsuario, Long id){ ModelUsuario usuarioAlterado = usuarioRepository.findById(id) .orElseThrow(() -> new UsuarioNaoEncontradoException("Usuario não encontrado")); usuarioAlterado.setNome(modelUsuario.getNome()); usuarioAlterado.setEmail(modelUsuario.getEmail()); return usuarioRepository.save(usuarioAlterado); } @CacheEvict(value = "ModelUsuario", key = "#id") public void deletarUsuario(Long id){ ModelUsuario modelUsuario = usuarioRepository.findById(id) .orElseThrow(() -> new UsuarioNaoEncontradoException("Usuario não encontrado")); usuarioRepository.deleteById(modelUsuario.getId()); } }
Explicando as Anotações do Redis
Abaixo, irei detalhar como cada anotação está sendo utilizada no projeto, ao final vamos testar cada uma delas no Postman, e você ira ver o resultado.
Anotação @Cacheable
@Cacheable(value = "ModelUsuario") public List<ModelUsuario> listarUsuarios(){ return usuarioRepository.findAll(); }
Ao adicionar a anotação @Cacheable a um método que recupera a lista de usuários do banco de dados, o Spring Boot armazena em cache o resultado da chamada desse método.
Isso significa que, quando o método é chamado pela primeira vez, os dados são recuperados do banco de dados e armazenados em cache. Nas chamadas subsequentes ao mesmo método com os mesmos parâmetros, o Spring Boot recupera os dados diretamente do cache, evitando a necessidade de acessar o banco de dados novamente.
Anotação @CachePut
@CachePut(value = "ModelUsuario", key = "#id") public ModelUsuario alterarUsuario(ModelUsuario modelUsuario, Long id){ ModelUsuario usuarioAlterado = usuarioRepository.findById(id) .orElseThrow(() -> new UsuarioNaoEncontradoException("Usuario não encontrado")); usuarioAlterado.setNome(modelUsuario.getNome()); usuarioAlterado.setEmail(modelUsuario.getEmail()); return usuarioRepository.save(usuarioAlterado); }
Quando um método marcado com @CachePut é invocado, o Spring Boot executa o método e, em seguida, atualiza o cache com o resultado retornado pelo método.
Isso significa que, sempre que um usuário é alterado no banco de dados, o cache correspondente é atualizado com os novos dados.
Ao configurar a chave de cache com key=”#id”, você está indicando ao Spring Boot que o cache deve ser atualizado ou invalidado com base no ID do usuário que está sendo alterado. Isso garante que apenas o cache relacionado a esse usuário específico seja afetado pela alteração, mantendo os outros dados do cache intactos.
Anotação @CacheEvict
@CacheEvict(value = "ModelUsuario", key = "#id") public void deletarUsuario(Long id){ ModelUsuario modelUsuario = usuarioRepository.findById(id) .orElseThrow(() -> new UsuarioNaoEncontradoException("Usuario não encontrado")); usuarioRepository.deleteById(modelUsuario.getId()); }
Ao marcar um método com @CacheEvict, o Spring Boot identifica e remove as entradas relacionadas ao método especificado do cache. Isso é especialmente útil em operações de exclusão, onde é importante garantir que o cache seja atualizado corretamente após a remoção dos dados.
Ao configurar a chave de cache com key=”#id”, você diz para o Spring Boot a invalidar apenas o cache associado ao usuário que está sendo excluído. Isso garante que apenas os dados do cache relacionados a esse usuário específico sejam removidos, preservando as outras entradas do cache.
Testando o Cache no Postman
Agora vamos testar! você vai ver o resultado de aplicar Caches em suas aplicações.
Antes de ver o desempenho do cache, vamos criar uma Api com algumas rotas que serão chamadas pela camada UsuarioService, onde estão os métodos anotados com o Redis.
Classe: UsuarioController
package br.com.virandoprogramador.redis_spring_boot.controller; import br.com.virandoprogramador.redis_spring_boot.model.ModelUsuario; import br.com.virandoprogramador.redis_spring_boot.service.UsuarioService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("api/usuario") public class UsuarioController { @Autowired private UsuarioService usuarioService; @GetMapping("/listar") public ResponseEntity<List<ModelUsuario>> listarUsuario(){ return ResponseEntity.ok().body(usuarioService.listarUsuarios()); } @GetMapping("/pesquisar/{id}") public ModelUsuario pesquisarUsuario(@PathVariable Long id){ return usuarioService.pesquisaPorId(id); } @PostMapping("/salvar") public ResponseEntity<ModelUsuario> salvarUsuario(@RequestBody ModelUsuario modelUsuario){ return ResponseEntity.ok(usuarioService.salvarUsuario(modelUsuario)); } @PutMapping("/alterar/{id}") public ResponseEntity<ModelUsuario> alterarUsuario(@RequestBody ModelUsuario modelUsuario, @PathVariable Long id){ return ResponseEntity.ok(usuarioService.alterarUsuario(modelUsuario, id)); } @DeleteMapping("/deletar/{id}") public void deletarUsuario(@PathVariable Long id){ usuarioService.deletarUsuario(id); } }
No Postman, acesse as seguintes rotas:
- localhost:8080/api/usuario/salvar
- localhost:8080/api/usuario/alterar/1
- localhost:8080/api/usuario/listar
- localhost:8080/api/usuario/pesquisar/1
- localhost:8080/api/usuario/deletar/1
Salve alguns dados na api de salvar, nós vamos testar o métodos listar todos e verificar o desempenho utilizando cache.
Api de Listar Usuários:
Observação: note que a primeira consulta na api de listar Usuários, levou 1034 milissegundos para retornar os dados do banco de dados.
A segunda consulta deve retornar em um tempo muito menor utilizando o cache:
Observação: note que na segunda consulta, o tempo de resposta do servidor foi de apenas 22 milissegundos, os dados foram armazenados em cache na primeira consulta, logo na segunda a aplicação não precisa consultar o banco de dados para recuperar esses dados. Agora basta testar o cache nos outros endpoints =).
Conclusão sobre Caches com Redis e Spring Boot
Desenvolvemos uma API REST utilizando Spring Boot e Redis para armazenar e gerenciar os dados dos usuários. Durante os testes de desempenho, observamos uma melhoria significativa no tempo de resposta ao utilizar o cache do Redis.
Ao listar os usuários pela primeira vez, a consulta levou 1034 milissegundos para ser concluída. No entanto, após o resultado ser armazenado em cache pelo Redis, a segunda consulta teve seu tempo de execução drasticamente reduzido para apenas 22 milissegundos.
Essa diferença de desempenho evidencia os benefícios do caching em operações repetidas, onde o Redis permite armazenar e recuperar dados rapidamente, minimizando a necessidade de acessar o banco de dados repetidamente.
Perguntas Frequentes
O que é Redis e para que serve?
O Redis é um armazenamento remoto de estrutura de dados na memória, caracterizado por sua eficiência e desempenho. Pode ser utilizado de várias maneiras, oferecendo soluções em diferentes contextos:
Banco de Dados na Memória:
O Redis pode ser empregado como um banco de dados na memória, proporcionando um espaço eficiente para armazenamento e recuperação de dados. Sua natureza No-SQL elimina a necessidade de tabelas, sequências ou junções, permitindo o armazenamento de dados em diversos formatos, como strings, hashes, listas e conjuntos.
Esse modelo simplificado é acompanhado de serviços integrados, tornando-o uma opção viável para muitas aplicações.
Cache:
Uma das utilizações mais comuns do Redis é como um sistema de cache para aumentar o desempenho de aplicativos. Ao armazenar dados em memória, o Redis reduz a necessidade de consultas repetidas ao banco de dados, agilizando o acesso a informações frequentemente acessadas.
Isso é especialmente benéfico em cenários onde a resposta rápida é essencial, como em aplicativos web e móveis.
Message Broker (MQ):
Redis pode funcionar como um Message Broker, facilitando a comunicação assíncrona entre diferentes componentes de um sistema distribuído.
Ele oferece suporte a diferentes padrões de mensagens, como pub/sub (publicar/inscrever-se), filas de mensagens e filas de tópicos, tornando-o uma escolha popular para sistemas de mensageria em tempo real.
Como acessar o Redis?
Para acessar o Redis, a ferramenta mais comum é o redis-cli, uma interface de linha de comando que permite interagir diretamente com o Redis a partir do terminal. Com o redis-cli, os usuários têm maior liberdade na leitura e manipulação dos dados armazenados no Redis.
Outro ponto bem legal, é possível enviar instruções administrativas para o Redis usando o console, o que pode ser útil para fins de automação de scripts ou para realizar tarefas de manutenção e gerenciamento do banco de dados.
Qual a vantagem de usar Redis Cache em sua aplicação?
Usar Redis Cache em sua aplicação oferece uma série de vantagens. Em primeiro lugar, o Redis é extremamente rápido e eficiente, o que significa que pode armazenar e recuperar dados em tempo recorde, reduzindo significativamente o tempo de resposta da sua aplicação.
O Redis também é altamente escalável e robusto, capaz de lidar com grandes volumes de dados e cargas de trabalho intensas sem comprometer o desempenho.