Redis中使用pipeline增加效率(2022.2.7编程记录)

今天主要是在编写文件服务的分块上传大文件功能时,使用redis存储文件哪些块上传了(使用bitmap)

然后有个地方就是要获取哪些块没有上传方便断点续传功能。

常规的思路是程序不停的去jedis.getBit(key,offset);把每个块都遍历一次,这样会产生文件分块数N的RTT,效率就会很低。

这个时候我就考虑到了使用pipeline,让N个RTT变成1个RTT,能让程序更快的执行完,增加效率。

pipeline的细节补充的话之后再填坑(总而言之记住就是,我们可以让多次请求变成一次请求发出去),以下是java中通过redistemplate使用pipeline的用法

然后有一个小小的细节,下面的代码的话是使用单机版本的redis,当我们使用redis集群的时候,因为存在hash槽,所以我们用pipeline访问的key可能不在一个node上,这个时候我们可以简单预处理一下key,通过CRC16去计算key的hash值,然后让再让处在同一个node的hash的key放在同一个pipeline中,这样就可以进一步增加集群中批处理操作的效率

 

public List<Integer> getUnUploadChunks(String name, String md5, int allCount) {//判断该文件哪几块还没上传,name:文件名,md5文件的d5值,allcount为分块数目
List<Object> objects = redisTemplate.executePipelined(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException {
redisConnection.openPipeline();
for (int i = 0; i < allCount; i++) {
redisConnection.getBit((RStrings.RedisFileChunksUpload + name + "-" + md5).getBytes(), i);
}
return null;//注意这里,必须返回null,这个具体的话 可以参考下面的源码
}
});
List<Integer> res=new ArrayList<>();
for(int i=0;i<allCount;i++){
Object o=objects.get(i);
if(o instanceof Boolean){
Boolean flag=(Boolean)o;
if(!flag){
res.add(i);
}
}
}
return null;
}
executePipelined(Rediscallback,serializer)方法
redistemplate的executePipelined(Rediscallback)方法如下,又调用了executePipelined(Rediscallback,serializer)方法
public List<Object> executePipelined(RedisCallback<?> action) {
return this.executePipelined(action, this.valueSerializer);
}
executePipelined(Rediscallback,serializer)方法如下
public List<Object> executePipelined(RedisCallback<?> action, @Nullable RedisSerializer<?> resultSerializer) {
return (List)this.execute((connection) -> {
connection.openPipeline();//开启管道
boolean pipelinedClosed = false;

List var7;
try {
Object result = action.doInRedis(connection);
if (result != null) {//注意看这里,如果不为空则会抛出异常
throw new InvalidDataAccessApiUsageException("Callback cannot return a non-null value as it gets overwritten by the pipeline");
}

List<Object> closePipeline = connection.closePipeline();//真正的返回的获取的就是关闭管道,之后返回的值
pipelinedClosed = true;
var7 = this.deserializeMixedResults(closePipeline, resultSerializer, this.hashKeySerializer, this.hashValueSerializer);//序列化,然后返回结果
} finally {
if (!pipelinedClosed) {
connection.closePipeline();
}

}

return var7;
});
}





 
 
posted @ 2022-02-08 00:15  SakuraFalling  阅读(787)  评论(0)    收藏  举报