redisTemplate使用scan模糊匹配key
2019-11-14 本文已影响0人
今年五年级
为什么不直接用keys
使用keys *进行模糊匹配引发Redis锁(因为redis单线程,keys会阻塞),造成Redis锁住,CPU飙升,引起了所有调用链路的超时并且卡住,等Redis锁的那几秒结束,所有的请求流量全部请求到mysql数据库中,使数据库发生宕机
scan以非阻塞的方式实现key值的查找,绝大多数情况下是可以替代keys命令的,可选性更强
redis中使用scan
SCAN cursor [MATCH pattern] [COUNT count]
当 SCAN 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束。
redis:6>scan 0 match userlist* count 50
1) "62"
2) 1) "userlist"
redis:6>scan 62 match userlist* count 50
1) "0"
2) 1) "userlist2"
redisTemplate中使用scan
redisTemplate默认没有提供遍历数据库键的scan,只提供了sscan和hscan,我们自己实现这个scan
private static Cursor<String> scan(StringRedisTemplate stringRedisTemplate, String match, int count){
ScanOptions scanOptions = ScanOptions.scanOptions().match(match).count(count).build();
RedisSerializer<String> redisSerializer = (RedisSerializer<String>) stringRedisTemplate.getKeySerializer();
return (Cursor) stringRedisTemplate.executeWithStickyConnection((RedisCallback) redisConnection ->
new ConvertingCursor<>(redisConnection.scan(scanOptions), redisSerializer::deserialize));
}
调用
@Test
public void test2() throws IOException {
long start = System.currentTimeMillis();
List<String> keys = Lists.newArrayList();
Cursor<String> cursor = scan(stringRedisTemplate, "userlist*", 200);
while (cursor.hasNext()){
//找到一次就添加一次
keys.add(cursor.next());
}
cursor.close();
keys.forEach(System.out::println);
long end = System.currentTimeMillis();
System.out.println(end-start);
}
上面遍历的count越小,分页越小,迭代次数越多,查询越耗时,在count设置为2的时候耗费时间:
image.png
在count设置为100的时候耗费时间:
image.png