Redis - 管道技术 pipeline

一、管道概念

1.1 为什么要有redis管道?

redis本身处理速度很快,但是如果你连续调用10条redis命令,它们要有10个网络来回,这速度就会降下来了,那么有没有办法把这10条命令一起发送到服务端呢?有,它就是redis管道

 

1.2 redis管道的本质是什么?

redis管道的本质是将要发往redis服务端执行的命令在客户端缓存起来,比如说缓存100条,然后你可以将这100条命令一起发送到redis服务端,从而将100个网络来回降低到1个来回,大大降低了网络开销,提升了性能。

 

1.3 redis管道优点是什么?

优点:

  • 多个指令之间没有依赖关系,一个命令出问题,不影响其他命令;
  • 可以使用 pipeline 一次性执行多个指令,减少 IO,缩减时间。

特点:

  • redis的管道,是客户端实现的技术,服务端稍微配合一下即可(读取批量命令执行,每条命令执行完后进行缓存,全部执行完后再一次性返回)。
  • 优点是大大减少了网络请求次数,提高了性能
  • 注意:由于执行结果是批量返回的,所以管道中的命令不宜太多,否则redis服务端的缓存压力将会变大,进而影响性能。
  • 注意:管道中的命令适合彼此没有关联的命令,如果一个命令的执行依赖上次执行的结果,那就不要用管道了。

 

二、Redis管道 vs Redis事务

从下方的流程图,可以看出区别:

1.命令在哪里缓存:

  • 事务里面的命令是在服务端缓存,当发出exec命令的时候,服务端就会判断并执行事务命令。
  • 管道里面的命令是在客户端缓存,当客户端结束管道后一次发送到服务端,服务端读取后按照先后顺序先后执行。
  • 但不管是事务还是管道,服务端都需要缓存单个命令的执行结果,等全部执行完后再返回给客户端

2.命令中出现语法错误,是否影响其他命令:

  • 事务里的命令如果有语法错误(比如:getset name,注意不是执行错误),会导致事务被丢弃,里面的命令都不会执行
  • 而管道里的命令如果出现语法错误,依然不影响其他的命令执行

3.命令执行过程:

  • 事务和管道里的命令执行过程中都不能被其他的命令插入(事务的肯定不会打断,管道的暂时认为不会打断吧)
  • 事务的命令指向前需要判断watch指定的值是否改变,如果改变了就不执行,而管道不会判断

 

事务流程图:

Redis - 管道技术 pipeline

管道流程图:
Redis - 管道技术 pipeline

 

 

三、代码示例:使用pipeline

下面就来对比一下使用管道和不使用管道的速度差异。

public class JedisDemo {

    private static int COMMAND_NUM = 1000;

    private static String REDIS_HOST = "Redis服务器IP";

    public static void main(String[] args) {

        Jedis jedis = new Jedis(REDIS_HOST, 6379);
        withoutPipeline(jedis);
        withPipeline(jedis);
    }

    private static void withoutPipeline(Jedis jedis) {
        Long start = System.currentTimeMillis();
        for (int i = 0; i < COMMAND_NUM; i++) {
            jedis.set("no_pipe_" + String.valueOf(i), String.valueOf(i), SetParams.setParams().ex(60));
        }
        long end = System.currentTimeMillis();
        long cost = end - start;
        System.out.println("withoutPipeline cost : " + cost + " ms");
    }

    private static void withPipeline(Jedis jedis) {
        Pipeline pipe = jedis.pipelined();
        long start_pipe = System.currentTimeMillis();
        for (int i = 0; i < COMMAND_NUM; i++) {
            pipe.set("pipe_" + String.valueOf(i), String.valueOf(i), SetParams.setParams().ex(60));
        }
        pipe.sync(); // 获取所有的response
        long end_pipe = System.currentTimeMillis();
        long cost_pipe = end_pipe - start_pipe;
        System.out.println("withPipeline cost : " + cost_pipe + " ms");
    }
}

结果也符合我们的预期:

withoutPipeline cost : 11791 ms
withPipeline cost : 55 ms

 

参考文献

版权声明:本文为CSDN博主「jackletter」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010476739/article/details/105252038

上一篇:netty总纲


下一篇:UnityWebRequest请求