Redis Scan指令解析与使用示例
概念
想要从redis key列表中找到某个key,redis提供了一个简单粗暴的指令keys用来列出满足查询条件的所有key。
keys redis*
keys redis*key
key指令非常简单,只要提供一个简单的正则表达式即可,但是有两个明显的缺点:
- 没有sffset和limit参数,一次性吐出所有满足条件的key。
- keys遍历算法时间复杂度O(n),如果实例中有千万级以上的key,那么keys一下就会导致redis服务卡顿,影响所有读写操作。
redis为了解决这个问题,在2.8版本中加入了scan指令,对比key具有不少特点:
- 虽然时间复杂度也是O(n),但是scan通过游标分步进行,不会阻塞线程(scan指令本身不会阻塞,但是如果在遍历过程中进行了大量写入操作)。
- 提供limit参数控制每次遍历的字典槽位的数量。
- 同key一样,它也提供了模式匹配功能。
- 服务器不需要单独为游标保存状态。
- 返回结果可能会有重复。
- 遍历途中有数据改动,无法保证会被遍历。
- 返回的游标值为0表示遍历结束。
scan 0 match you* count 1000
scan指令有三个参数,第一个参数是游标cursor值(从0开始);第二个参数是需要匹配的正则表达式;第三个参数是遍历的limit限制。
scan遍历顺序
scan的遍历顺序不是从一位数组的第0位一直遍历到最后一位,而是采用高位进位加法来遍历。
高位进位加法就是,从左边加,进位往右边移动,例如:
0000 —+1—> 1000 —+1—> 0100 —+1—> 1100
二进制逢一进一:
第一次对最高位+1,最高位变为1;
第二次对最高位+1,发现最高位已满需要向右进一,从而最高位变为0,次高位为1;
第三次对最高位+1,最高位变为1,且不改变次高位;
redis之所以这样设计,是为了防止字典扩容和缩容重复遍历和遗漏。