一、Pipeline是什么
Redis是一种基于内存的缓存结构,其处理请求的方式类似NIO,因此效率非常高,QPS可以达到4.4万/秒。但是对于单一客户端来讲,其向redis发起的请求是串行的,如图一,当一个请求获得响应后,才能发送第二个。假设请求客户端请求单程的时间是1ms,一次请求和响应来回就需要2ms,而redis处理一次请求的时间为1/4.4万=0.023毫秒,几乎可以忽略不计。一秒的请求数量最多只有1000/2=500次,redis在进行数据处理的时间只花费500/4.4万=11.36毫秒,大部分的时间耗费在数据传输上让人无法忍受。
图一
为了改变这种现状,基于pipeline管道的批处理方式被提出来。使用管道情况下,客户端可以缓存多个命令后,一起发送给redis,redis处理完后一起返回,如图二,这样能极大地减少传输时间。图二中三个命令只花费一个RTT时间,而图一却要花费三个RTT时间。
图二
二、Pipeline的特点
1、延时性:在请求命令被发出去前,需要将命令进行缓存,这消耗内存空间。因此一次发送的命令不是越多越好。命令被缓存起来,没有及时发送出去,这对于及时性很高的命令来讲,非常不适合。
2、不准确性:批处理允许出现少量次数的失败,比如500次失败1次,比如推送500条广告,有一次未到达是能够被接受的。但是如果业务场景对准确性要求非常高,比如涉及到订单数据等,就不太适合。
3、高时间利用率:减少了RTT的次数,提高了时间利用率。
三、java中Pipeline的应用
// redis 正常使用
public static void useNormal(){
ShardedJedis jedis = getShardedJedis();
long begin = System.currentTimeMillis();
for(int i = 0;i<count;i++){
// 插入key-value
jedis.set("key_"+i,"value_"+i);
}
jedis.close();
System.out.println("useNormal total time:" + (System.currentTimeMillis() - begin));
}
// pipeline 使用
public static void usePipeline(){
ShardedJedis jedis = getShardedJedis();
ShardedJedisPipeline pipeline = jedis.pipelined();
long begin = System.currentTimeMillis();
for(int i = 0;i<count;i++){
// 插入key-value
pipeline.set("key_"+i,"value_"+i);
}
pipeline.sync();
jedis.close();
System.out.println("usePipeline total time:" + (System.currentTimeMillis() - begin));
}