Redis中有一個經典的問題,在巨大的數據量的狀況下,作相似於查找符合某種規則的Key的信息,這裏就有兩種方式,
一是keys命令,簡單粗暴,因爲Redis單線程這一特性,keys命令是以阻塞的方式執行的,keys是以遍歷的方式實現的複雜度是 O(n),Redis庫中的key越多,查找實現代價越大,產生的阻塞時間越長。
二是scan命令,以非阻塞的方式實現key值的查找,絕大多數狀況下是能夠替代keys命令的,可選性更強python
# -*- 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()
若使用keys命令,則執行keys key1111*,一次性所有查出來。git
一樣,若是使用scan命令,則用 scan 0 match key1111* count 20github
scan的語法爲:SCAN cursor [MATCH pattern] [COUNT count] The default COUNT value is 10.redis
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)。oop
另外,使用redis desktop manager的時候,當刷新某個庫的時候,控制檯自動不斷刷新scan命令,也就知道它在幹嗎了測試
參考:http://jinguoxing.github.io/redis/2018/09/04/redis-scan/spa