在我的Redis数据库中,我有许多prefix:<numeric_id>
个哈希值。
有时我想以原子方式清除它们。如何在不使用分布式锁定机制的情况下执行此操作?
答案 0 :(得分:662)
在bash中执行:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
<强>更新强>
好的,我明白了。这种方式:存储当前额外的增量前缀并将其添加到您的所有键。例如:
你有这样的价值观:
prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10
当您需要清除数据时,首先更改prefix_actuall(例如set prefix_prefix_actuall = 3),这样您的应用程序就会将新数据写入密钥前缀:3:1和前缀:3:2。然后,您可以安全地从前缀:2:1和前缀:2:2中取旧值并清除旧密钥。
答案 1 :(得分:395)
从redis 2.6.0开始,您可以运行原子执行的lua脚本。我从来没有写过,但我认为它看起来像这样
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]
答案 2 :(得分:68)
这是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服务器中有更多的密钥要删除而不是空闲内存,那么你将遇到"too many elements to unpack" error。在这种情况下,请执行:
for _,k in ipairs(redis.call('keys', ARGV[1])) do
redis.call('del', k)
end
正如Kikito建议的那样。
答案 3 :(得分:60)
免责声明:以下解决方案不会提供原子性。
从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。如果您正在寻找在密钥空间子集中查找密钥的方法,请考虑使用集合。
UPDATE:一个衬垫,具有相同的基本效果 -
$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
答案 4 :(得分:34)
对于那些在解析其他答案时遇到问题的人:
eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0
将key:*:pattern
替换为您自己的模式并将其输入redis-cli
,您就可以了。
答案 5 :(得分:17)
您也可以使用此命令删除密钥: -
假设您的redis中有许多类型的键,如 -
前 - ' xyz_category_fpc '此处 xyz 是网站名称,这些密钥与电子商务网站的产品和类别相关并由FPC生成。
如果您使用以下命令 -
_config
OR
/_node/couchdb@localhost/_config
删除所有键,例如“ xyz_category_fpc ”(删除1,2和3键)。要删除其他4,5和6个数字键,请在上面的命令中使用“ xyz_product_fpc ”。
如果您想在 Redis 中删除所有内容,请按照以下命令进行操作 -
使用redis-cli:
例如: - 在你的shell中:
couchdb@localhost
答案 6 :(得分:16)
@ mcdizle的解决方案不起作用它只适用于一个条目。
这个适用于具有相同前缀的所有键
EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*
注意:您应该将'prefix'替换为您的密钥前缀...
答案 7 :(得分:12)
如果密钥名称中有空格,则可以在bash中使用:
redis-cli keys "pattern: *" | xargs -L1 -I '$' echo '"$"' | xargs redis-cli del
答案 8 :(得分:10)
@ itamar的答案很棒,但解析回复对我不起作用,尤其是。在给定扫描中没有找到键的情况下。一个可能更简单的解决方案,直接来自控制台:
public class AgentSkills
{
public List<string> agentSkillsNameList=new List<string>();
public List<string> agentSkillsLvlList=new List<string>();
}
这也使用SCAN,它在生产中优于KEYS,但不是原子的。
答案 9 :(得分:8)
我遇到了同样的问题。我以下列格式存储了用户的会话数据:
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
(顺序对我来说无关紧要)如果我不再需要那个哈希我只做DEL session:sessionid
并且与该哈希id相关的所有数据都消失了。 DEL
是原子的,访问数据/写入哈希的数据是O(1)。
答案 10 :(得分:5)
我认为可能对你有帮助的是MULTI/EXEC/DISCARD。虽然不是100% equivalent of transactions,但您应该能够将删除与其他更新隔离开来。
答案 11 :(得分:4)
请使用此命令并尝试:
redis-cli --raw keys "$PATTERN" | xargs redis-cli del
答案 12 :(得分:3)
通过&#34;删除分支&#34;简单实现FastoRedis中的功能,只需选择要删除的分支。
答案 13 :(得分:2)
这不是问题的直接答案,但是因为我在搜索自己的答案时来到这里,我会在这里分享。
如果你必须匹配数十或数亿个密钥,这里给出的答案将导致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
答案 14 :(得分:2)
使用SCAN而不是KEYS(对于生产服务器推荐)和--pipe
而不是xargs的版本。
我更喜欢管道覆盖xargs,因为它更高效,当你的密钥包含引号或其他特殊字符时,你的shell会尝试和解释。此示例中的正则表达式替换将键包装在双引号中,并转义内部的任何双引号。
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
答案 15 :(得分:1)
这个对我有用:
calcManifest()
答案 16 :(得分:1)
如果您的密钥名称中有空格,这将适用于 MacOS
/tmp/prefix2
答案 17 :(得分:1)
// TODO
您有时认为DEL
之类的Redis命令无法正常工作,因此该命令没有任何意义,
redis-cli KEYS "*" | xargs -i redis-cli EXPIRE {} 1
这是生活骇客
答案 18 :(得分:0)
我用最简单的 EVAL 命令变体成功了:
EVAL "return redis.call('del', unpack(redis.call('keys', my_pattern_here*)))" 0
我用我的值替换了 my_pattern_here
。
答案 19 :(得分:0)
如果您使用Windows环境,请按照以下步骤操作,它绝对可以使用:
从此处下载GOW-https://github.com/bmatzelle/gow/wiki(因为xargs命令在Windows中不起作用)
下载适用于Windows的redis-cli(详细说明在这里-https://medium.com/@binary10111010/redis-cli-installation-on-windows-684fb6b6ac6b)
运行cmd并打开存储redis-cli的目录(例如:D:\ Redis \ Redis-x64-3.2.100)
如果要删除所有以“ Global:ProviderInfo”开头的密钥,请执行此查询(需要更改粗体参数(主机,端口,密码,密钥)并编写您的参数,因为这仅是示例):
redis-cli -h redis.test.com -p 6379 -a redispassword -原始键“ 全局: ProviderInfo *” | xargs redis-cli -h redis.test.com -p 6379 -a redispassword del
答案 20 :(得分:0)
现在,您可以使用redis客户端并先执行SCAN(支持模式匹配),然后分别删除每个密钥。
但是,官方redis github上存在一个创建模式匹配项here的问题,如果发现有用的话就去爱上它吧!
答案 21 :(得分:0)
我尝试了上面提到的大多数方法,但是它们对我不起作用,经过一番搜索,我发现了这些要点:
-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
答案 22 :(得分:0)
我支持所有与使用某个工具或执行Lua表达式相关的答案。
我身边的另一个选择:
在我们的生产和预生产数据库中,有数千个密钥。我们需要不时删除一些键(通过某些掩码),按某些标准修改等等。当然,没有办法从CLI手动执行,特别是有分片(每个物理中有512个逻辑dbs)。
为此,我编写了完成所有这些工作的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();
}
}
答案 23 :(得分:-1)
如果您的密钥包含特殊字符-例如Guide$CLASSMETADATA][1]
,其他答案可能不起作用。将每个键括在引号中将确保将其正确删除:
redis-cli --scan --pattern sf_* | awk '{print $1}' | sed "s/^/'/;s/$/'/" | xargs redis-cli del
答案 24 :(得分:-1)
下面的命令对我有用。
redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL
答案 25 :(得分:-1)
穷人的原子质量删除?
也许你可以将它们全部设置为EXPIREAT相同的秒 - 比如将来的几分钟 - 然后等到那个时候再看到它们全部“自毁”。
但我不确定那将是多么原子。
答案 26 :(得分:-2)
Spring RedisTemplate本身提供了这些功能。最新版本中的RedissonClient已弃用&#34; deleteByPattern&#34;功能。
Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);