677

在我的 Redis DB 中,我有许多prefix:<numeric_id>哈希值。

有时我想以原子方式清除它们。如何在不使用某些分布式锁定机制的情况下做到这一点?

4

31 回答 31

796

在 bash 中执行:

redis-cli KEYS "prefix:*" | xargs redis-cli DEL

更新

好,我明白了。这种方式怎么样:存储当前的附加增量前缀并将其添加到所有密钥中。例如:

你有这样的价值观:

prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10

当您需要清除数据时,首先更改 prefix_actuall(例如设置 prefix_prefix_actuall = 3),因此您的应用程序会将新数据写入键 prefix:3:1 和 prefix:3:2。然后,您可以安全地从 prefix:2:1 和 prefix:2:2 中获取旧值并清除旧键。

于 2010-10-23T23:31:15.880 回答
471

从 redis 2.6.0 开始,您可以运行自动执行的 lua 脚本。我从来没有写过,但我认为它看起来像这样

EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]

警告:正如Redis 文档所说,由于性能问题,keys 该命令不应用于生产中的常规操作,该命令用于调试和特殊操作。阅读更多

请参阅EVAL 文档

于 2013-06-06T23:47:53.097 回答
84

这是在 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

正如奇奇托建议的那样。

于 2013-06-10T04:20:43.760 回答
73

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

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

更新:一个具有相同基本效果的衬里 -

$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
于 2014-04-30T22:26:54.790 回答
55

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

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

用您自己的模式替换key:*:pattern并输入它redis-cli,您就可以开始了。

信用 lisco 来自:http ://redis.io/commands/del

于 2014-03-19T15:32:24.963 回答
42

我在 redis 3.2.8 中使用以下命令

redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL

您可以从此处获得与键模式搜索相关的更多帮助:- https://redis.io/commands/keys。根据您的要求使用您方便的 glob 样式模式,例如*YOUR_KEY_PREFIX*orYOUR_KEY_PREFIX??或任何其他。

如果你们中的任何人已经集成了Redis PHP 库,那么下面的函数将会对你有所帮助。

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);
            }
        }

谢谢 :)

于 2017-05-08T07:33:48.607 回答
31

您还可以使用此命令删除密钥:-

假设您的 redis 中有多种类型的键,例如-

  1. 'xyz_category_fpc_12'
  2. 'xyz_category_fpc_245'
  3. 'xyz_category_fpc_321'
  4. 'xyz_product_fpc_876'
  5. 'xyz_product_fpc_302'
  6. 'xyz_product_fpc_01232'

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

如果您按以下方式使用此命令-

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

或者

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:

  1. FLUSHDB - 从连接的 CURRENT 数据库中删除数据。
  2. FLUSHALL - 从所有数据库中删除数据。

例如:- 在您的外壳中:

redis-cli flushall
redis-cli flushdb
于 2017-01-12T18:31:11.997 回答
26

@mcdizle 的解决方案不起作用,它仅适用于一个条目。

这个适用于所有具有相同前缀的键

EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*

注意:您应该将“前缀”替换为您的密钥前缀...

于 2014-12-19T07:20:32.253 回答
15

如果键名中有空格,则可以在 bash 中使用:

redis-cli keys "pattern: *" | xargs -L1 -I '$' echo '"$"' | xargs redis-cli del
于 2015-03-04T23:48:41.813 回答
13

@itamar 的回答很棒,但是回复的解析对我不起作用,尤其是。在给定扫描中没有找到密钥的情况下。一个可能更简单的解决方案,直接从控制台:

redis-cli -h HOST -p PORT  --scan --pattern "prefix:*" | xargs -n 100 redis-cli DEL

这也使用了 SCAN,它在生产中比 KEYS 更可取,但不是原子的。

于 2015-06-23T02:18:55.200 回答
13

如果您的密钥包含特殊字符,其他答案可能不起作用 -Guide$CLASSMETADATA][1]例如。将每个键包装成引号将确保它们被正确删除:

redis-cli --scan --pattern sf_* | awk '{print $1}' | sed "s/^/'/;s/$/'/" | xargs redis-cli del
于 2019-11-15T14:45:58.660 回答
10

我只是有同样的问题。我以以下格式存储用户的会话数据:

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

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

我所做的:将会话数据存储在hash中。我只是创建一个哈希 id 的哈希session:sessionid,然后在该哈希中推送key-x, key-y, key-z(顺序对我来说无关紧要),如果我不再需要该哈希,我只需执行 aDEL session:sessionid并且与该哈希 id 关联的所有数据都消失了。DEL是原子的,访问数据/将数据写入哈希是 O(​​1)。

于 2010-12-18T19:06:29.430 回答
8

// TODO

您认为它的命令没有意义,但有时 Redis 命令就像DEL无法正常工作一样,可以解决这个问题

redis-cli KEYS "*" | xargs -i redis-cli EXPIRE {} 1这是生活黑客

于 2020-11-18T09:22:12.420 回答
6

使用 SCAN 而不是 KEYS(推荐用于生产服务器)--pipe而不是 xargs 的版本。

我更喜欢管道而不是 xargs,因为当您的键包含引号或您的外壳尝试解释的其他特殊字符时,它更有效并且可以工作。此示例中的正则表达式替换将键包裹在双引号中,并转义其中的任何双引号。

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
于 2017-06-26T01:23:59.280 回答
5

我认为可能对您有所帮助的是MULTI/EXEC/DISCARD。虽然不是100% 等同于 transactions,但您应该能够将删除与其他更新隔离开来。

于 2010-10-24T08:51:05.663 回答
5

供参考。

  • 仅使用 bash 和redis-cli
  • 不使用keys(这使用scan
  • 集群模式下运行良好
  • 不是原子的

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

扫描匹配.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

清除-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
于 2017-05-08T07:08:03.703 回答
4

请使用此命令并尝试:

redis-cli --raw keys "$PATTERN" | xargs redis-cli del
于 2018-11-29T14:02:13.550 回答
3

这不是问题的直接答案,但由于我是在寻找自己的答案时来到这里的,所以我会在这里分享。

如果您必须匹配数千万或数亿个键,则此处给出的答案将导致 Redis 在很长一段时间(几分钟?)内无响应,并可能由于内存消耗而崩溃(当然,后台保存将在您的操作过程中开始)。

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

想法很简单:编写一个循环运行的脚本,并使用 O(1) 操作,如http://redis.io/commands/SCANhttp://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
于 2016-02-22T14:01:45.447 回答
3

我尝试了上面提到的大多数方法,但它们对我不起作用,经过一些搜索后我发现了以下几点:

  • 如果你在 redis 上有多个数据库,你应该使用-n [number]
  • 如果您使用了几个键del,但如果有数千或数百万个键,则最好使用unlink,因为unlink 是非阻塞的,而 del 是阻塞的,有关更多信息,请访问此页面unlink vs del
  • keys像 del 并且正在阻塞

所以我用这段代码按模式删除键:

 redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink 
于 2019-07-11T04:13:33.163 回答
2

添加到这个答案:

要查找前 1000 个键:

EVAL "return redis.call('scan', 0, 'COUNT', 1000, 'MATCH', ARGV[1])" 0 find_me_*

要删除它们:

EVAL "return redis.call('del', unpack(redis.call('SCAN', 0, 'COUNT', 1000, 'MATCH', ARGV[1])[2]))" 0 delete_me_*
于 2021-10-25T16:45:58.663 回答
2

我用最简单的 EVAL 命令变体成功了:

EVAL "return redis.call('del', unpack(redis.call('keys', my_pattern_here*)))" 0

my_pattern_here用我的价值代替。

于 2021-05-19T07:39:37.980 回答
2

下面的命令对我有用。

redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL
于 2019-09-12T08:28:05.770 回答
1

这个对我有用,但可能不是原子的:

redis-cli keys "stats.*" | cut -d ' ' -f2 | xargs -d '\n' redis-cli DEL
于 2021-05-10T16:40:14.130 回答
0

穷人的原子质量删除?

也许您可以将它们全部设置为 EXPIREAT 同一秒 - 比如未来几分钟 - 然后等到那个时候,同时看到它们全部“自毁”。

但我不确定那将是多么原子。

于 2014-03-13T16:28:31.453 回答
0

现在,您可以使用 redis 客户端并首先执行 SCAN(支持模式匹配),然后单独 DEL 每个键。

但是,redis 官方 github 上有一个问题,在这里创建一个模式匹配-德尔,如果你觉得它有用,就给它一些爱吧!

于 2019-09-12T14:14:25.470 回答
0

如果您的键名中有空格,这将适用于 MacOS

redis-cli --scan --pattern "myprefix:*" | tr \\n \\0 | xargs -0 redis-cli unlink
于 2021-03-09T15:45:16.167 回答
0

我支持所有与拥有一些工具或执行 Lua 表达式相关的答案。

我这边的另一种选择:

在我们的生产和预生产数据库中,有数千个密钥。有时我们需要删除一些键(通过一些掩码),根据一些标准进行修改等。当然,没有办法从 CLI 手动完成,尤其是有分片(每个物理中有 512 个逻辑数据库)。

为此,我编写了完成所有这些工作的 java 客户端工具。在删除键的情况下,该实用程序可以非常简单,那里只有一个类:

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();
    }

}
于 2016-09-01T18:52:01.733 回答
0

如果您使用的是低于 4 的 Redis 版本,您可以尝试

redis-cli -h 127.0.0.1 -p 26379 -a `yourPassword` --scan --pattern data:* | xargs redis-cli del

如果您使用的是上述 4 个版本,那么

redis-cli -h 127.0.0.1 -p 26379 -a `yourPassword` --scan --pattern data:*| xargs redis-cli unlink

要检查您的版本,请使用以下命令输入您的 Redis 终端

redis-cli -h 127.0.0.1 -p 26379 -a `yourPassword

然后输入

> INFO

# Server
redis_version:5.0.5
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:da75abdfe06a50f8
redis_mode:standalone
os:Linux 5.3.0-51-generic x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:7.5.0
process_id:14126
run_id:adfaeec5683d7381a2a175a2111f6159b6342830
tcp_port:6379
uptime_in_seconds:16860
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:15766886
executable:/tmp/redis-5.0.5/src/redis-server
config_file:

# Clients
connected_clients:22
....More Verbose
于 2021-12-08T05:06:49.353 回答
-1

如果您使用 windows 环境,请按照以下步骤操作,它肯定会起作用:

  1. 从这里下载 GOW - https://github.com/bmatzelle/gow/wiki(因为 xargs 命令在 Windows 中不起作用)

  2. 下载适用于 Windows 的 redis-cli(详细说明在这里 - https://medium.com/@binary10111010/redis-cli-installation-on-windows-684fb6b6ac6b

  3. 运行cmd打开redis-cli存储的目录(例如:D:\Redis\Redis-x64-3.2.100)

  4. 如果您想删除以“Global:ProviderInfo”开头的所有键,请执行此查询(需要更改粗体参数(主机、端口、密码、键)并编写您的,因为这只是示例):

    redis-cli -h redis.test.com -p 6379 -a redispassword --raw keys " Global:ProviderInfo *" | xargs redis-cli -h redis.test.com -p 6379 -a redispassword del

于 2020-10-27T11:39:09.113 回答
-1

这是不使用任何 xargs 魔法的最简单方法

纯粹的狂欢!

redis-cli DEL $(redis-cli KEYS *pattern*)
于 2022-02-07T15:17:27.513 回答
-3

Spring RedisTemplate 本身提供了该功能。最新版本中的 RedissonClient 已弃用“deleteByPattern”功能。

Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
于 2015-11-30T10:29:28.577 回答