需求:redis在线上运行过程中,需要获取一批Key,可能包含特定前缀或者存在一定的规则?

  1. 生成测试数据

     public static void main(String[] args) {
         Jedis jedis = RedisUtils.getJedis();
         for (int i = 0 ;i<10000;i++){
             jedis.set("key"+i, String.valueOf(i));
         }
         jedis.close();
     }
  2. 方案一:

    直接使用keys * ,进行匹配

    127.0.0.1:6379> keys key99*
    1) "key9991"
    2) "key999"
    3) "key9987"
    4) "key9930"
    5) "key9936"
    6) "key9933"
    7) "key9986"
    8) "key9978"
    9) "key9949"
    10) "key9983"
    11) "key9975"
    ..............................
    缺点:

    • 没有offset和limit参数,一次性查询多条记录,查看不是很方便
    • keys是遍历算法,复杂地O(N),数据key过多明总,会造成redis卡顿,造成正常读写操作超时,redis是单线程的顺序执行指令,其他指令需要等待keys命令执行完后,才会继续执行。
  3. 方案二:

    redis V2.8后加入了scan命令。

    • 复杂度O(N),但是它是通过游标分布进行,不会阻塞线程
    • 提供limit ,可以控制返回结果数
    • 拥有和keys一样的正则匹配
    • 返回的结果可能重复,需要去重
    • 遍历过程如果有修改,可能数据不是完全正确
    • 返回结果为空是不一定为遍历结束,结束标志位游标返回为0
scan 0 match key99* count 1000
# 从0开始查询,匹配key99开头的key,每次查询1000条,可能返回为(empty list or set),但是游标不为0,还可以继续遍历
0
key9921
key9900
key9928
key9939
key9923
............