版权声明:非商业目的可自由转载,转载请标明出处 https://blog.csdn.net/u010013573/article/details/87932576
keys命令
-
keys命令用于返回指定的正则表达式所匹配的所有key的列表,其所检索的是Redis当前所使用的数据库(默认为0号数据库)的所有key,用法如下:
1. *匹配数据库中所有key KEYS * 2. ?匹配某个字符 KEYS t?st 3. *和其他字符一起使用,如下匹配test, teest等 KEYS t*st 4. []匹配某些字符中的一个,如下匹配test或tast KEYS t[ae]st
-
由于每个Redis实例是使用单线程处理所有请求的,故keys命令和其他命令都是在同一个队列排队等待执行的,如果keys命令执行时间长,则会阻塞其他命令的执行,导致性能问题。如果keys命令需要匹配非常多的key,则可能造成长期停顿。
-
在Java中keys命令通常使用RedisTemplate来调用,如下:
String pattern = "*"; redisTemplate.keys(pattern)
scan命令
-
scan命令是在2.8及之后版本提供的,主要用于解决keys命令可能导致整个Redis实例停顿的问题。scan是一种迭代命令,主要是对keys命令进行了分解,即原本使用一个keys请求一次匹配获取所有符合的key的操作,分解了多次scan操作,每次scan操作返回匹配的key的一个子集,这样每个scan请求的操作时间很短,多次scan请求之间可以执行其他命令,故减少对其他命令执行的阻塞,直到最后一个scan请求发现没有数据可返回了,则操作完成,汇总该次所有scan请求的数据,从而达到与keys命令一次获取的数据相同。
-
由于scan命令需要执行多次,即相当于执行了多个命令,存在多次命令请求和响应周期,故整体执行时间可能要比keys命令长。
-
在使用scan命令时,通常需要指定一个count参照,如下:0为游标,第二次迭代从第一次迭代返回的游标开始,COUNT为1000表示提示hint此次需要返回1000个数据,但实际并不一定,可能更多也可能更少。在多次迭代中COUNT可以指定不同的值。COUNT默认值为10.
127.0.0.1:6379> scan 0 MATCH user_* COUNT 1000 1) "0" 2) (empty list or set)
-
游标的使用:第一次返回17,则第二次可以从17开始。
127.0.0.1:6379> scan 0 1) "17" 2) 1) "key:12" 2) "key:8" 3) "key:4" 4) "key:14" 5) "key:16" 6) "key:17" 7) "key:15" 8) "key:10" 9) "key:3" 10) "key:7" 11) "key:1" 127.0.0.1:6379> scan 17 1) "0" 2) 1) "key:5" 2) "key:18" 3) "key:0" 4) "key:2" 5) "key:19" 6) "key:13" 7) "key:6" 8) "key:9" 9) "key:11"
Java使用scan命令示例
- 在Java中一般基于spring的RedisTemplate来进行Redis相关操作,其中RedisTemplate是线程安全的,故整个项目可以共享一个RedisTemplate实例。scan代码示例如下:
public int getTotalUsers() { Set<String> allUsers = redisTemplate.execute(new RedisCallback<Set<String>>() { @Override public Set<String> doInRedis(RedisConnection connection) throws DataAccessException { Set<String> partUers = new HashSet<>(); // 放在try中自动释放cursor try (Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder() .match(RedisStorage.USER_KEY + "*").count(50000).build())) { while (cursor.hasNext()) { partUers.add(new String(cursor.next())); } } catch (IOException e) { LOG.error("getTotalUsers cursor close {}", e); } return partUers; } }); return sessions.size(); }