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、示例

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