Use of Redis pipeline technology

Use of Redis pipeline technology

table of Contents

Redis pipeline technology

Redis is a TCP service based on - (C/S )and /.

This means that under normal circumstances a request will follow the following steps:

  • The client sends a query request to the server and listens to the Socket to return, usually in blocking mode, waiting for the server to respond.

  • The server processes the commands and returns the results to the client.

This is the normal request model.

The so-called RTT (Round-Trip Time) is the round-trip time delay. It is an important performance indicator in a computer network. It means that the data is sent from the sender to the sender receives the confirmation from the receiver (after the receiver receives the data) Then send the confirmation immediately), the total time delay experienced.

Generally speaking, one-way delay = transmission delay t1 + propagation delay t2 + queuing delay t3

To solve this problem, Redis supports pipes to reduce RTT.

SpringDataRedis uses pipeline

SpringDataRedis provides executePipelinedmethods to support pipelines.

The following is the operation of a Redis queue, which is put into the pipeline for operation.

package net.ijiangtao.tech.framework.spring.ispringboot.redis.pipelining;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import java.time.Duration;
import java.time.Instant;

/**
 * Redis Pipelining
 *
 * @author ijiangtao
 * @create 2019-04-13 22:32
 **/
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class RedisPipeliningTests {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String RLIST = "test_redis_list";

    @Test
    public void test() {

      Instant beginTime2 = Instant.now();

      redisTemplate.executePipelined(new RedisCallback<Object>() {
          @Override
          public Object doInRedis(RedisConnection connection) throws DataAccessException {
              for (int i = 0; i < (10 * 10000); i++) {
                  connection.lPush(RLIST.getBytes(), (i + "").getBytes());
              }
              for (int i = 0; i < (10 * 10000); i++) {
                  connection.rPop(RLIST.getBytes());
              }
              return null;
          }
      });

      log.info(" ***************** pipeling time duration : {}", Duration.between(beginTime2, Instant.now()).getSeconds());

  }
}
 

Note executePipelinedthat the doInRedismethod returns always as null.

Redis pipeline performance test

The above briefly demonstrates how the pipeline is used, so what is the performance of the pipeline?

Let's verify it together.

First of all, redis provides redis-benchmarktools to test performance. I opened the command line through cmd on my computer, did not use pipes, and performed a million set and get operations. The effects are as follows:

$ redis-benchmark -n 1000000 -t set,get -q
SET: 42971.94 requests per second
GET: 46737.71 requests per second
 

On average, more than 40,000 operation requests are processed per second.

-PUsing pipes through commands, the effect is as follows:

$ redis-benchmark -n 1000000 -t set,get -P 16  q
SET: 198098.27 requests per second
GET: 351988.72 requests per second
 

After using the pipeline, the speed of set and get has become nearly 200,000 times and 350,000 times per second.

Then I tested the use of SpringDataRedis on the serverrpop dequeue 2000 times .

Respectively use single-threaded dequeue, 32-thread co-issued queue and single-threaded pipeline dequeue. Here are the results of the test:

From the statistical results, it takes about 6 seconds to dequeue 2000 times in a single thread; it takes about 2 seconds to concurrently request 32 threads; and it only takes about 70 milliseconds to use the pipeline in a single thread.

Precautions for using pipeline technology

When you want to make frequent Redis requests, in order to achieve the best performance and reduce RTT, you should use pipeline technology.

But if too many requests are sent through the pipe, it will also cause the Redis CPU usage to be too high.

The following is to monitor the CUP usage of the queue by sending a dequeue command to Redis in a loop:

When a large number of requests were accumulated in the pipeline, the CUP usage rate quickly rose to 100%, which is a very dangerous operation.

For the monitoring queue scenario, a simple method is to let the thread sleep for a few seconds when the content returned by the queue is found to be empty, and then wait for a certain amount of data to accumulate in the queue and then fetch it through the pipeline, so that you can enjoy it. The high performance brought by the pipeline avoids the risk of excessive CPU usage.

Thread.currentThread().sleep(10 * 1000);
 

Code example

Github-ispringboot-redis