Redis4.x(八):Pipeline管道技术

star2017 1年前 ⋅ 297 阅读

Redis 管道是客户端将多个命令打包一次性发送给服务器,不用等到单独命令的执行结果返回;而 Redis 管理需要服务器在执行所有的命令后返回结果,所有命令发送和接收只发生一次,大大减少了多个命令单独在网络的耗时延迟。Redis 管道官方文档

管道(pipeline)详解

Redis 是一个使用客户端/服务器模型,遵循请求/响应协议TCP服务器,这意味着完成请求(通信过程)需要经过以下步骤:

  1. 客户端向服务发送一个命令。
  2. 服务器收到命令并将其放入执行队列(阻塞方式,因为 Redis 是单线程执行模型)。
  3. 命令被执行。
  4. 服务器将命令执行结果返回给客户端。

客户端和服务器通常需要通过网络连接,数据包从客户端经网络传输到服务器,服务器返回结果到客户端,这发送和返回的时间称为往返时延(RTT)。当客户端需要发送多个命令时(例如,将多个元素加到同一列表等),很容易看出是影响性能的。
通信过程的第1步 和 第4步 耗费的时间完全取决于客户端和服务器之间的网络延迟。若执行多条个命令,服务器执行命令的时间非常短,而网络传输可能花费更多的时间。

Redis 管道是客户端将多个命令打包一次性发送给服务器,不用等到单独命令的执行结果返回;而 Redis 管理需要服务器在执行所有的命令后返回结果,所有命令发送和接收只发生一次,大大减少了多个命令单个在网络的耗时。

管道技术是广泛使用的技术。使如,许多 POP3 协议实现已经支持此功能,大大加快了从服务器下载电子邮件的过程。Redis 从行早就开始支持管道技术,不管运行的什么版本,可理解为使用管道技术可以不考虑版本是否支持的情况。

管道技术不仅仅可以减少由于往返时间而导致的延迟成功,还大大提高了在给定 Redis 服务中每秒可执行的总操作量。这是因为,在不使用管道技术的情况下,为每个命令提供服务,需要调用系统 read()write(),意味着从用户态内核态,在多命令情况下,频繁的上下文切换需要消耗巨大的系统性能。使用管道技术,通常调用一次read()可以读取多个命令,并调用一次write()返回多个执行结果。使用管道技术最多可以提高10倍的性能。

示例操作:

  1. 创建多个 Redis 命令操作的文件

    $ touch pipeline.txt
    $ vim pipeline.txt
    
    set key1 value1
    sadd key2 value21 value22
    get key1
    scard key2
    cat pipeline.txt
    
  2. 转换行尾结束符

    unix2dos pipeline.txt
    
  3. 使用 redis-cli--pipe 选项,通过管道发送命令

    $ cat pipeline.txt | /usr/local/redis/bin/redis-cli -a 123456 - -pipe
    Warning: Using a password with '-a' option on the command line interface may not be safe.
    All data transferred. Waiting for the last reply...
    Last reply received from server.
    errors: 0, replies: 4
    

Java 中使用Redis管道

Spring Boot 集成 Redis,使用 RedisTemplate 执行 Pipeline 操作。

/**
 * @name: SaveByPipeLine
 * @desc: 使用管道技术批量发送数据
 **/
@RunWith(SpringRunner.class)
@SpringBootTest
public class SendByPipeLine {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    /**
     * 使用管道技术
     */
    @Test
    public void saveByPipeLine(){

        RedisCallback<Object> redisCallback = new RedisCallback<Object>() {

            //doInRedis中的redis操作不会立刻执行
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                connection.openPipeline();

                //执行业务,打包多条命令
                for (int i = 0; i < 10000; i++) {
                    String key = "key:" + i;
                    String value = "value" + i;
                    connection.set(key.getBytes(), value.getBytes());
//                    connection.get(key.getBytes());
                }

                //所有redis操作会在connection.closePipeline()之后一并提交到redis并执行,这是pipeline方式的优势
//                List<Object> resultList = connection.closePipeline();
                return null;
            }
        };

        //所有操作的执行结果为executePipelined()的返回值
        List<Object> resultList = redisTemplate.executePipelined(redisCallback, redisTemplate.getStringSerializer());
        System.out.println(JSON.toJSONString(resultList));
    }
}

参考:
RedisTemplate使用PipeLine的总结

更多内容请访问:IT源点

相关文章推荐
  • 该目录下还没有内容!

全部评论: 0

    我有话说: