Redis中的Scan命令的使用

Redis中有一個經典的問題,在巨大的數據量的情況下,做類似於查找符合某種規則的Key的信息,這裏就有兩種方式,
一是keys命令,簡單粗暴,由於Redis單線程這一特性,keys命令是以阻塞的方式執行的,keys是以遍歷的方式實現的複雜度是 O(n),Redis庫中的key越多,查找實現代價越大,產生的阻塞時間越長。
二是scan命令,以非阻塞的方式實現key值的查找,絕大多數情況下是可以替代keys命令的,可選性更強

以下寫入100000條key***:value***格式的測試數據(ps:用pipline的話,1w一筆,每一筆在秒級完成)

# -*- coding: utf-8 -*-
# !/usr/bin/env python3
import redis
import sys
import datetime

def create_testdata():
    r = redis.StrictRedis(host='***.***.***.***', port=***, db=0, password='***')
    counter = 0
    with r.pipeline(transaction=False) as p:
        for i in range(0, 100000):
            p.set('key' + str(i), "value" + str(i))
            counter = counter + 1
            if (counter == 10000):
                p.execute()
                counter = 0
                print("set by pipline loop")

if __name__ == "__main__":
    create_testdata()

比如這裏查詢key111開頭的key有哪些?
若使用keys命令,則執行keys key1111*,一次性全部查出來。
在這裏插入圖片描述
同樣,如果使用scan命令,則用 scan 0 match key1111* count 20
在這裏插入圖片描述
scan的語法爲:SCAN cursor [MATCH pattern] [COUNT count] The default COUNT value is 10.

SCAN命令是一個基於遊標的迭代器。這意味着命令每次被調用都需要使用上一次這個調用返回的遊標作爲該次調用的遊標參數,以此來延續之前的迭代過程。
這裏使用scan 0 match key1111* count 20命令來完成這個查詢,稍顯意外的是,使用一開始都沒有查詢到結果,這個要從scan命令的原理來看。
scan在遍歷key的時候,0就代表第一次,key1111*代表按照key1111開頭的模式匹配,count 20中的20並不是代表輸出符合條件的key,而是限定服務器單次遍歷的字典槽位數量(約等於)。

那麼,什麼又叫做槽的數據?這個槽是不是Redis集羣中的slot?答案是否定的。其實上圖已經給出了答案了。
如果上面說的“字典槽”的數量是集羣中的slot,又知道集羣中的slot數量是16384,那麼遍歷16384個槽之後,必然能遍歷出來所有的key信息,
上面清楚地看到,當遍歷的字典槽的數量20000的時候,遊標依舊沒有走完遍歷結果,因此這個字典槽並不等於集羣中的slot的概念。
經過測試,在scan的時候,究竟遍歷多大的COUNT值能完全match到符合條件的key,跟具體對象的key的個數有關,
如果以超過key個數的count來scan,必定會一次性就查找到所有符合條件的key,比如在key個數爲10W個的情況下,一次遍歷20w個字典槽,肯定能完全遍歷出來結果。
在這裏插入圖片描述

scan 指令是一系列指令,除了可以遍歷所有的 key 之外,還可以對指定的容器集合進行遍歷。
zscan 遍歷 zset 集合元素,
hscan 遍歷 hash 字典的元素、
sscan 遍歷 set 集合的元素。
SSCAN 命令、 HSCAN 命令和 ZSCAN 命令的第一個參數總是一個數據庫鍵(某個指定的key)。

另外,使用redis desktop manager的時候,當刷新某個庫的時候,控制檯自動不斷刷新scan命令,也就知道它在幹嘛了
在這裏插入圖片描述

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