Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Redis自动删除与模式匹配的键_Redis - Fatal编程技术网

如何使用Redis自动删除与模式匹配的键

如何使用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

在我的Redis DB中,我有许多
前缀:
散列

有时候我想把它们都原子化。如何在不使用分布式锁定机制的情况下执行此操作?

在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