如何使用Redis自动删除与模式匹配的键
在我的Redis DB中,我有许多如何使用Redis自动删除与模式匹配的键,redis,Redis,在我的Redis DB中,我有许多前缀:散列 有时候我想把它们都原子化。如何在不使用分布式锁定机制的情况下执行此操作?在bash中执行: redis-cli KEYS "prefix:*" | xargs redis-cli DEL 更新 好的,我明白了。这样做怎么样:存储当前的额外增量前缀,并将其添加到所有密钥中。例如: 你有这样的价值观: prefix_prefix_actuall = 2 prefix:2:1 = 4 prefix:2:2 = 10 当需要清除数据时,首先更改前缀\u
前缀:
散列
有时候我想把它们都原子化。如何在不使用分布式锁定机制的情况下执行此操作?在bash中执行:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
更新
好的,我明白了。这样做怎么样:存储当前的额外增量前缀,并将其添加到所有密钥中。例如:
你有这样的价值观:
prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10
当需要清除数据时,首先更改前缀\u actuall(例如,设置prefix\u prefix\u actuall=3),以便应用程序将新数据写入关键字prefix:3:1和prefix:3:2。然后,您可以安全地从prefix:2:1和prefix:2:2中获取旧值并清除旧键。我认为可能对您有所帮助的是。虽然没有,但您应该能够将删除与其他更新隔离开来。我也遇到了同样的问题。我以以下格式存储了用户的会话数据:
session:sessionid:key-x - value of x
session:sessionid:key-y - value of y
session:sessionid:key-z - value of z
因此,每个条目都是一个单独的键值对。当会话被破坏时,我想通过删除模式为session:sessionid:
-的键来删除所有会话数据,但redis没有这样的功能
我所做的:将会话数据存储在一个数据库中。我只是创建了一个散列id为
session:sessionid
的散列,然后在该散列中按key-x
,key-y
,key-z
(顺序对我来说无关紧要),如果我不再需要该散列,我只需执行DEL session:sessionid
,所有与该散列id相关的数据都会消失DEL
是原子的,访问数据/将数据写入哈希是O(1)。从redis 2.6.0开始,您可以运行lua脚本,它以原子方式执行。我从来没有写过,但我想它看起来会像这样
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]
警告:如前所述,由于性能问题,键
此命令不应用于生产中的常规操作
命令用于调试和特殊操作
请参阅。这是一个在Lua中实现的通配符删除的完整工作和原子版本。它将比xargs版本运行得快得多,因为来回的网络要少得多,而且它是完全原子的,在完成之前阻止对redis的任何其他请求。如果您想自动删除Redis 2.6.0或更高版本上的密钥,这绝对是一种方法:
redis-cli -n [some_db] -h [some_host_name] EVAL "return redis.call('DEL', unpack(redis.call('KEYS', ARGV[1] .. '*')))" 0 prefix:
这是@mcdizzle在回答这个问题时的想法的一个有效版本。这个主意100%归功于他
编辑:根据Kikito在下面的评论,如果您的Redis服务器中要删除的密钥多于可用内存,那么您将遇到问题。在这种情况下,请执行以下操作:
for _,k in ipairs(redis.call('keys', ARGV[1])) do
redis.call('del', k)
end
正如Kikito所建议的那样。穷人的原子质量删除了吗 也许你可以把它们都设置为在同一秒内过期——就像未来的几分钟——然后等到那一刻,看到它们同时“自毁”
但我真的不确定这会有多原子。对于那些在解析其他答案时遇到困难的人:
eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0
用您自己的模式替换key:::::pattern
,并将其输入到redis cli
中,您就可以开始了
lisco的信贷来源:免责声明:以下解决方案不提供原子性
从v2.8开始,您确实希望使用命令而不是键[1]。以下Bash脚本演示了按模式删除键:
#!/bin/bash
if [ $# -ne 3 ]
then
echo "Delete keys from Redis matching a pattern using SCAN & DEL"
echo "Usage: $0 <host> <port> <pattern>"
exit 1
fi
cursor=-1
keys=""
while [ $cursor -ne 0 ]; do
if [ $cursor -eq -1 ]
then
cursor=0
fi
reply=`redis-cli -h $1 -p $2 SCAN $cursor MATCH $3`
cursor=`expr "$reply" : '\([0-9]*[0-9 ]\)'`
keys=${reply##[0-9]*[0-9 ]}
redis-cli -h $1 -p $2 DEL $keys
done
redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink
@mcdizle的解决方案不起作用,它只适用于一个条目 此选项适用于具有相同前缀的所有键
EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*
注意:您应该将“prefix”替换为密钥前缀…如果密钥名称中有空格,您可以在bash中使用:
redis-cli keys "pattern: *" | xargs -L1 -I '$' echo '"$"' | xargs redis-cli del
@itamar的回答很好,但是对回复的解析对我来说不起作用,特别是在给定扫描中没有找到键的情况下。一个可能更简单的解决方案,直接从控制台:
redis-cli -h HOST -p PORT --scan --pattern "prefix:*" | xargs -n 100 redis-cli DEL
这也使用了扫描,这比生产中的密钥更可取,但不是原子的。Spring RedisTemplate本身提供了这一功能。最新版本的RedissonClient不推荐使用“deleteByPattern”功能
Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
Set keys=redisTemplate.keys(“geotag |*”);
redisTemplate.delete(键);
这不是问题的直接答案,但因为我是在这里搜索自己的答案的,所以我将在这里分享
如果你有几十或数以百万计的密钥你必须匹配,这里给出的答案会导致ReDIS对大量的时间(分钟)没有响应,并且可能由于内存消耗而崩溃(当然,后台保存将在你的操作中开始)。 不可否认,下面的方法很难看,但我没有找到更好的方法。原子性在这里是毫无疑问的,在这种情况下,主要目标是保持Redis在100%的时间内保持快速响应。如果您的所有密钥都在其中一个数据库中,并且不需要匹配任何模式,但由于其阻塞性而无法使用,那么它将非常有效
想法很简单:编写一个在循环中运行的脚本,并使用O(1)操作(如or)来获取密钥,检查它们是否匹配模式(如果需要的话),然后逐个执行 如果有更好的方法,请让我知道,我会更新答案 Ruby中randomkey的示例实现,作为rake任务,是redis cli-n 3 flushdb之类的非阻塞替代品:desc 'Cleanup redis'
task cleanup_redis: :environment do
redis = Redis.new(...) # connection to target database number which needs to be wiped out
counter = 0
while key = redis.randomkey
puts "Deleting #{counter}: #{key}"
redis.del(key)
counter += 1
end
end
我支持所有与使用某种工具或执行Lua表达式相关的答案 我这边还有一个选择: 在我们的生产和预生产数据库中有数千个密钥。有时我们需要删除一些键(通过一些掩码)、根据一些标准进行修改等。当然,无法从CLI手动执行此操作,尤其是使用分片(每个物理分区中有512个逻辑数据库) 为此,我编写了java客户机工具来完成所有这些工作。在删除密钥的情况下,实用程序ca
public class DataCleaner {
public static void main(String args[]) {
String keyPattern = args[0];
String host = args[1];
int port = Integer.valueOf(args[2]);
int dbIndex = Integer.valueOf(args[3]);
Jedis jedis = new Jedis(host, port);
int deletedKeysNumber = 0;
if(dbIndex >= 0){
deletedKeysNumber += deleteDataFromDB(jedis, keyPattern, dbIndex);
} else {
int dbSize = Integer.valueOf(jedis.configGet("databases").get(1));
for(int i = 0; i < dbSize; i++){
deletedKeysNumber += deleteDataFromDB(jedis, keyPattern, i);
}
}
if(deletedKeysNumber == 0) {
System.out.println("There is no keys with key pattern: " + keyPattern + " was found in database with host: " + host);
}
}
private static int deleteDataFromDB(Jedis jedis, String keyPattern, int dbIndex) {
jedis.select(dbIndex);
Set<String> keys = jedis.keys(keyPattern);
for(String key : keys){
jedis.del(key);
System.out.println("The key: " + key + " has been deleted from database index: " + dbIndex);
}
return keys.size();
}
}
redis-cli --scan --pattern 'key*' | xargs redis-cli del
redis-cli --scan --pattern 'xyz_category_fpc*' | xargs redis-cli del
redis-cli flushall
redis-cli flushdb
#!/bin/bash
rcli="/YOUR_PATH/redis-cli"
default_server="YOUR_SERVER"
default_port="YOUR_PORT"
servers=`$rcli -h $default_server -p $default_port cluster nodes | grep master | awk '{print $2}' | sed 's/:.*//'`
if [ x"$1" == "x" ]; then
startswith="DEFAULT_PATTERN"
else
startswith="$1"
fi
MAX_BUFFER_SIZE=1000
for server in $servers; do
cursor=0
while
r=`$rcli -h $server -p $default_port scan $cursor match "$startswith*" count $MAX_BUFFER_SIZE `
cursor=`echo $r | cut -f 1 -d' '`
nf=`echo $r | awk '{print NF}'`
if [ $nf -gt 1 ]; then
for x in `echo $r | cut -f 1 -d' ' --complement`; do
echo $x
done
fi
(( cursor != 0 ))
do
:
done
done
#!/bin/bash
STARTSWITH="$1"
RCLI=YOUR_PATH/redis-cli
HOST=YOUR_HOST
PORT=6379
RCMD="$RCLI -h $HOST -p $PORT -c "
./scan-match.sh $STARTSWITH | while read -r KEY ; do
$RCMD del $KEY
done
$ ./clear-redis-key.sh key_head_pattern
redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL
flushRedisMultipleHashKeyUsingPattern("*YOUR_KEY_PATTERN*"); //function call
function flushRedisMultipleHashKeyUsingPattern($pattern='')
{
if($pattern==''){
return true;
}
$redisObj = $this->redis;
$getHashes = $redisObj->keys($pattern);
if(!empty($getHashes)){
$response = call_user_func_array(array(&$redisObj, 'del'), $getHashes); //setting all keys as parameter of "del" function. Using this we can achieve $redisObj->del("key1","key2);
}
}
export REDIS_HOST=your.hostname.com
redis-cli -h "$REDIS_HOST" --scan --pattern "YourPattern*" > /tmp/keys
time cat /tmp/keys | perl -pe 's/"/\\"/g;s/^/DEL "/;s/$/"/;' | redis-cli -h "$REDIS_HOST" --pipe
redis-cli --raw keys "$PATTERN" | xargs redis-cli del
redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink
redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL
redis-cli --scan --pattern "myprefix:*" | tr \\n \\0 | xargs -0 redis-cli unlink
redis-cli keys "stats.*" | cut -d ' ' -f2 | xargs -d '\n' redis-cli DEL
EVAL "return redis.call('del', unpack(redis.call('keys', my_pattern_here*)))" 0