redis pipeline批量处理提高性能
Redis使用的是客户端-服务器(CS)模型和请求/响应协议的TCP服务器。Redis客户端与Redis服务器之间使用TCP协议进行连接,一个客户端可以通过一个socket连接发起多个请求命令。每个请求命令发出后client通常会阻塞并等待redis服务器处理,redis处理完请求命令后会将结果通过响应报文返回给client,因此当执行多条命令的时候都需要等待上一条命令执行完毕才能执行。
然而使用Pipeline模式,客户端可以一次性发送多条命令,并在执行完后一次性将结果返回。这样就大大的减少了网络往返时间,提高了系统性能。
下面用一个例子测试这两种模式在效率上的差别:
Maven依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
Jedis工具类
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisUtil {
private static JedisPool pool;
static {
int redisTimeout = 30000;
String redisHost = "127.0.0.1";
int redisPort = 22621;
String redisPassword = "36a20fded94c4319a1986efbf3046ba3";
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(100);
//最大空闲连接数
poolConfig.setMaxIdle(10);
//获取Jedis连接的最大等待时间(50秒)
poolConfig.setMaxWaitMillis(50 * 1000);
//在获取Jedis连接时,自动检验连接是否可用
poolConfig.setTestOnBorrow(true);
//在将连接放回池中前,自动检验连接是否有效
poolConfig.setTestOnReturn(true);
//自动测试池中的空闲连接是否都是可用连接
poolConfig.setTestWhileIdle(true);
//创建连接池
pool = new JedisPool(poolConfig, redisHost, redisPort, redisTimeout,redisPassword);
}
public static Jedis getResource(){
return pool.getResource();
}
public static void close(){
pool.close();
}
}
测试类
import redis.clients.jedis.*;
public class JedisPipelineTest {
private static int count = 10000;
public static void main(String[] args){
useNormal();
usePipeline();
}
public static void usePipeline(){
Jedis jedis = JedisUtil.getResource();
Pipeline pipeline = jedis.pipelined();
long begin = System.currentTimeMillis();
for(int i = 0;i<count;i++){
pipeline.setex("pipe_"+i,1000,"value_"+i);
}
pipeline.sync();
jedis.close();
System.out.println("usePipeline total time:" + (System.currentTimeMillis() - begin));
}
public static void useNormal(){
Jedis jedis = JedisUtil.getResource();
long begin = System.currentTimeMillis();
for(int i = 0;i<count;i++){
jedis.setex("key_"+i,1000,"value_"+i);
}
jedis.close();
System.out.println("useNormal total time:" + (System.currentTimeMillis() - begin));
}
}
测试结果
useNormal total time:30771
usePipeline total time:62
从测试的结果可以看出,pipeline在“批量处理”时的优势,使用pipeline的效率要远高于普通的访问方式。
需要注意到是用 pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并不是打包的命令越多越好。