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必須在處理完所有命令前先緩存起所有命令的處理結果。打包的命令越多,緩存消耗內存也越多。所以並不是打包的命令越多越好。