Spring Boot с Redis: конвейерные операции

Введение Redis - это хранилище данных в памяти, которое можно использовать как базу данных NoSQL, кеш или как типичный брокер сообщений. Он написан на ANSI C, который компилируется в значительно эффективный машинный код, а его способность хранить данные в виде пар ключ-значение делает кэширование в памяти привлекательным вариантом использования Redis, помимо сохранения данных на диске. В этой статье мы будем использовать конвейерную обработку, чтобы приложение Spring Boot могло отправлять несколько запросов на сервер Redis неблокирующим способом. U

Вступление

Redis - это хранилище данных в памяти, которое можно использовать как базу данных NoSQL, кеш или как типичный брокер сообщений. Он написан на ANSI C, который компилируется в значительно эффективный машинный код, а его способность хранить данные в виде пар ключ-значение делает кэширование в памяти привлекательным вариантом использования Redis, помимо сохранения данных на диске.

В этой статье мы будем использовать конвейерную обработку, чтобы приложение Spring Boot могло отправлять несколько запросов на сервер Redis неблокирующим способом.

Пример использования конвейерной обработки в Redis

Redis основан на архитектуре клиент / сервер (запрос / ответ). В этих архитектурах клиент обычно отправляет запрос или запрос на сервер и ожидает ответа. Обычно это делается блокирующим способом, так что новый запрос не может быть отправлен до тех пор, пока не будет отправлен ответ на последний:

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

Это может привести к значительной неэффективности с большой задержкой между получением команд и их обработкой.

Конвейерная обработка позволяет нам отправлять несколько команд как одну операцию клиента, не дожидаясь ответа от сервера между каждой командой. Затем вместо этого все ответы читаются вместе:

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

Поскольку клиент не ожидает ответа сервера перед отправкой другой команды, время ожидания уменьшается, что, в свою очередь, улучшает производительность приложения.

Примечание . Команды здесь помещаются в очередь. Эта очередь должна оставаться разумного размера. Если вы имеете дело с десятками тысяч команд, лучше отправлять и обрабатывать их партиями, чтобы преимущества конвейерной обработки не стали излишними.

Выполнение

Давайте продолжим и создадим небольшое приложение Spring Boot, которое работает с Redis и передает несколько команд по конвейеру. Это стало проще с помощью проекта Spring Data Redis .

Настройка Spring Boot

Самый простой способ начать с пустого приложения Spring Boot - использовать Spring Initializr :

инициализация весеннейзагрузки{.ezlazyload}

В качестве альтернативы вы также можете использовать Spring Boot CLI для начальной загрузки приложения:

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

Мы начинаем с spring-boot-starter-data-redis поскольку она включает в себя spring-data-redis , spring-boot-starter и lettuce-core .

Если у вас уже есть приложение Maven / Spring, добавьте зависимость в свой файл pom.xml

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

Или, если вы используете Gradle:

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

Мы также будем использовать Jedis в качестве клиента подключения вместо Lettuce:

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

Конфигурация Redis

Мы разместим Redis на Scalegrid , который предоставляет бесплатную пробную учетную запись для размещения экземпляра сервера Redis. Кроме того, вы можете загрузить сервер и разместить его на своем компьютере в Linux и MacOS. Windows требует небольшого взлома, и ее сложно настроить.

Давайте JedisConnectionFactory чтобы наше приложение могло подключаться к экземпляру сервера Redis. В вашем @Configuration аннотируйте соответствующий @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 - это входной класс, предоставляемый Spring Data, через который мы взаимодействуем с сервером Redis.

Мы передадим ему нашу настроенную фабрику соединений:

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

Мы установили сериализатор по умолчанию для хранения ключей и значений как String . В качестве альтернативы вы можете определить свой собственный сериализатор.

Конвейерная обработка с использованием RedisTemplate

Давайте добавим несколько элементов из списка на сервер Redis. Мы сделаем это без конвейерной обработки, используя RedisTemplate . В частности, мы будем использовать ListOperations , полученный из opsForList() :

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

Выполнение этого кода приведет к:

результаты операцииRedis{.ezlazyload}

Теперь давайте удалим это. Представляя, что это может быть дорогостоящая операция, мы будем конвейерно rPop() чтобы они отправлялись вместе и чтобы результаты синхронизировались после удаления всех элементов. Затем мы получим эти результаты обратно. Для конвейерных команд мы используем метод executedPipeline() .

Он принимает RedisCallback или SessionCallback которые мы ему предоставляем. Метод executedPipeline() возвращает результаты, которые мы затем можем зафиксировать и просмотреть. Если в этом нет необходимости и вы просто хотите выполнить команды, вы можете использовать метод execute() и вместо этого true в качестве pipeline

 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; 

Метод executePipelined() принял new RedisCallback() , в котором мы используем метод doInRedis() чтобы указать, что мы хотим сделать.

В частности, мы запустили метод rPop() 5 раз, удалив 5 элементов списка, которые мы вставили заранее.

После выполнения всех пяти этих команд элементы удаляются из списка и отправляются обратно - результаты упаковываются в список results

результаты конвейераRedis{.ezlazyload}

Заключение

Самый популярный вариант использования Redis - это хранилище кешей. Однако его также можно использовать в качестве базы данных или посредника сообщений.

Redis позволяет нам повысить производительность приложений за счет минимизации обращений к уровню базы данных. Его поддержка конвейерной обработки позволяет отправлять на сервер несколько команд за одну операцию записи, тем самым сокращая время приема и передачи на сервер и обратно.

В этой статье мы конвейеризовали несколько команд с помощью RedisTemplate API и проверили результаты.

comments powered by Disqus