赞
踩
平时线上Redis维护工作中,有时候需要从Redis实例的成千上万个key中找出特定前缀的key列表来手动处理数据。这里就有个问题如何从海量的key中找出满足特定前缀的key列表?Redis提供了一个简单的指令keys用来查询出所有满足特定正则规则字符串的所有key。这个指令虽然简单,但是有明显的缺陷。
1. 没有offset、limit参数,一次性会查询出所有满足条件的key。如果数据量大,绝对会造成操作堵塞,导致其它查询redis的线程等待,是比较危险的操作。
2. redis的keys操作的复杂度是O(n),需要一个一个去遍历匹配。所以性能比较低。
面对以上的问题,redis在2.8版本以后提供了一个指令-----scan。这个命令具备以下特点。
1. 复杂度O(n),但他是通过游标分布进行的,不会阻塞线程。
2. 提供limit参数,可以控制每次返回结果的最大条数,limit只是一个 hint,返回的结果可多可少。
3. 同keys一样, 他也提供模式匹配功能。
4. 服务器不需要为游标保存状态,游标的唯一状态就是scan返回给客户端的游标整数。
5. 返回的结果可能会有重复,需要客户端去重。
6. 遍历的过程中如果有数据修改,改动后的数据能不能遍历到是不确定的。
7. 单次返回的结果是空的并不意味着遍历结束,而要看返回的游标值是否为零。
下面我们看一个命令:
san 0 match keyuser* count 100
参数解释:
0:cursor整数值。
keyuser*:key的正则模式。
100:遍历的limit值。
第一次遍历时,cursor值为0,然后将返回结果中第一个整数值作为下一次遍历的cursor,一直遍历到返回的cursor值为0时结束。
如果执行上述命令,虽然与keyuser*相关的结果可能超过100,但是上述命令执行后返回的结果不一定是100个,因为这个100只是代表扫描了100个key,这100个key中有可能没有一个与制定的正则key匹配,可能返回结果为空,我们要看是否扫描完,主要是看返回来的第一个整数值是否为0。为0,则扫描完毕。
以下为示例:
查询 s* 相关的key,一共有7个key。
每次查询的时候,都查询指定查询数为3。从下图可以看出实际每次查询结果都是2个,但是扫描了3个key。如果要翻页查,下次执行命令的时候,cursor就得指定上一次返回的第一个整数参数,如下图红框所示。指导图片中的最后一行命令执行的返回结果中第一个正式值为0时,扫描完毕。
郑重声明:以上内容参考了《Redis深历险》一文,非常感谢作者的贡献。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。