jedis redis pipeline的理解

简单代码使用

Pipeline pipeline = redis.pipelined();
Map> responseMap = new HashMap<>();
for (String key : keys) {
    String redisKey = getKey(key);
    responseMap.put(key, pipeline.get(redisKey));
}
pipeline.sync();
Map map = new HashMap<>();
for (Map.Entry> entry : responseMap.entrySet()) {
    map.put(entry.getKey(), entry.getValue().get());
}
return map;

可以看到,第一个map需要把所有的response收集起来,然后在pipeline.sync()后,再一个个读取。
redis官方的解释是,客户端会请求,然后获取结果,一般情况下这是 一个阻塞的过程,会等待服务器执行并返回结果。即:request->response request->response request->response

而管道的方式是,不用等待请求结果,一直发送命令,最后一次性获取。(原文:A Request/Response server can be implemented so that it is able to process new requests even if the client didn’t already read the old responses. This way it is possible to send multiple commands to the server without waiting for the replies at all, and finally read the replies in a single step.)
方式是:request->request->request->response->response->response
我觉得最后的这三个response应该是一个,只是客户端维护一个队列,对结果进行一个个取出,服务器是一次性返回的。

注意:如果有非常多的命令,也并不是一次性全部发送完最好,毕竟服务器是需要维护一个队列存储结果的,如果命令太多,最好是分批,redis对此的建议是一万个。

PS:这个说出来比较low,这和我之前的想法不同,我开始以为是命令先放着,然后要获取的时候,一次性发送命令到服务器,然后一次性获取。其实是每一个命令都是单独发送的,只是一次性获取。这已经涉及到socket了,而在jedis源码中发现,其实操作是一模一样的,jedis.get()有两步操作,一步是发送命令,然后是阻塞获取结果,而在pipeline里面,只发送命令,不再获取结果(会存储中间对象,用于处理返回结果),会在最后一次性获取。但是从socket的原理上来讲,其实client发送命令后不获取,server也会把结果返回到socket流中。所以按照redis的官方解释,这个过程中应该是,如果有返回值没有确认获取,服务器便不再返回结果,直到获取了才继续返回结果(没有读过源码,仅是猜想可能的实现方式)。

总结:用管道读取大量数据会更方便快速,而且在使用线程池的情况下,不需要频繁地获取和归还池对象。

但是需要注意,这里不能在对象池中使用,因为pipeline对象持有client对象,对象池归还了jedis,但是这个jedis对象的client被pipeline持有,会导致线程不安全。

你可能感兴趣的:(redis)