溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Redis如何刪除1.2億指定前綴的key

發(fā)布時間:2021-12-01 17:15:48 來源:億速云 閱讀:195 作者:小新 欄目:數(shù)據(jù)庫

這篇文章主要為大家展示了“Redis如何刪除1.2億指定前綴的key”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學習一下“Redis如何刪除1.2億指定前綴的key”這篇文章吧。

背景

因為更換IDC的原因,我們需要遷移緩存到新的機房,開發(fā)同學提出老的緩存有1.2億無效(未設(shè)置過期時間)的key和正常在用的業(yè)務(wù)key,在遷移之前可以先指定前綴將key刪除。那么問題來了,如何快速刪除1.2億的key呢?

如何獲取指定的 key

大家都知道由于Redis的單線程服務(wù)模式,命令 keys * 會阻塞正常的業(yè)務(wù)請求,所以肯定不行。

在這里我們利用Redis 提供的 SCAN 功能。SCAN 命令是一個基于游標的迭代器(cursor based iterator): SCAN 命令每次被調(diào)用之后, 都會向用戶返回一個新的游標, 用戶在下次迭代時需要使用這個新游標作為 SCAN 命令的游標參數(shù), 以此來延續(xù)之前的迭代過程。

當 SCAN 命令的游標參數(shù)被設(shè)置為 0 時, 服務(wù)器將開始一次新的迭代, 而當服務(wù)器向用戶返回值為 0 的游標時, 表示迭代已結(jié)束。 SCAN的語法如下 

SCAN cursor [MATCH pattern] [COUNT count]

其中 cousor 是游標,MATCH 則支持正則匹配,我們正好可以利用此功能,比如匹配 前綴為"dba_"的key, COUNT 是每次獲取多少個key。

redis 127.0.0.1:6379> scan 0
1) "17"
2)  1) "key:12"
    2) "key:8"
    3) "key:4"
    4) "key:14"
    5) "key:16"
    6) "key:17"
    7) "key:15"
    8) "key:10"
    9) "key:3"
    10) "key:7"
    11) "key:1"
redis 127.0.0.1:6379> scan 17
1) "0"
2) 1) "key:5"
   2) "key:18"
   3) "key:0"
   4) "key:2"
   5) "key:19"
   6) "key:13"
   7) "key:6"
   8) "key:9"
   9) "key:11"

在上面這個例子中, 第一次迭代使用 0 作為游標, 表示開始一次新的迭代。第二次迭代使用的是第一次迭代時返回的游標, 也即是命令回復第一個元素的值 —— 17 。 在第二次調(diào)用 SCAN 命令時, 命令返回了游標 0 , 這表示迭代已經(jīng)結(jié)束, 整個數(shù)據(jù)集(collection)已經(jīng)被完整遍歷過了。

從上面的示例可以看到, SCAN 命令的回復是一個包含兩個元素的數(shù)組, 第一個數(shù)組元素是用于進行下一次迭代的新游標, 而第二個數(shù)組元素則是一個數(shù)組, 這個數(shù)組中包含了所有被迭代的元素。

注意:以 0 作為游標開始一次新的迭代, 一直調(diào)用 SCAN 命令, 直到命令返回游標 0 , 我們稱這個過程為一次完整遍歷(full iteration)。 我們會在后面的代碼實現(xiàn)中利用此特點。

Python的redis 模塊提供 scan_iter 迭代器來遍歷key,其返回的結(jié)果迭代器對象。

In [53]: ret=r.scan_iter('dba_*',20)
In [54]: print ret

至此,我們解決了如何獲取數(shù)據(jù)的問題,下面思考第二個問題。

如何執(zhí)行刪除

這個相對比較簡單,Redis 提供DEL 命令

127.0.0.1:6379[2]> get "dba_7"
"r06cVX9"
127.0.0.1:6379[2]> get "dba_1"
"ETX57PA"
127.0.0.1:6379[2]> del "dba_7" "dba_1"
(integer) 2
127.0.0.1:6379[2]>

在redis-py 中,提供了delete(key),delete(*key)的函數(shù), 其中參數(shù) *key 是多個值的列表。 到這里,我們大致可以想到獲取key,然后批量刪除

(mytest)?  test git:(master) ? python delete_key.py
initial keys successfully,use time: 90.2497739792
normal ways end at: 68.685477972
normal ways delete numbers: 1000000

常規(guī)方式的刪除10W個key耗時68.7秒,如果是1.2億個key 要多少時間呢?68*1000/3600=18.8小時。能不能更快呢? 

如何提高執(zhí)行速度

Redis本身是基于Request/Response協(xié)議的,客戶端發(fā)送一個命令,等待Redis應(yīng)答,Redis在接收到命令,處理后應(yīng)答。其中發(fā)送命令加上返回結(jié)果的時間稱為(Round Time Trip)RRT-往返時間。如果客戶端發(fā)送大量的命令給Redis,那就是等待上一條命令應(yīng)答后再執(zhí)行再執(zhí)行下一條命令,這中間不僅僅多了RTT,而且還頻繁的調(diào)用系統(tǒng)IO,發(fā)送網(wǎng)絡(luò)請求。

Redis如何刪除1.2億指定前綴的key

Pipeline(流水線)功能極大的改善了上面的缺點。Pipeline能將一組Redis命令進行組裝,然后一次性傳輸給Redis,再將Redis執(zhí)行這組命令的結(jié)果按照順序返回給客戶端。

Redis如何刪除1.2億指定前綴的key

需要注意的是Pipeline 雖然好用,但是Pipline組裝的命令個數(shù)不能沒有限制,否則一次組裝數(shù)據(jù)量過大,一方面增加客戶端的等待時間,另一方面會造成網(wǎng)絡(luò)阻塞,需要批量組裝。使用Pepline 和常規(guī)方式的性能對比如下:

Redis如何刪除1.2億指定前綴的key

代碼

  1. # encoding: utf-8

  2. """

  3. author: yangyi@youzan.com

  4. time: 2018/3/9 下午8:35

  5. func:

  6. """

  7. import redis

  8. import random

  9. import string

  10. import time

  11. pool = redis.ConnectionPool(host='127.0.0.1', port=6379, db=2)

  12. r = redis.Redis(connection_pool=pool)



  13. def random_str():

  14.     return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(7))



  15. def init_keys():

  16.     start_time = time.time()

  17.     for i in xrange(0, 20):

  18.         key_name = 'dba_'+str(i)

  19.         value_name = random_str()

  20.         r.set(key_name, value_name)

  21.     print 'initial keys successfully,use time:', time.time() - start_time



  22. def del_keys_without_pipe():

  23.     start_time = time.time()

  24.     result_length = 0

  25.     for key in r.scan_iter(match='dba_*', count=2000):

  26.         r.delete(key)

  27.         result_length += 1

  28.     print "normal ways end at:", time.time() - start_time

  29.     print "normal ways delete numbers:", result_length



  30. def del_keys_with_pipe():

  31.     start_time = time.time()

  32.     result_length = 0

  33.     pipe = r.pipeline()

  34.     for key in r.scan_iter(match='dba_*', count=5000):

  35.         pipe.delete(key)

  36.         result_length += 1

  37.         if result_length % 5000 == 0:

  38.             pipe.execute()

  39.     pip_time = time.time()

  40.     print "use pipeline scan time ", time.time() - start_time

  41.     pipe.execute()


  42.     print "use pipeline end at:", time.time() - pip_time

  43.     print "use pipeline ways delete numbers:", result_length



  44. def main():

  45.     init_keys()

  46.     del_keys_without_pipe()

  47.     init_keys()

  48.     del_keys_with_pipe()



  49. if __name__ == '__main__':

  50.     main()

以上是“Redis如何刪除1.2億指定前綴的key”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI