Redis 管道pipeline

Redis是一个cs模式的tcp server,使用和http相似的请求响应协议。java

一个client能够经过一个socket链接发起多个请求命令。redis

每一个请求命令发出后client一般会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果经过响应报文返回给client。数据库

基本的通讯过程以下:
缓存

./bin/redis-cli -h 192.168.36.189 -p 6379  
192.168.36.189:6379> incr x  
(integer) 1  
192.168.36.189:6379> incr x  
(integer) 2  
192.168.36.189:6379> incr x  
(integer) 3  

 

 

客户端和服务端经过网络进行链接。这样的链接可能很是快(在一个回路网络中),也可能很是慢(在广域网上通过多个结点才能互通的两个主机)。可是不管是否存在网络延迟,数据包从客户端传输到服务端,以及客户端从服务端得到相应都须要花费一些时间。这段时间就成为往返时延(Round Trip Time)。所以当客户端须要执行一串请求的时候,很容易看出它对性能的影响(例如往同一个队列中加入大量元素,或者往数据库中插入大量的键)。若是RTT时长为250毫秒(在基于广域网的低速链接环境下),即便服务器每秒能够处理10万个请求,可是实际上咱们依然只能每秒处理最多4个请求。
若是处于一个回路网络中,RTT时长则至关短(个人主机ping 127.0.0.1时只须要0.044ms),可是若是你执行一大串写入请求的时候,仍是会有点长。
幸运的是,redis给咱们提供了管道技术。

1.Redis管道技术
一个请求/相应服务能够实现为,即便客户端没有读取到旧请求的响应,服务端依旧能够处理新请求。经过这种方式,能够彻底无需等待服务端应答地发送多条指令给服务端,并最终一次性读取全部应答。管道技术最显著的优点是提升了redis服务的性能。
经过pipeline方式当有大批量的操做时候。咱们能够节省不少原来浪费在网络延迟的时间。须要注意到是用pipeline方式打包命令发送,redis必须在处理完全部命令前先缓存起全部命令的处理结果。打包的命令越多,缓存消耗内存也越多。因此并是否是打包的命令越多越好。具体多少合适须要根据具体状况测试。
服务器

$(echo -en "PING\r\n SET key redis\r\nGET key\r\nINCR x\r\nINCR x\r\nINCR x\r\n"; sleep 10) | nc 192.168.36.189 6379  
+PONG  
+OK  
$5  
redis  
:4  
:5  
:6  

 

以上实例中咱们经过使用 PING 命令查看redis服务是否可用, 以后咱们们设置了key的值为 redis,而后咱们获取key 的值并使得x自增 3 次。
在返回的结果中咱们能够看到这些命令一次性向redis服务提交,并最终一次性读取全部服务端的响应。网络


2.java测试代码socket

 

    package cn.slimsmart.redis.demo.pipeline;  
      
    import redis.clients.jedis.Jedis;  
    import redis.clients.jedis.Pipeline;  
      
    @SuppressWarnings("resource")  
    public class PipelineTest {  
      
        public static void main(String[] args) {  
            long start = System.currentTimeMillis();  
            usePipeline();  
            long end = System.currentTimeMillis();  
            System.out.println("usePipeline:"+(end - start));  
      
            start = System.currentTimeMillis();  
            withoutPipeline();  
            end = System.currentTimeMillis();  
            System.out.println("withoutPipeline:"+(end - start));  
        }  
      
        private static void withoutPipeline() {  
            try {  
                Jedis jedis = new Jedis("192.168.36.189", 6379);  
                for (int i = 0; i < 1000; i++) {  
                    jedis.incr("test2");  
                }  
                jedis.disconnect();  
            } catch (Exception e) {  
            }  
        }  
      
        private static void usePipeline() {  
            try {  
                Jedis jedis = new Jedis("192.168.36.189", 6379);  
                Pipeline pipeline = jedis.pipelined();  
                for (int i = 0; i < 1000; i++) {  
                    pipeline.incr("test2");  
                }  
                pipeline.sync();  
                jedis.disconnect();  
            } catch (Exception e) {  
            }  
        }  
    }  

 

运行结果:tcp

127.0.0.1 循环10000次 效果性能

usePipeline:151
withoutPipeline:6229
测试

 

外网IP循环10000次 效果

 

usePipeline:201
withoutPipeline:94909

结果仍是很明显有较大的差距,因此屡次操做用pipeline仍是有明显的优点。

相关文章
相关标签/搜索