Redis中的Scan命令的使用

1、背景

Redis中有一个经典的问题,在巨大的数据量的情况下,做类似于查找符合某种规则的Key的信息,这里就有两种方式:

  • 一是keys命令,简单粗暴,由于Redis单线程这一特性,keys命令是以阻塞的方式执行的,keys是以遍历的方式实现的复杂度是 O(n),Redis库中的key越多,查找实现代价越大,产生的阻塞时间越长。
  • 二是scan命令,以非阻塞的方式实现key值的查找,绝大多数情况下是可以替代keys命令的,可选性更强。

2、示例

2.1、scan命令

scan执行方法,执行结果是Cursor<Entry<HK, HV>>

public static Cursor<Map.Entry<Object, Object>> scan(String key) {
    if (!StringUtils.isEmpty(key)) {
        return redisTemplate.opsForHash().scan(key, ScanOptions.NONE);
    }
    return null;
}

Cursor游标每次会返回一个对象Map.Entry<Object, Object> entry = cursor.next(),entry 对象包含key和value,通过以下方式可以读取键值:

String key = String.valueOf(entry.getKey())
String.valueOf(entry.getValue())

debug截图如下,展示了每次游标获取的数据:
在这里插入图片描述

2.2、scan命令实例

比如一段遍历redis缓存的代码,不过该逻辑依据不同的场景存在优化空间。

@Override
public void traversalMessage() throws Exception {
    Cursor<Map.Entry<Object,Object>> cursor = RedisCacheUtils.scan(CacheConsts.SOMETHING_KEY);
    if (cursor == null) {
        logger.info("通过scan(H key, ScanOptions options)方法获取匹配键值对记录为空");
        return;
    }
    while (cursor.hasNext()) {
        Map.Entry<Object, Object> entry = cursor.next();
        String key = String.valueOf(entry.getKey()); 
        Object value = entry.getValue();
    }
}

待优化点:

  • 若数据量小,但处理逻辑复杂,建议先缓存遍历数据,再对数据进行处理。
  • 若数据量大,遍历时需要考虑范围条件,对遍历数据量进行有效控制。

3、示例

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章