RedisTemplate 实现 scan 方法(最新版 spring-redis-data 已于 2022.02.23 支持了 scan 方法)
RedisTemplate 实现 scan 方法
·
RedisTemplate 实现 scan 方法
问题来源: 工作中遇到一个问题,需要清理大量的 key ,由于数量过于大,用 keys
获取时可能会造成 redis 的阻塞,所以就想到用 scan
命令。scan
命令对于集群来说只能获取到单台机器的数据,所以对集群上的所有机器都执行 scan
命令。公司用的 spring-boot 所依赖的 spring-redis-data
中 RedisTemplate 并没有 scan
方法,也在网上查了一些实现,不是只获取了单台机器的数据,就是无法正常返回数据,实现起来也并不简单。
解决思路: redis 的命令并不只有 scan
命令只能在单台机器上执行,keys
其实也是只能在单台机器上执行,解决思路就清晰了,直接去看一下 RedisTemlate 中 keys
方法是如何实现的,仿写一下就好了。
// spring-redis-data version: 2.2.x
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.RedisOperations#keys(java.lang.Object)
*/
@Override
@SuppressWarnings("unchecked")
public Set<K> keys(K pattern) {
byte[] rawKey = rawKey(pattern);
Set<byte[]> rawKeys = execute(connection -> connection.keys(rawKey), true);
return keySerializer != null ? SerializationUtils.deserialize(rawKeys, keySerializer) : (Set<K>) rawKeys;
}
于是产生了如下代码:
/*
* @Resource
* RedisTemplate redisTemplate;
*/
public Set<String> scan (String pattern, int count) {
Set<String> keys = new HashSet<>();
RedisSerializer serializer = redisTemplate.getKeySerializer();
ScanOptions scanOptions = ScanOptions.scanOptions().match(pattern).count(count).build();
Cursor<byte[]> cursor = redisTemplate.execute(connection -> connection.scan(scanOptions), true);
while (cursor.hasNext()) {
keys.add(String.valueOf(serializer.deserialize(cursor.next())));
}
return keys;
}
测试过后跟通过 keys
方法得到的结果集对比,发现是一样的,说明这样写是可行的。可通过调节 count
的大小来控制单次 scan
命令扫描的数据量,redis 中默认是 10 。注意:不要把 count
的值设成 Integer.MAX_VALUE
或过大,否则会产生和 keys
命令类似的效果,可能会阻塞 redis。
最后放上最新版 spring-redis-data
中的 scan
方法实现(不禁发出感叹,如果早四个月,没准就是我贡献了这部分代码了,哈哈哈)
@Override
public Cursor<K> scan(ScanOptions options) {
Assert.notNull(options, "ScanOptions must not be null");
return executeWithStickyConnection(
(RedisCallback<Cursor<K>>) connection -> new ConvertingCursor<>(connection.scan(options),
this::deserializeKey));
}
@SuppressWarnings("unchecked")
private K deserializeKey(byte[] value) {
return keySerializer != null ? (K) keySerializer.deserialize(value) : (K) value;
}
更多推荐
已为社区贡献1条内容
所有评论(0)