在我的Redis DB中,我有一些前缀:<numeric_id>哈希值。

有时我想把它们都原子地清除掉。如何在不使用分布式锁定机制的情况下做到这一点呢?


当前回答

这并不是对这个问题的直接回答,但因为我是在寻找自己的答案时来到这里的,所以我将在这里分享。

如果你有数千万或数亿个键需要匹配,这里给出的答案将导致Redis在很长一段时间内(几分钟?)没有响应,并可能因为内存消耗而崩溃(当然,后台保存将在你的操作过程中启动)。

下面的方法不可否认是丑陋的,但我没有找到更好的方法。原子性在这里是没有问题的,在这种情况下,主要目标是保持Redis的正常运行和100%的响应。如果您将所有的密钥都放在一个数据库中,并且不需要匹配任何模式,那么它将完美地工作,但不能使用http://redis.io/commands/FLUSHDB,因为它具有阻塞特性。

想法很简单:写一个脚本,在循环中运行,使用O(1)操作,如http://redis.io/commands/SCAN或http://redis.io/commands/RANDOMKEY来获取密钥,检查它们是否匹配模式(如果你需要的话),然后逐个http://redis.io/commands/DEL它们。

如果有更好的方法,请告诉我,我会更新答案。

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

其他回答

FYI.

只使用bash和redis-cli 不使用键(这使用扫描) 在集群模式下工作良好 不是原子

也许您只需要修改大写字符。

scan-match.sh

#!/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

clear-redis-key.sh

#!/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

在bash提示符下运行

$ ./clear-redis-key.sh key_head_pattern

我也遇到了同样的问题。我为用户存储会话数据的格式为:

session:sessionid:key-x - value of x
session:sessionid:key-y - value of y
session:sessionid:key-z - value of z

因此,每个条目都是一个单独的键值对。当会话被销毁时,我想通过使用模式session:sessionid:* -删除键来删除所有会话数据,但redis没有这样的功能。

我所做的是:将会话数据存储在散列中。我只是用session:sessionid的哈希id创建了一个哈希,然后我在那个哈希中推key-x, key-y, key-z(顺序对我来说并不重要),如果我不再需要那个哈希,我只是做一个DEL session:sessionid,所有与那个哈希id相关的数据都消失了。DEL是原子的,访问数据/向哈希写入数据是O(1)。

您还可以使用该命令删除密钥

假设你的redis中有很多类型的键,比如-

“xyz_category_fpc_12” “xyz_category_fpc_245” “xyz_category_fpc_321” “xyz_product_fpc_876” “xyz_product_fpc_302” “xyz_product_fpc_01232”

Ex- 'xyz_category_fpc'这里xyz是一个站点名称,这些键与电子商务网站的产品和类别相关,由FPC生成。

如果您像下面那样使用此命令-

redis-cli --scan --pattern 'key*' | xargs redis-cli del

OR

redis-cli --scan --pattern 'xyz_category_fpc*' | xargs redis-cli del

它删除所有的键,如“xyz_category_fpc”(删除1、2和3个键)。若要删除其他4,5和6数字键,请使用上述命令中的'xyz_product_fpc'。

如果你想删除所有在Redis,然后按照这些命令-

redis-cli:

FLUSHDB -从连接的当前数据库中删除数据。 FLUSHALL—从所有数据库中删除数据。

例如:-在你的壳:

redis-cli flushall
redis-cli flushdb

免责声明:以下解决方案不提供原子性。

从v2.8开始,您确实希望使用SCAN命令而不是KEYS[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

[1] KEYS是一个可能导致DoS的危险命令。以下摘自其文档页面:

警告:将KEYS视为只应在生产环境中极其小心地使用的命令。当它针对大型数据库执行时,可能会破坏性能。此命令用于调试和特殊操作,例如更改密钥空间布局。不要在常规应用程序代码中使用key。如果您正在寻找一种在键空间子集中查找键的方法,请考虑使用集合。

更新:一个班轮相同的基本效果-

$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL

对于那些无法解析其他答案的人:

eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0

将key:*:pattern替换为您自己的模式,并将其输入到redis-cli中,就可以开始了。

Credit lisco来自:http://redis.io/commands/del