如何通路Redis中海量資料,服務不會受影響?
我們知道使用keys可以找出想要的結果,但是redis有一個很關鍵的特性:單線程。keys算法是周遊算法,複雜度是0(n),資料越多時間越高。keys指令會順序執行,這将導緻線程阻塞一段時間,直到執行完畢。想象一下如果一次找出幾百萬以上的資料,執行keys指令會帶來什麼後果?卡頓,假死。如果是重要的核心業務恐怕要造成不小的損失。
那麼我們如何去周遊大資料量呢?
redis在2.8版本以後提供了scan這個指令。
scan有什麼特點:
- 複雜度0(n),但是它是通過遊标分步進行的,不會阻塞線程
- 提供count參數,不是結果數量,是Redis單次周遊字典槽位數量(約等于)
- 同keys一樣,它也提供模式比對功能
- 伺服器不需要為遊标儲存狀态,遊标的唯一狀态就是 scan傳回給用戶端的遊标整數
- 傳回的結果可能會有重複,需要用戶端去重,這點非常重要
- 單詞傳回的結果是空的并不意味着周遊結束,而要看傳回的遊标值是否為0
scan 指令格式
SCAN cursor [MATCH pattern] [COUNT count]
scan 遊标 MATCH <傳回和給定模式相比對的元素> count 每次疊代所傳回的元素數量。
scan 指令是增量的循環,每次條用隻會反回一小部分的元素。所有不會讓Redis假死。
scan 指令傳回的是一個遊标,從0開始周遊,到0結束周遊。
舉例
127.0.0.1:6379> scan 0 match mtsu* count 10
1) "244"
2) 1) "mtsubmitid:128464154332"
2) "mtsubmitid:128463915872"
3) "mtsubmitid:128464745924"
4) "mtsubmitid:128463892716"
5) "mtsubmitid:128464775064"
6) "mtsubmitid:128463758432"
7) "mtsubmitid:128464611971"
從0開始周遊,傳回了遊标244,又傳回了資料,繼續scan周遊,就要從244開始
127.0.0.1:6379> scan 244 match mtsu* count 10
1) "390"
2) 1) "mtsubmitid:128464736797"
2) "mtsubmitid:128464571625"
3) "mtsubmitid:128464559272"
4) "mtsubmitid:128464163953"
5) "mtsubmitid:128463748985"
6) "mtsubmitid:128464777189"
7) "mtsubmitid:128464161014"