java相关

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
上一篇 下一篇

猜你喜欢

热点阅读