Redis中的Pipeline
- Pipeline是打包多条命令发送给服务端,服务端处理完多条命令后将结果打包一起返回的方式;
- redis是一个cs模式的tcp server,使用和http类似的请求响应协议,一个client可以通过一个socket连接发起多个请求命令;每个请求命令发出后client通常会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果通过响应报文返回给client;
- 模拟的通信过程;
- 基本上四个命令需要8个tcp报文才能完成,由于通信会有网络延迟,假如从client和server之间的包传输时间需要0.125秒,那么上面的四个命令8个报文至少会需要1秒才能完成,这样即使redis每秒能处理100个命令,而我们的client也只能一秒钟发出四个命令,这显示没有充分利用redis的处理能力;
- 可以利用mget,mset之类的单条命令处理多个key的命令外,还可以利用pipeline的方式从client打包多条命令一起发出,不需要等待单条命令的响应返回,而redis服务端会处理完多条命令后会将多条命令的处理结果打包到一起返回给客户端;
-
假设不会因为tcp报文过长而被拆分,可能两个tcp报文就能完成四条命令,client可以将四个incr命令放到一个tcp报文一起发送,server则可以将四条命令的处理结果放到一个tcp报文返回;通过pipeline方式当有大批量的操作时候,我们可以节省很多原来浪费在网络延迟的时间,需要注意到是用pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果,打包的命令越多,缓存消耗内存也越多;所以并是不是打包的命令越多越好;
- 使用Jedis测试Pipeline的过程,发现使用pipeline节省很多时间;
package com.snda.study.redis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
public class PipeLineTest
{
public static void main(String[] args)
{
// 不使用pipeline的时间消耗;
long start = System. currentTimeMillis();
withoutPipeline();
long end = System. currentTimeMillis();
System. out.println( “WithoutPipeline:” + (end – start));
// 使用pipeline的时间消耗;
start = System. currentTimeMillis();
usePipeline();
end = System. currentTimeMillis();
System. out.println( “UsePipeline:” + (end – start));
}
/**
* 不使用pipeline的方式,循环N次,需要与服务器端交互2N次;
*/
private static void withoutPipeline()
{
try
{
Jedis jedis = new Jedis( “192.168.10.112”, 6379);
for ( int i = 0; i < 100000; i++)
{
jedis.incr( “withoutPipeline”);
}
jedis.quit();
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* 使用pipeline,循环N次,会把操作打包发送给服务端,然后一次性返回;
*/
private static void usePipeline()
{
try
{
Jedis jedis = new Jedis( “192.168.10.112”, 6379);
Pipeline pipeline = jedis.pipelined();
for ( int i = 0; i < 100000; i++)
{
pipeline.incr( “usePipeline”);
}
pipeline.sync();
jedis.quit();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}