redis大key刪除


一、直接刪除大Key的風險

DEL命令在刪除單個集合類型的Key時,命令的時間復雜度是O(M),其中M是集合類型Key包含的元素個數。

DEL keyTime complexity: O(N) where N is the number of keys that will be removed. When a key to remove holds a value other than a string, the individual complexity for this key is O(M) where M is the number of elements in the list, set, sorted set or hash. Removing a single key that holds a string value is O(1).

生產環境中遇到過多次因業務刪除大Key,導致Redis阻塞,出現故障切換和應用程序雪崩的故障。測試刪除集合類型大Key耗時,一般每秒可清理100w~數百w個元素; 如果數千w個元素的大Key時,會導致Redis阻塞上10秒可能導致集群判斷Redis已經故障,出現故障切換;或應用程序出現雪崩的情況。

說明:Redis是單線程處理。單個耗時過大命令,導致阻塞其他命令,容易引起應用程序雪崩或Redis集群發生故障切換。所以避免在生產環境中使用耗時過大命令。

Redis刪除大的集合鍵的耗時, 測試估算,可參考;和硬件環境、Redis版本和負載等因素有關

Key類型 Item數量 耗時
Hash ~100萬 ~1000ms
List ~100萬 ~1000ms
Set ~100萬 ~1000ms
Sorted Set ~100萬 ~1000ms

當我們發現集群中有大key時,要刪除時,如何優雅地刪除大Key?

二、如何優雅地刪除各類大Key

從Redis2.8版本開始支持SCAN命令,通過m次時間復雜度為O(1)的方式,遍歷包含n個元素的大key.這樣避免單個O(n)的大命令,導致Redis阻塞。 這里刪除大key操作的思想也是如此。

2.1  Delete Large Hash Key

通過hscan命令,每次獲取500個字段,再用hdel命令,每次刪除1個字段。Python代碼:

def del_large_hash():
 
r = redis.StrictRedis(host='redis-host1', port=6379)
 
large_hash_key ="xxx"
 
cursor = '0'
 
while cursor != 0:
 
cursor, data = r.hscan(large_hash_key, cursor=cursor, count=500)
 
for item in data.items():
 
r.hdel(large_hash_key, item[0])

 

2.2  Delete Large Set Key

刪除大set鍵,使用sscan命令,每次掃描集合中500個元素,再用srem命令每次刪除一個鍵Python代碼:

def del_large_set():
 
r = redis.StrictRedis(host='redis-host1', port=6379)
 
large_set_key = 'xxx'
 
cursor = '0'
 
while cursor != 0:
 
cursor, data = r.sscan(large_set_key, cursor=cursor, count=500)
 
for item in data:
 
r.srem(large_size_key, item)

 

2.3  Delete Large List Key

刪除大的List鍵,未使用scan命令; 通過ltrim命令每次刪除少量元素。Python代碼:

 
def del_large_list():
 
r = redis.StrictRedis(host='redis-host1', port=6379)
 
large_list_key = 'xxx'
 
while r.llen(large_list_key)>0:
 
r.ltrim(large_list_key, 0, -101)

 

2.4  Delete Large Sorted set key

刪除大的有序集合鍵,和List類似,使用sortedset自帶的zremrangebyrank命令,每次刪除top 100個元素。Python代碼:

def del_large_sortedset():
 
r = redis.StrictRedis(host='large_sortedset_key', port=6379)
 
large_sortedset_key='xxx'
 
while r.zcard(large_sortedset_key)>0:
 
r.zremrangebyrank(large_sortedset_key,0,99)

三、Redis Lazy Free

應該從3.4版本開始,Redis會支持lazy delete free的方式,刪除大鍵的過程不會阻塞正常請求。

【最佳實踐】

核心思路是拆分,通過上面相關方法,分批獲取,分批刪除;

(1)關於任意類型key刪除

#!/bin/bash
source /etc/profile
next_position=0
del_key_file='6381_del_key.txt'
redis_port=6381

while read line
do
while [ 1 ]
do
key_info=`redis-cli -a bfengzlgdredis2017 -p $redis_port scan ${next_position} match $line count 10000`
next_position=`echo ${key_info}|awk '{print $1}'`
echo ${key_info}|awk '{$1=null;print }'|sed 's/ /\n/g'|sed '/^$/d'|sed 's#^#del #g' >> all_${redis_port}.txt


if [ ${next_position} -eq 0 ];then
   break
fi
done
done<$del_key_file
 
6381_del_key.txt 這個文件里存放的是需要被刪除的key 信息,或通配符信息

(2)單個key前綴的所有key查找

獲取 userplaylist: 開頭的所有key   

#!/bin/bash
source /etc/profile
next_position=0
#del_key_file='6379_del_key.txt'
redis_port=6379

while [ 1 ]
do
key_info=`redis-cli -a bfengzlgdredis2017 -p $redis_port scan ${next_position} match userplaylist:* count 10000`
next_position=`echo ${key_info}|awk '{print $1}'`
echo ${key_info}|awk '{$1=null;print }'|sed 's/ /\n/g'|sed '/^$/d'|sed 's#^#del #g' >> all_${redis_port}.txt


if [ ${next_position} -eq 0 ];then
   break
fi
done

 

(3)關於應用刪除key命令

#!/bin/bash
source /etc/profile
cd `dirname $0`

f_del_key(){
redis_port=$1
key_name=$2

all_number=`ls -l ${key_name}*|wc -l`
for i in `ls  |grep ${key_name}`
do 
 redis-cli -a bfengzlgdredis2017 -p ${redis_port} --pipe <$i
date "+%F-%T"
echo "${all_number}-${i}"
sleep 0.3
done
}

main(){

f_del_key 6383 6383_del_key_
}

main

 【清理 set 大key實踐 】

直接使用 spop,再結合一個 shell 爽飛

  (4)spop(隨機刪除):spop setkey del_count

 

【使用 unlink 代替 del】

Redis UNLINK 命令跟 DEL 命令十分相似:用於刪除指定的 key 。

就像 DEL 一樣,如果 key 不存在,則將其忽略。

但是,該命令會執行命令之外的線程中執行實際的內存回收,因此它不是阻塞,而 DEL 是阻塞的。這就是命令名稱的來源:UNLINK 命令只是將鍵與鍵空間斷開連接。實際的刪除將稍后異步進行。

參考:redis-cli -a 12345678qwert --scan --pattern "refresh:*" |  xargs -L 10   redis-cli -a 12345678qwert -n 0 unlink

【參考文檔】

轉自:https://blog.csdn.net/weixin_33970449/article/details/92369718


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM