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();
}
}
待優化點:
- 若數據量小,但處理邏輯複雜,建議先緩存遍歷數據,再對數據進行處理。
- 若數據量大,遍歷時需要考慮範圍條件,對遍歷數據量進行有效控制。