本质
客户端通过改变了读写的顺序带来的性能的巨大提升
什么时候使用管道(pipeline)
Redis客户端执行事务时都会结合pipeline,可以将多次IO操作压缩为单次IO操作
request
1.write操作只需要把消息写到本地操作系统内核的发送缓冲然后就返回了
2.操作系统内核异步将数据发送到目标机器,但是如果发送缓冲满了,就需要
等待缓冲腾出空闲空间来,(这个就是写操作IO真正耗时的地方)
response
1.read操作负责将数据从本地操作系统内核的接收缓冲区取出来,如果缓冲是空的
那么久需要等待数据的到来(这个就是读操作IO真正耗时的地方)
在Spring中使用SessionCallback 和 RedisCallback
redisTemplate.opsForValue().set("key1", "value1");每次都需要开启一个连接
为了在一个redis连接中执行2条以上的命令,我们可以使用 SessionCallback 或者 RedisCallback
SessionCallback优先使用
RedisCallback 可读性比较差
//TODO 该方法比较底层,可读性较差不推荐使用
List<Object> redisCallback = redisTemplate.executePipelined(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
//打开管道
redisConnection.openPipeline();
// 给本次管道内添加要一次性执行的多条命令
for (int i = 0; i < number; i++) {
redisConnection.set(("B" + i).getBytes(), (i + "").getBytes());
}
// 关闭管道,不需要close,否则拿不到返回值
// redisConnection.closePipeline()
// 这里一定要返回null,最终pipeline的执行结果,才会返回给最外层
return null;
}
});
public <T> void setObject(String key, T clazz, long timeout) {
this.setObject(key, clazz, timeout, TimeUnit.SECONDS);
}
public Object pipeline() {
int number = 1000;
Long startTime = System.currentTimeMillis();
for (int i = 0; i < number; i++) {
setObject(("T" + i), (i + ""));
}
Long endTime = System.currentTimeMillis();
List<Object> sessionCallback = redisTemplate.executePipelined(new SessionCallback<Object>() {
@Override
public <K, V> Object execute(RedisOperations<K, V> redisOperations) throws DataAccessException {
for (int i = 0; i < number; i++) {
setObject(("Pipeline" + i), (i + ""));
}
return null;
}
});
Long end = System.currentTimeMillis();
log.info("不使用管道耗时:{}", (endTime - startTime));
log.info("管道执行耗时: {}", (end - endTime));
return sessionCallback;
}