最近做一个统计项目,数据量非常大,之前使用scan命令对redis中指定key进行扫描,效率较低可以忽略,但是tcp连接的time-wait不一会就超过了几万,对性能造成了极大的浪费同时执行时间也很慢,而且当数据量进一步增大可能会影响其他服务。为了减少tcp连接数量,将redis的scan修改为pipeLine操作。
本文使用的是RedisTemplate调用execute,connection使用的redis原生的操作,这里简单使用了zCount来计算keys中集合数据的长度。获取结果为result,这里要使用pipeline需要调用Connection.openPipeline()。Connection.closePipeline()返回值为List<Object>是执行后的结果。
redisTemplate.execute(new RedisCallback<Long>() {
@Nullable
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
for (int i = 0; i < 1000000; i++) {
String key = "123" + i;
connection.zCount(key.getBytes(), 0,Integer.MAX_VALUE);
}
List<Object> result=connection.closePipeline();
return null;
}
});
如果要获取返回值,我们可以调用如下代码executePipelined,这样就可以返回我们需要的结果,下面我们可以对list进行操作。
List<Long> List = redisTemplate.executePipelined(new RedisCallback<Long>() {
@Nullable
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
for (int i = 0; i < 1000000; i++) {
String key = "123" + i;
connection.zCount(key.getBytes(), 0,Integer.MAX_VALUE);
}
return null;
}
});
在这里需要注意4点内容:
1.connection的返回结果是基本上是byte数组,如果需要存储的数据,需要对byte[]数组反序列化。
2.在doInRedis中返回值必须返回为null,为什么返回为空可以定位到内部代码去查看,这里不再赘述。
3. connection.openPipeline()可以调用,也可以不调用,但是connection.closePipeline()最好不调用,调用了拿不到返回值,因为调用的时候会直接将结果返回,同时还不会对代码进行反序列化。
4.反序列化需要传入反序列化对象,如下图所示,这些对象都可以进行相应的实例化。