Redis刪除特定前綴key的優雅實現

還在用keys命令模糊匹配刪除數據嗎?這就是一顆隨時爆炸的炸彈!linux

Redis中沒有批量刪除特定前綴key的指令,但咱們每每須要根據前綴來刪除,那麼究竟該怎麼作呢?可能你一通搜索後會獲得下邊的答案redis

redis-cli --raw keys "ops-coffee-*" | xargs redis-cli del
複製代碼

直接在linux下經過redis的keys命令匹配到全部的key,而後調用系統命令xargs來刪除,看似很是完美,實則風險巨大數組

由於Redis的單線程服務模式,命令keys會阻塞正常的業務請求,若是你一次keys匹配的數量過多或者在del的時候遇到大key,都會直接致使業務的不可用,甚至形成redis宕機的風險安全

因此咱們在生產環境中應當避免使用上邊的方法,那有什麼優雅的方法來解決呢?SCAN!bash

SCAN介紹及使用

Redis從2.8版本開始支持scan命令,SCAN命令的基本用法以下:服務器

SCAN cursor [MATCH pattern] [COUNT count]
複製代碼

cursor: 遊標,SCAN命令是一個基於遊標的迭代器,SCAN命令每次被調用以後,都會向用戶返回一個新的遊標,用戶在下次迭代時須要使用這個新遊標做爲SCAN命令的遊標參數,以此來延續以前的迭代過程,直到服務器向用戶返回值爲0的遊標時,一次完整的遍歷過程就結束了markdown

MATCH: 匹配規則,例如遍歷以ops-coffee-開頭的全部key能夠寫成ops-coffee-*,中間包含-coffee-的能夠寫成*-coffee-*數據結構

COUNT: COUNT選項的做用就是讓用戶告知迭代命令,在每次迭代中應該從數據集裏返回多少元素,COUNT只是對增量式迭代命令的一種提示,並不表明真正返回的數量,例如你COUNT設置爲2有可能會返回3個元素,但返回的元素數據會與COUNT設置的正相關,COUNT的默認值是10oop

如下是一個SCAN命令的迭代過程示例:spa

127.0.0.1:6379> scan 0 MATCH ops-coffee-* 
1) "38"
2)  1) "ops-coffee-25"
    2) "ops-coffee-19"
    3) "ops-coffee-29"
    4) "ops-coffee-10"
    5) "ops-coffee-23"
    6) "ops-coffee-5"
    7) "ops-coffee-14"
    8) "ops-coffee-16"
    9) "ops-coffee-11"
   10) "ops-coffee-15"
   11) "ops-coffee-7"
   12) "ops-coffee-1"
127.0.0.1:6379> scan 38 MATCH ops-coffee-* COUNT 1000
1) "0"
2)  1) "ops-coffee-13"
    2) "ops-coffee-9"
    3) "ops-coffee-21"
    4) "ops-coffee-6"
    5) "ops-coffee-30"
    6) "ops-coffee-20"
    7) "ops-coffee-2"
    8) "ops-coffee-12"
    9) "ops-coffee-28"
   10) "ops-coffee-3"
   11) "ops-coffee-26"
   12) "ops-coffee-4"
   13) "ops-coffee-31"
   14) "ops-coffee-8"
   15) "ops-coffee-22"
   16) "ops-coffee-27"
   17) "ops-coffee-18"
   18) "ops-coffee-24"
   19) "ops-coffee-17"
複製代碼

SCAN命令返回的是一個包含兩個元素的數組,第一個數組元素是用於進行下一次迭代的新遊標,而第二個數組元素則是一個數組,這個數組中包含了全部被迭代的元素

上面這個例子的意思是掃描全部前綴爲ops-coffee-的key

第一次迭代使用0做爲遊標,表示開始一次新的迭代,同時使用了MATCH匹配前綴爲ops-coffee-的key,返回了遊標值38以及遍歷到的數據

第二次迭代使用的是第一次迭代時返回的遊標,也便是命令回覆第一個元素的值38,同時經過將COUNT選項的參數設置爲1000,強制命令爲本次迭代掃描更多元素

在第二次調用SCAN命令時,命令返回了遊標0,這表示迭代已經結束,整個數據集已經被完整遍歷過了

KEYS命令的時間複雜度爲O(n),而SCAN命令會將遍歷操做分解成m次時間複雜度爲O(1)的操做來執行,從而解決使用keys命令遍歷大量數據而致使服務器阻塞的狀況,使用下邊的指令能夠達到優雅刪除的目的:

redis-cli --scan --pattern "ops-coffee-*" | xargs -L 2000 redis-cli del
複製代碼

其中xargs -L指令表示xargs一次讀取的行數,也就是每次刪除的key數量,一次讀取太多xargs會報錯

其餘幾種數據結構的優雅刪除

相似的SCAN命令,對於Redis不一樣的數據類型還有另外幾個SSCANHSCANZSCAN,使用方法相似:

> sscan ops-coffee 0 MATCH v1*
1) "7"
2) 1) "v15"
   2) "v13"
   3) "v12"
   4) "v10"
   5) "v14"
   6) "v1"
複製代碼

與SCAN命令不一樣的是這幾個命令須要多加一個key的參數,例如上邊的ops-coffee

對於一個大的set key,藉助sscan使用下邊的代碼能夠實現優雅的批量刪除:

import redis

def del_big_set_key(key_name):
    r = redis.StrictRedis(host='localhost', port=6379)
    
    # count表示每次刪除的元素數量,這裏每次刪除300元素
    for key in r.sscan_iter(name=key_name, count=300):
        r.srem(key_name, key)

del_big_set_key('ops-coffee')
複製代碼

對於一個大的hash key,則可藉助hscan使用下邊的代碼實現優雅的刪除:

import redis

def del_big_hash_key(key_name):
    r = redis.StrictRedis(host='localhost', port=6379)
    
    # hscan_iter獲取出來的結果是個元祖,下邊hdel刪除用key[0]取到key
    for key in r.hscan_iter(name=key_name, count=300):
        r.hdel(key_name, key[0])

del_big_hash_key('ops-coffee')
複製代碼

對於大的有序集合的刪除就比較簡單了,直接根據zremrangebyrank排行範圍刪除

import redis

def del_big_sort_key(key_name):
    r = redis.StrictRedis(host='localhost', port=6379)

    while r.zcard(key_name) > 0:
        # 判斷集合中是否有元素,若有有則刪除排行0-99的元素
        r.zremrangebyrank(key_name, 0, 99)

del_big_sort_key('ops-coffee')
複製代碼

big list大列表的刪除能夠參考上邊這個方法,經過llen判斷數量,而後ltrim移除範圍內的元素,這裏不贅述

至此對於Redis的五中數據結構大key的優雅刪除就所有實現了,生產環境擇優使用~


掃碼關注公衆號查看更多原創文章

相關文章推薦閱讀:

相關文章
相關標籤/搜索