Spring Boot con Redis: operaciones de canalización

S

 

Introducción

Redis es un almacén de datos en memoria, que se puede utilizar como base de datos NoSQL, caché o como un intermediario de mensajes típico. Está escrito en ANSI C, que se compila en un código de máquina significativamente eficiente y su capacidad para almacenar datos como pares clave-valor hace que el almacenamiento en caché en memoria sea un caso de uso atractivo para Redis, además de conservar los datos en un disco.

En este artículo, usaremos Pipelining para permitir que una aplicación Spring Boot envíe múltiples solicitudes al servidor Redis, de una manera sin bloqueo.

Caso de uso de canalización en Redis

Redis se basa en una arquitectura Cliente / Servidor (Solicitud / Respuesta). En estas arquitecturas, un cliente normalmente envía una consulta o solicitud al servidor y espera una respuesta. Por lo general, esto se hace de forma de bloqueo de modo que no se pueda enviar una nueva solicitud hasta que se envíe la respuesta de la última:

Client: <command 1>
Server: Response for <command 1>
Client: <command 2>
Server: Response for <command 2>
Client: <command 3>
Server: Response for <command 3>

Esto puede conducir a ineficiencias masivas, con una alta latencia entre recibir comandos y procesarlos.

La canalización nos permite enviar múltiples comandos, como una sola operación por parte del cliente, sin esperar la respuesta del servidor entre cada comando. Luego, todas las respuestas se leen juntas en su lugar:

Client: <command 1>
Client: <command 2>
Client: <command 3>
Server: Response for <command 1>
Server: Response for <command 2>
Server: Response for <command 3>

Dado que el cliente no espera la respuesta del servidor antes de emitir otro comando, se reduce la latencia, lo que a su vez mejora el rendimiento de la aplicación.

Nota: Los comandos aquí se colocan en una cola. Esta cola debe tener un tamaño razonable. Si está tratando con decenas de miles de comandos, es mejor enviarlos y procesarlos en lotes, no sea que los beneficios de la canalización se vuelvan redundantes.

Implementación

Sigamos adelante y creemos una pequeña aplicación Spring Boot que funcione con Redis y canalice múltiples comandos. Esto se hace más fácil con la ayuda del Spring Data Redis proyecto.

Configuración de Spring Boot

La forma más fácil de comenzar con una aplicación Spring Boot en blanco es usar Spring Initializr:

Alternativamente, también puede utilizar el Spring Boot CLI para arrancar la aplicación:

$ spring init --dependencies=spring-boot-starter-data-redis redis-spring-boot-demo

Empezamos con el spring-boot-starter-data-redis dependencia ya que incluye spring-data-redis, spring-boot-starter y lettuce-core.

Si ya tiene una aplicación Maven / Spring, agregue la dependencia a su pom.xml archivo:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
	<version>${version}</version>
</dependency>

O si está usando Gradle:

compile group: 'org.springframework.data', name: 'spring-data-redis', version: '${version}'

También usaremos Jedis como cliente de conexión, en lugar de Lettuce:

<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
	<version>${version}</version>
</dependency>

Configuración de Redis

Alojaremos Redis en Scalegrid, que proporciona una cuenta de prueba gratuita para alojar una instancia del servidor Redis. Alternativamente, puede descargar el servidor y alójelo en su propia computadora en Linux y MacOS. Windows requiere un poco de piratería y es complicado de configurar.

Vamos a configurar el JedisConnectionFactory para que nuestra aplicación pueda conectarse a la instancia del servidor Redis. En tus @Configuration clase, anote lo adecuado @Bean:

@Configuration
public class Config {
    @Bean
    public JedisConnectionFactory redisConnectionFactory() {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setHostName("<server-hostname-here>");
        jedisConnectionFactory.setPort(6379);
        jedisConnectionFactory.setPassword("<server-password-here>");
        jedisConnectionFactory.afterPropertiesSet();
        return jedisConnectionFactory;
    }
}

RedisTemplate es una clase de entrada proporcionada por Spring Data a través de la cual interactuamos con el servidor Redis.

Le pasaremos nuestra fábrica de conexiones configurada:

@Bean
public RedisTemplate<String, String> redisTemplate() {
    RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(redisConnectionFactory());
    redisTemplate.setDefaultSerializer(RedisSerializer.string());
    redisTemplate.afterPropertiesSet();
    return redisTemplate;
}

Hemos configurado el serializador predeterminado para almacenar claves y valores como String. Alternativamente, puede definir su propio serializador personalizado.

Canalización con RedisTemplate

Agreguemos algunos elementos de una lista al servidor Redis. Haremos esto sin canalizar, usando el RedisTemplate. Específicamente, usaremos el ListOperations interfaz, adquirida de opsForList():

List<String> values = Arrays.asList("value-1", "value-2", "value-3", "value-4", "value-5");
redisTemplate.opsForList().leftPushAll("pipeline-list", values);

Ejecutar este código resultará en:

Ahora, eliminemos estos. Imaginando que esta puede ser una operación costosa, canalizaremos cada rPop() comando para que se envíen juntos y que los resultados se sincronicen con todos los elementos que se eliminan. Luego, recibiremos estos resultados. Para canalizar comandos, usamos el executedPipeline() método.

Acepta un RedisCallback o SessionCallback que le proporcionamos. los executedPipeline() El método devuelve los resultados que luego podemos capturar y revisar. Si no es necesario y solo desea ejecutar los comandos, puede usar el execute() método y pasar true como el pipeline argumento en su lugar:

List<Object> results = redisTemplate.executePipelined(new RedisCallback<Object>() {
    public Object doInRedis(RedisConnection connection) throws DataAccessException {
        for(int i = 0; i < 5; i++) {
            connection.rPop("pipeline-list".getBytes());
        }
    return null;
     }
});
return results;

los executePipelined() método aceptado un new RedisCallback(), en el que usamos el doInRedis() método para especificar lo que nos gustaría hacer.

Específicamente, hemos ejecutado el rPop() método 5 veces, eliminando los 5 elementos de lista que hemos insertado de antemano.

Una vez que se han ejecutado los cinco comandos, los elementos se eliminan de la lista y se devuelven; los resultados se empaquetan en el results lista:

Conclusión

El caso de uso más popular de Redis es como almacén de caché. Sin embargo, también se puede utilizar como base de datos o como intermediario de mensajes.

Redis nos permite incrementar el rendimiento de las aplicaciones, minimizando las llamadas a la capa de base de datos. Su soporte para canalización permite que se envíen múltiples comandos al servidor en una sola operación de escritura, reduciendo así el tiempo de ida y vuelta hacia y desde el servidor.

En este artículo, hemos canalizado varios comandos utilizando el RedisTemplate API y verificó los resultados.

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad